package net.sf.jasperreports.engine.fill;

import java.text.DecimalFormat;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRExpressionCollector;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRHyperlink;
import net.sf.jasperreports.engine.JRHyperlinkParameter;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintHyperlinkParameters;
import net.sf.jasperreports.engine.JRPrintText;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JRTextElement;
import net.sf.jasperreports.engine.JRTextField;
import net.sf.jasperreports.engine.JRVisitor;
import net.sf.jasperreports.engine.util.JRDataUtils;
import net.sf.jasperreports.engine.util.JRStyleResolver;

public class JRFillTextField extends JRFillTextElement implements JRTextField {
  private JRGroup evaluationGroup = null;
  
  private String anchorName = null;
  
  private String hyperlinkReference = null;
  
  private String hyperlinkAnchor = null;
  
  private Integer hyperlinkPage = null;
  
  private String hyperlinkTooltip;
  
  private JRPrintHyperlinkParameters hyperlinkParameters;
  
  protected JRFillTextField(JRBaseFiller filler, JRTextField textField, JRFillObjectFactory factory) {
    super(filler, (JRTextElement)textField, factory);
    this.evaluationGroup = factory.getGroup(textField.getEvaluationGroup());
  }
  
  protected JRFillTextField(JRFillTextField textField, JRFillCloneFactory factory) {
    super(textField, factory);
    this.evaluationGroup = textField.evaluationGroup;
  }
  
  public boolean isStretchWithOverflow() {
    return ((JRTextField)this.parent).isStretchWithOverflow();
  }
  
  public void setStretchWithOverflow(boolean isStretchWithOverflow) {}
  
  public byte getEvaluationTime() {
    return ((JRTextField)this.parent).getEvaluationTime();
  }
  
  public String getPattern() {
    return JRStyleResolver.getPattern(this);
  }
  
  public String getOwnPattern() {
    return ((JRTextField)this.parent).getOwnPattern();
  }
  
  public void setPattern(String pattern) {}
  
  public boolean isBlankWhenNull() {
    return JRStyleResolver.isBlankWhenNull(this);
  }
  
  public Boolean isOwnBlankWhenNull() {
    return ((JRTextField)this.parent).isOwnBlankWhenNull();
  }
  
  public void setBlankWhenNull(boolean isBlank) {}
  
  public void setBlankWhenNull(Boolean isBlank) {}
  
  public byte getHyperlinkType() {
    return ((JRTextField)this.parent).getHyperlinkType();
  }
  
  public byte getHyperlinkTarget() {
    return ((JRTextField)this.parent).getHyperlinkTarget();
  }
  
  public JRGroup getEvaluationGroup() {
    return this.evaluationGroup;
  }
  
  public JRExpression getExpression() {
    return ((JRTextField)this.parent).getExpression();
  }
  
  public JRExpression getAnchorNameExpression() {
    return ((JRTextField)this.parent).getAnchorNameExpression();
  }
  
  public JRExpression getHyperlinkReferenceExpression() {
    return ((JRTextField)this.parent).getHyperlinkReferenceExpression();
  }
  
  public JRExpression getHyperlinkAnchorExpression() {
    return ((JRTextField)this.parent).getHyperlinkAnchorExpression();
  }
  
  public JRExpression getHyperlinkPageExpression() {
    return ((JRTextField)this.parent).getHyperlinkPageExpression();
  }
  
  protected String getAnchorName() {
    return this.anchorName;
  }
  
  protected String getHyperlinkReference() {
    return this.hyperlinkReference;
  }
  
  protected String getHyperlinkAnchor() {
    return this.hyperlinkAnchor;
  }
  
  protected Integer getHyperlinkPage() {
    return this.hyperlinkPage;
  }
  
  protected String getHyperlinkTooltip() {
    return this.hyperlinkTooltip;
  }
  
  protected JRTemplateText getJRTemplateText() {
    JRStyle style = getStyle();
    JRTemplateText template = (JRTemplateText)getTemplate(style);
    if (template == null) {
      template = new JRTemplateText((this.band == null) ? null : this.band.getOrigin(), this.filler.getJasperPrint().getDefaultStyleProvider(), this);
      transferProperties(template);
      setTemplatePattern(template);
      registerTemplate(style, template);
    } 
    return template;
  }
  
