package net.sf.jasperreports.engine;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class JasperPrint implements Serializable, JRPropertiesHolder {
  public static final String PROPERTIES_PRINT_TRANSFER_PREFIX = "net.sf.jasperreports.print.transfer.";
  
  private static final long serialVersionUID = 10200L;
  
  private static class DefaultStyleProvider implements JRDefaultStyleProvider, Serializable {
    private static final long serialVersionUID = 10200L;
    
    private JRReportFont defaultFont;
    
    private JRStyle defaultStyle;
    
    DefaultStyleProvider(JRReportFont font, JRStyle style) {
      this.defaultFont = font;
      this.defaultStyle = style;
    }
    
    public JRReportFont getDefaultFont() {
      return this.defaultFont;
    }
    
    void setDefaultFont(JRReportFont font) {
      this.defaultFont = font;
    }
    
    public JRStyle getDefaultStyle() {
      return this.defaultStyle;
    }
    
    void setDefaultStyle(JRStyle style) {
      this.defaultStyle = style;
    }
  }
  
  private String name = null;
  
  private int pageWidth = 0;
  
  private int pageHeight = 0;
  
  private byte orientation = 1;
  
  private Map fontsMap = new HashMap();
  
  private List fontsList = new ArrayList();
  
  private Map stylesMap = new HashMap();
  
  private List stylesList = new ArrayList();
  
  private Map originsMap = new HashMap();
  
  private List originsList = new ArrayList();
  
  private List pages = new ArrayList();
  
  private transient Map anchorIndexes = null;
  
  private DefaultStyleProvider defaultStyleProvider = null;
  
  private String formatFactoryClass;
  
  private String localeCode;
  
  private String timeZoneId;
  
  private JRPropertiesMap propertiesMap;
  
  public JasperPrint() {
    this.defaultStyleProvider = new DefaultStyleProvider(null, null);
    this.propertiesMap = new JRPropertiesMap();
  }
  
  public String getName() {
    return this.name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
  
  public int getPageWidth() {
    return this.pageWidth;
  }
  
  public void setPageWidth(int pageWidth) {
    this.pageWidth = pageWidth;
  }
  
  public int getPageHeight() {
    return this.pageHeight;
  }
  
  public void setPageHeight(int pageHeight) {
    this.pageHeight = pageHeight;
  }
  
  public byte getOrientation() {
    return this.orientation;
  }
  
  public void setOrientation(byte orientation) {
    this.orientation = orientation;
  }
  
  public boolean hasProperties() {
    return (this.propertiesMap != null && this.propertiesMap.hasProperties());
  }
  
  public JRPropertiesMap getPropertiesMap() {
    return this.propertiesMap;
  }
  
  public JRPropertiesHolder getParentProperties() {
    return null;
  }
  
  public String[] getPropertyNames() {
    return this.propertiesMap.getPropertyNames();
  }
  
  public String getProperty(String propName) {
    return this.propertiesMap.getProperty(propName);
  }
  
  public void setProperty(String propName, String value) {
    this.propertiesMap.setProperty(propName, value);
  }
  
  public void removeProperty(String propName) {
    this.propertiesMap.removeProperty(propName);
  }
  
  public JRReportFont getDefaultFont() {
    return this.defaultStyleProvider.getDefaultFont();
  }
  
  public void setDefaultFont(JRReportFont font) {
    this.defaultStyleProvider.setDefaultFont(font);
  }
  
  public JRDefaultFontProvider getDefaultFontProvider() {
    return this.defaultStyleProvider;
  }
  
  public JRReportFont[] getFonts() {
    JRReportFont[] fontsArray = new JRReportFont[this.fontsList.size()];
    this.fontsList.toArray((Object[])fontsArray);
    return fontsArray;
  }
  
  public List getFontsList() {
    return this.fontsList;
  }
  
  public Map getFontsMap() {
    return this.fontsMap;
  }
  
  public synchronized void addFont(JRReportFont reportFont) throws JRException {
    addFont(reportFont, false);
  }
  
  public synchronized void addFont(JRReportFont reportFont, boolean isIgnoreDuplicate) throws JRException {
    if (this.fontsMap.containsKey(reportFont.getName())) {
      if (!isIgnoreDuplicate)
        throw new JRException("Duplicate declaration of report font : " + reportFont.getName()); 
    } else {
      this.fontsList.add(reportFont);
      this.fontsMap.put(reportFont.getName(), reportFont);
      if (reportFont.isDefault())
        setDefaultFont(reportFont); 
    } 
  }
  
  public synchronized JRReportFont removeFont(String fontName) {
    return removeFont((JRReportFont)this.fontsMap.get(fontName));
  }
  
  public synchronized JRReportFont removeFont(JRReportFont reportFont) {
    if (reportFont != null) {
      if (reportFont.isDefault())
        setDefaultFont(null); 
      this.fontsList.remove(reportFont);
      this.fontsMap.remove(reportFont.getName());
    } 
    return reportFont;
  }
  
  public JRStyle getDefaultStyle() {
    return this.defaultStyleProvider.getDefaultStyle();
  }
  
  public synchronized void setDefaultStyle(JRStyle style) {
    this.defaultStyleProvider.setDefaultStyle(style);
  }
  
  public JRDefaultStyleProvider getDefaultStyleProvider() {
    return this.defaultStyleProvider;
  }
  
  public JRStyle[] getStyles() {
    JRStyle[] stylesArray = new JRStyle[this.stylesList.size()];
    this.stylesList.toArray((Object[])stylesArray);
    return stylesArray;
  }
  
  public List getStylesList() {
    return this.stylesList;
  }
  
  public Map getStylesMap() {
    return this.stylesMap;
  }
  
  public synchronized void addStyle(JRStyle style) throws JRException {
    addStyle(style, false);
  }
  
  public synchronized void addStyle(JRStyle style, boolean isIgnoreDuplicate) throws JRException {
    if (this.stylesMap.containsKey(style.getName())) {
      if (!isIgnoreDuplicate)
        throw new JRException("Duplicate declaration of report style : " + style.getName()); 
    } else {
      this.stylesList.add(style);
      this.stylesMap.put(style.getName(), style);
      if (style.isDefault())
        setDefaultStyle(style); 
    } 
  }
  
  public synchronized JRStyle removeStyle(String styleName) {
    return removeStyle((JRStyle)this.stylesMap.get(styleName));
  }
  
  public synchronized JRStyle removeStyle(JRStyle style) {
    if (style != null) {
      if (style.isDefault())
        setDefaultStyle(null); 
      this.stylesList.remove(style);
      this.stylesMap.remove(style.getName());
    } 
    return style;
  }
  
  public JROrigin[] getOrigins() {
    return (JROrigin[])this.originsList.toArray((Object[])new JROrigin[this.originsList.size()]);
  }
  
  public List getOriginsList() {
    return this.originsList;
  }
  
  public Map getOriginsMap() {
    return this.originsMap;
  }
  
  public synchronized void addOrigin(JROrigin origin) {
    if (!this.originsMap.containsKey(origin)) {
      this.originsList.add(origin);
      this.originsMap.put(origin, new Integer(this.originsList.size() - 1));
    } 
  }
  
  public synchronized JROrigin removeOrigin(JROrigin origin) {
    if (this.originsMap.containsKey(origin)) {
      this.originsList.remove(origin);
      this.originsMap = new HashMap();
      for (int i = 0; i < this.originsList.size(); i++)
        this.originsMap.put(this.originsList.get(i), new Integer(i)); 
    } 
    return origin;
  }
  
  public List getPages() {
    return this.pages;
  }
  
  public synchronized void addPage(JRPrintPage page) {
    this.anchorIndexes = null;
    this.pages.add(page);
  }
  
  public synchronized void addPage(int index, JRPrintPage page) {
    this.anchorIndexes = null;
    this.pages.add(index, page);
  }
  
  public synchronized JRPrintPage removePage(int index) {
    this.anchorIndexes = null;
    return this.pages.remove(index);
  }
  
  public synchronized Map getAnchorIndexes() {
    if (this.anchorIndexes == null) {
      this.anchorIndexes = new HashMap();
      int i = 0;
      for (Iterator itp = this.pages.iterator(); itp.hasNext(); i++) {
        JRPrintPage page = itp.next();
        Collection elements = page.getElements();
        collectAnchors(elements, i, 0, 0);
      } 
    } 
    return this.anchorIndexes;
  }
  
  protected void collectAnchors(Collection elements, int pageIndex, int offsetX, int offsetY) {
    if (elements != null && elements.size() > 0) {
      JRPrintElement element = null;
      for (Iterator it = elements.iterator(); it.hasNext(); ) {
        element = it.next();
        if (element instanceof JRPrintAnchor)
          this.anchorIndexes.put(((JRPrintAnchor)element).getAnchorName(), new JRPrintAnchorIndex(pageIndex, element, offsetX, offsetY)); 
        if (element instanceof JRPrintFrame) {
          JRPrintFrame frame = (JRPrintFrame)element;
          collectAnchors(frame.getElements(), pageIndex, offsetX + frame.getX(), offsetY + frame.getY());
        } 
      } 
    } 
  }
  
  public String getFormatFactoryClass() {
    return this.formatFactoryClass;
  }
  
  public void setFormatFactoryClass(String formatFactoryClass) {
    this.formatFactoryClass = formatFactoryClass;
  }
  
  public String getLocaleCode() {
    return this.localeCode;
  }
  
  public void setLocaleCode(String localeCode) {
    this.localeCode = localeCode;
  }
  
  public String getTimeZoneId() {
    return this.timeZoneId;
  }
  
  public void setTimeZoneId(String timeZoneId) {
    this.timeZoneId = timeZoneId;
  }
}