  protected void setTemplatePattern(JRTemplateText template) {
    if (getExpression() != null) {
      Class valueClass = getExpression().getValueClass();
      if (!String.class.equals(valueClass)) {
        template.setValueClassName(valueClass.getName());
        String pattern = getTemplatePattern();
        if (pattern != null)
          template.setPattern(pattern); 
        if (!this.filler.hasMasterFormatFactory())
          template.setFormatFactoryClass(this.filler.getFormatFactory().getClass().getName()); 
        if (!this.filler.hasMasterLocale())
          template.setLocaleCode(JRDataUtils.getLocaleCode(this.filler.getLocale())); 
        if (!this.filler.hasMasterTimeZone() && Date.class.isAssignableFrom(valueClass))
          template.setTimeZoneId(JRDataUtils.getTimeZoneId(this.filler.getTimeZone())); 
      } 
    } 
  }
  
  protected void evaluate(byte evaluation) throws JRException {
    initDelayedEvaluations();
    reset();
    evaluatePrintWhenExpression(evaluation);
    if (isPrintWhenExpressionNull() || (!isPrintWhenExpressionNull() && isPrintWhenTrue()))
      if (isEvaluateNow())
        evaluateText(evaluation);  
  }
  
  protected void evaluateText(byte evaluation) throws JRException {
    evaluateProperties(evaluation);
    Object textFieldValue = evaluateExpression(getExpression(), evaluation);
    if (textFieldValue == null) {
      if (isBlankWhenNull())
        textFieldValue = ""; 
    } else {
      Format format = getFormat();
      if (format != null)
        textFieldValue = format.format(textFieldValue); 
    } 
    String oldRawText = getRawText();
    String newRawText = processMarkupText(String.valueOf(textFieldValue));
    setRawText(newRawText);
    setTextStart(0);
    setTextEnd(0);
    setValueRepeating(((oldRawText == null && newRawText == null) || (oldRawText != null && oldRawText.equals(newRawText))));
    this.anchorName = (String)evaluateExpression(getAnchorNameExpression(), evaluation);
    this.hyperlinkReference = (String)evaluateExpression(getHyperlinkReferenceExpression(), evaluation);
    this.hyperlinkAnchor = (String)evaluateExpression(getHyperlinkAnchorExpression(), evaluation);
    this.hyperlinkPage = (Integer)evaluateExpression(getHyperlinkPageExpression(), evaluation);
    this.hyperlinkTooltip = (String)evaluateExpression(getHyperlinkTooltipExpression(), evaluation);
    this.hyperlinkParameters = JRFillHyperlinkHelper.evaluateHyperlinkParameters((JRHyperlink)this, this.expressionEvaluator, evaluation);
  }
  
  protected boolean prepare(int availableStretchHeight, boolean isOverflow) throws JRException {
    boolean willOverflow = false;
    super.prepare(availableStretchHeight, isOverflow);
    if (!isToPrint())
      return willOverflow; 
    boolean isToPrint = true;
    boolean isReprinted = false;
    if (isEvaluateNow()) {
      if (isOverflow) {
        if (getPositionType() == 3) {
          setTextStart(0);
          setTextEnd(0);
        } 
        if (getTextEnd() >= getText().length() || !isStretchWithOverflow() || getRotation() != 0)
          if (isAlreadyPrinted())
            if (isPrintWhenDetailOverflows()) {
              setTextStart(0);
              setTextEnd(0);
              isReprinted = true;
            } else {
              isToPrint = false;
            }   
        if (isToPrint && isPrintWhenExpressionNull() && !isPrintRepeatedValues() && isValueRepeating())
          isToPrint = false; 
      } else if (isPrintWhenExpressionNull() && !isPrintRepeatedValues() && isValueRepeating()) {
        if ((!isPrintInFirstWholeBand() || !getBand().isFirstWholeOnPageColumn()) && (getPrintWhenGroupChanges() == null || !getBand().isNewGroup(getPrintWhenGroupChanges())))
          isToPrint = false; 
      } 
      if (isToPrint)
        if (availableStretchHeight >= getRelativeY() - getY() - getBandBottomY()) {
          if (getTextEnd() < getText().length() || getTextEnd() == 0) {
            if (isStretchWithOverflow() && getRotation() == 0) {
              chopTextElement(availableStretchHeight - getRelativeY() + getY() + getBandBottomY());
              if (getTextEnd() < getText().length())
                willOverflow = true; 
            } else {
              chopTextElement(0);
            } 
          } else {
            isToPrint = false;
          } 
        } else {
          isToPrint = false;
          willOverflow = true;
        }  
      if (isToPrint && isRemoveLineWhenBlank() && getText().substring(getTextStart(), getTextEnd()).trim().length() == 0)
        isToPrint = false; 
    } else {
      if (isOverflow && isAlreadyPrinted())
        if (isPrintWhenDetailOverflows()) {
          isReprinted = true;
        } else {
          isToPrint = false;
        }  
      if (isToPrint && availableStretchHeight < getRelativeY() - getY() - getBandBottomY()) {
        isToPrint = false;
        willOverflow = true;
      } 
    } 
    setToPrint(isToPrint);
    setReprinted(isReprinted);
    return willOverflow;
  }
  
  protected JRPrintElement fill() throws JRException {
    JRTemplatePrintText text;
    JRRecordedValuesPrintText recordedValuesText;
    byte evaluationType = getEvaluationTime();
    if (isEvaluateAuto()) {
      text = recordedValuesText = new JRRecordedValuesPrintText(getJRTemplateText());
    } else {
      text = new JRTemplatePrintText(getJRTemplateText());
      recordedValuesText = null;
    } 
    text.setX(getX());
    text.setY(getRelativeY());
    text.setWidth(getWidth());
    if (getRotation() == 0) {
      text.setHeight(getStretchHeight());
    } else {
      text.setHeight(getHeight());
    } 
    text.setRunDirection(getRunDirection());
    if (isEvaluateNow()) {
      copy(text);
    } else if (isEvaluateAuto()) {
      initDelayedEvaluationPrint(recordedValuesText);
    } else {
      this.filler.addBoundElement(this, text, evaluationType, getEvaluationGroup(), this.band);
    } 
    return text;
  }
  
  protected void copy(JRPrintText text) {
    text.setLineSpacingFactor(getLineSpacingFactor());
    text.setLeadingOffset(getLeadingOffset());
    text.setTextHeight(getTextHeight());
    setPrintText(text);
    text.setAnchorName(getAnchorName());
    text.setHyperlinkReference(getHyperlinkReference());
    text.setHyperlinkAnchor(getHyperlinkAnchor());
    text.setHyperlinkPage(getHyperlinkPage());
    text.setHyperlinkTooltip(getHyperlinkTooltip());
    text.setBookmarkLevel(getBookmarkLevel());
    text.setHyperlinkParameters(this.hyperlinkParameters);
    transferProperties((JRPrintElement)text);
  }
  
  protected Format getFormat() {
    Format format = null;
    JRExpression valueExpression = getExpression();
    if (valueExpression != null) {
      Class valueClass = valueExpression.getValueClass();
      if (Date.class.isAssignableFrom(valueClass)) {
        format = this.filler.getDateFormat(getPattern());
      } else if (Number.class.isAssignableFrom(valueClass)) {
        format = this.filler.getNumberFormat(getPattern());
      } 
    } 
    return format;
  }
  
  protected String getTemplatePattern() {
    String pattern = null;
    String originalPattern = getPattern();
    Format format = getFormat();
    JRExpression valueExpression = getExpression();
    if (format != null && valueExpression != null) {
      Class valueClass = valueExpression.getValueClass();
      if (Date.class.isAssignableFrom(valueClass)) {
        if (format instanceof SimpleDateFormat)
          pattern = ((SimpleDateFormat)format).toPattern(); 
      } else if (Number.class.isAssignableFrom(valueClass)) {
        if (format instanceof DecimalFormat)
          pattern = ((DecimalFormat)format).toPattern(); 
      } 
    } 
    if (pattern == null)
      pattern = originalPattern; 
    return pattern;
  }
  
  public void collectExpressions(JRExpressionCollector collector) {
    collector.collect(this);
  }
  
  public void visit(JRVisitor visitor) {
    visitor.visitTextField(this);
  }
  
  protected void resolveElement(JRPrintElement element, byte evaluation) throws JRException {
    evaluateText(evaluation);
    chopTextElement(0);
    copy((JRPrintText)element);
  }
  
  public int getBookmarkLevel() {
    return ((JRTextField)this.parent).getBookmarkLevel();
  }
  
  public JRFillCloneable createClone(JRFillCloneFactory factory) {
    return new JRFillTextField(this, factory);
  }
  
  protected void collectDelayedEvaluations() {
    collectDelayedEvaluations(getExpression());
    collectDelayedEvaluations(getAnchorNameExpression());
    collectDelayedEvaluations(getHyperlinkReferenceExpression());
    collectDelayedEvaluations(getHyperlinkAnchorExpression());
    collectDelayedEvaluations(getHyperlinkPageExpression());
  }
  
  public JRHyperlinkParameter[] getHyperlinkParameters() {
    return ((JRTextField)this.parent).getHyperlinkParameters();
  }
  
  public String getLinkType() {
    return ((JRTextField)this.parent).getLinkType();
  }
  
  public JRExpression getHyperlinkTooltipExpression() {
    return ((JRTextField)this.parent).getHyperlinkTooltipExpression();
  }
  
  protected boolean canOverflow() {
    return (isStretchWithOverflow() && getRotation() == 0 && isEvaluateNow() && this.filler.isBandOverFlowAllowed());
  }
}
