package net.sf.jasperreports.engine.fill;

import java.awt.Color;
import java.awt.Image;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import net.sf.jasperreports.engine.JRAlignment;
import net.sf.jasperreports.engine.JRBox;
import net.sf.jasperreports.engine.JRCommonElement;
import net.sf.jasperreports.engine.JRCommonImage;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRExpressionCollector;
import net.sf.jasperreports.engine.JRGraphicElement;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRHyperlink;
import net.sf.jasperreports.engine.JRHyperlinkParameter;
import net.sf.jasperreports.engine.JRImage;
import net.sf.jasperreports.engine.JRImageRenderer;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintHyperlinkParameters;
import net.sf.jasperreports.engine.JRPrintImage;
import net.sf.jasperreports.engine.JRRenderable;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JRVisitor;
import net.sf.jasperreports.engine.util.JRStyleResolver;
import net.sf.jasperreports.engine.util.LineBoxWrapper;

public class JRFillImage extends JRFillGraphicElement implements JRImage {
  private JRGroup evaluationGroup = null;
  
  private JRRenderable renderer = null;
  
  private String anchorName = null;
  
  private String hyperlinkReference = null;
  
  private String hyperlinkAnchor = null;
  
  private Integer hyperlinkPage = null;
  
  private String hyperlinkTooltip;
  
  private JRPrintHyperlinkParameters hyperlinkParameters;
  
  protected JRFillImage(JRBaseFiller filler, JRImage image, JRFillObjectFactory factory) {
    super(filler, (JRGraphicElement)image, factory);
    this.evaluationGroup = factory.getGroup(image.getEvaluationGroup());
  }
  
  protected JRFillImage(JRFillImage image, JRFillCloneFactory factory) {
    super(image, factory);
    this.evaluationGroup = image.evaluationGroup;
  }
  
  public byte getMode() {
    return JRStyleResolver.getMode((JRCommonElement)this, (byte)2);
  }
  
  public byte getScaleImage() {
    return JRStyleResolver.getScaleImage((JRCommonImage)this);
  }
  
  public Byte getOwnScaleImage() {
    return ((JRImage)this.parent).getOwnScaleImage();
  }
  
  public void setScaleImage(byte scaleImage) {}
  
  public void setScaleImage(Byte scaleImage) {}
  
  public byte getHorizontalAlignment() {
    return JRStyleResolver.getHorizontalAlignment((JRAlignment)this);
  }
  
  public Byte getOwnHorizontalAlignment() {
    return ((JRImage)this.parent).getOwnHorizontalAlignment();
  }
  
  public void setHorizontalAlignment(byte horizontalAlignment) {}
  
  public void setHorizontalAlignment(Byte horizontalAlignment) {}
  
  public byte getVerticalAlignment() {
    return JRStyleResolver.getVerticalAlignment((JRAlignment)this);
  }
  
  public Byte getOwnVerticalAlignment() {
    return ((JRImage)this.parent).getOwnVerticalAlignment();
  }
  
  public void setVerticalAlignment(byte verticalAlignment) {}
  
  public void setVerticalAlignment(Byte verticalAlignment) {}
  
  public boolean isUsingCache() {
    return ((JRImage)this.parent).isUsingCache();
  }
  
  public Boolean isOwnUsingCache() {
    return ((JRImage)this.parent).isOwnUsingCache();
  }
  
  public void setUsingCache(boolean isUsingCache) {}
  
  public void setUsingCache(Boolean isUsingCache) {}
  
  public boolean isLazy() {
    return ((JRImage)this.parent).isLazy();
  }
  
  public void setLazy(boolean isLazy) {}
  
  public byte getOnErrorType() {
    return ((JRImage)this.parent).getOnErrorType();
  }
  
  public void setOnErrorType(byte onErrorType) {}
  
  public byte getEvaluationTime() {
    return ((JRImage)this.parent).getEvaluationTime();
  }
  
  public JRGroup getEvaluationGroup() {
    return this.evaluationGroup;
  }
  
  public JRBox getBox() {
    return (JRBox)new LineBoxWrapper(getLineBox());
  }
  
  public JRLineBox getLineBox() {
    return ((JRImage)this.parent).getLineBox();
  }
  
  public byte getBorder() {
    return getBox().getBorder();
  }
  
  public Byte getOwnBorder() {
    return getBox().getOwnBorder();
  }
  
  public void setBorder(byte border) {
    getBox().setBorder(border);
  }
  
  public void setBorder(Byte border) {
    getBox().setBorder(border);
  }
  
  public Color getBorderColor() {
    return getBox().getBorderColor();
  }
  
  public Color getOwnBorderColor() {
    return getBox().getOwnBorderColor();
  }
  
  public void setBorderColor(Color borderColor) {
    getBox().setBorderColor(borderColor);
  }
  
  public int getPadding() {
    return getBox().getPadding();
  }
  
  public Integer getOwnPadding() {
    return getBox().getOwnPadding();
  }
  
  public void setPadding(int padding) {
    getBox().setPadding(padding);
  }
  
  public void setPadding(Integer padding) {
    getBox().setPadding(padding);
  }
  
  public byte getTopBorder() {
    return getBox().getTopBorder();
  }
  
  public Byte getOwnTopBorder() {
    return getBox().getOwnTopBorder();
  }
  
  public void setTopBorder(byte topBorder) {
    getBox().setTopBorder(topBorder);
  }
  
  public void setTopBorder(Byte topBorder) {
    getBox().setTopBorder(topBorder);
  }
  
  public Color getTopBorderColor() {
    return getBox().getTopBorderColor();
  }
  
  public Color getOwnTopBorderColor() {
    return getBox().getOwnTopBorderColor();
  }
  
  public void setTopBorderColor(Color topBorderColor) {
    getBox().setTopBorderColor(topBorderColor);
  }
  
  public int getTopPadding() {
    return getBox().getTopPadding();
  }
  
  public Integer getOwnTopPadding() {
    return getBox().getOwnTopPadding();
  }
  
  public void setTopPadding(int topPadding) {
    getBox().setTopPadding(topPadding);
  }
  
  public void setTopPadding(Integer topPadding) {
    getBox().setTopPadding(topPadding);
  }
  
  public byte getLeftBorder() {
    return getBox().getLeftBorder();
  }
  
  public Byte getOwnLeftBorder() {
    return getBox().getOwnLeftBorder();
  }
  
  public void setLeftBorder(byte leftBorder) {
    getBox().setLeftBorder(leftBorder);
  }
  
  public void setLeftBorder(Byte leftBorder) {
    getBox().setLeftBorder(leftBorder);
  }
  
  public Color getLeftBorderColor() {
    return getBox().getLeftBorderColor();
  }
  
  public Color getOwnLeftBorderColor() {
    return getBox().getOwnLeftBorderColor();
  }
  
  public void setLeftBorderColor(Color leftBorderColor) {
    getBox().setLeftBorderColor(leftBorderColor);
  }
  
  public int getLeftPadding() {
    return getBox().getLeftPadding();
  }
  
  public Integer getOwnLeftPadding() {
    return getBox().getOwnLeftPadding();
  }
  
  public void setLeftPadding(int leftPadding) {
    getBox().setLeftPadding(leftPadding);
  }
  
  public void setLeftPadding(Integer leftPadding) {
    getBox().setLeftPadding(leftPadding);
  }
  
  public byte getBottomBorder() {
    return getBox().getBottomBorder();
  }
  
  public Byte getOwnBottomBorder() {
    return getBox().getOwnBottomBorder();
  }
  
  public void setBottomBorder(byte bottomBorder) {
    getBox().setBottomBorder(bottomBorder);
  }
  
  public void setBottomBorder(Byte bottomBorder) {
    getBox().setBottomBorder(bottomBorder);
  }
  
  public Color getBottomBorderColor() {
    return getBox().getBottomBorderColor();
  }
  
  public Color getOwnBottomBorderColor() {
    return getBox().getOwnBottomBorderColor();
  }
  
  public void setBottomBorderColor(Color bottomBorderColor) {
    getBox().setBottomBorderColor(bottomBorderColor);
  }
  
  public int getBottomPadding() {
    return getBox().getBottomPadding();
  }
  
  public Integer getOwnBottomPadding() {
    return getBox().getOwnBottomPadding();
  }
  
  public void setBottomPadding(int bottomPadding) {
    getBox().setBottomPadding(bottomPadding);
  }
  
  public void setBottomPadding(Integer bottomPadding) {
    getBox().setBottomPadding(bottomPadding);
  }
  
  public byte getRightBorder() {
    return getBox().getRightBorder();
  }
  
  public Byte getOwnRightBorder() {
    return getBox().getOwnRightBorder();
  }
  
  public void setRightBorder(byte rightBorder) {
    getBox().setRightBorder(rightBorder);
  }
  
  public void setRightBorder(Byte rightBorder) {
    getBox().setRightBorder(rightBorder);
  }
  
  public Color getRightBorderColor() {
    return getBox().getRightBorderColor();
  }
  
  public Color getOwnRightBorderColor() {
    return getBox().getOwnRightBorderColor();
  }
  
  public void setRightBorderColor(Color rightBorderColor) {
    getBox().setRightBorderColor(rightBorderColor);
  }
  
  public int getRightPadding() {
    return getBox().getRightPadding();
  }
  
  public Integer getOwnRightPadding() {
    return getBox().getOwnRightPadding();
  }
  
  public void setRightPadding(int rightPadding) {
    getBox().setRightPadding(rightPadding);
  }
  
  public void setRightPadding(Integer rightPadding) {
    getBox().setRightPadding(rightPadding);
  }
  
  public byte getHyperlinkType() {
    return ((JRImage)this.parent).getHyperlinkType();
  }
  
  public byte getHyperlinkTarget() {
    return ((JRImage)this.parent).getHyperlinkTarget();
  }
  
  public JRExpression getExpression() {
    return ((JRImage)this.parent).getExpression();
  }
  
  public JRExpression getAnchorNameExpression() {
    return ((JRImage)this.parent).getAnchorNameExpression();
  }
  
  public JRExpression getHyperlinkReferenceExpression() {
    return ((JRImage)this.parent).getHyperlinkReferenceExpression();
  }
  
  public JRExpression getHyperlinkAnchorExpression() {
    return ((JRImage)this.parent).getHyperlinkAnchorExpression();
  }
  
  public JRExpression getHyperlinkPageExpression() {
    return ((JRImage)this.parent).getHyperlinkPageExpression();
  }
  
  protected JRRenderable getRenderer() {
    return this.renderer;
  }
  
  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 JRTemplateImage getJRTemplateImage() {
    JRStyle style = getStyle();
    JRTemplateImage template = (JRTemplateImage)getTemplate(style);
    if (template == null) {
      template = new JRTemplateImage((this.band == null) ? null : this.band.getOrigin(), this.filler.getJasperPrint().getDefaultStyleProvider(), this);
      transferProperties(template);
      registerTemplate(style, template);
    } 
    return template;
  }
  
  protected void evaluate(byte evaluation) throws JRException {
    initDelayedEvaluations();
    reset();
    evaluatePrintWhenExpression(evaluation);
    if (isPrintWhenExpressionNull() || (!isPrintWhenExpressionNull() && isPrintWhenTrue()))
      if (isEvaluateNow())
        evaluateImage(evaluation);  
  }
  
  protected void evaluateImage(byte evaluation) throws JRException {
    evaluateProperties(evaluation);
    JRExpression expression = getExpression();
    JRRenderable newRenderer = null;
    Object source = evaluateExpression(expression, evaluation);
    if (source != null)
      if (isUsingCache() && this.filler.fillContext.hasLoadedImage(source)) {
        newRenderer = this.filler.fillContext.getLoadedImage(source).getRenderer();
      } else {
        Class expressionClass = expression.getValueClass();
        if (Image.class.getName().equals(expressionClass.getName())) {
          Image img = (Image)source;
          newRenderer = JRImageRenderer.getInstance(img, getOnErrorType());
        } else if (InputStream.class.getName().equals(expressionClass.getName())) {
          InputStream is = (InputStream)source;
          newRenderer = JRImageRenderer.getInstance(is, getOnErrorType());
        } else if (URL.class.getName().equals(expressionClass.getName())) {
          URL url = (URL)source;
          newRenderer = JRImageRenderer.getInstance(url, getOnErrorType());
        } else if (File.class.getName().equals(expressionClass.getName())) {
          File file = (File)source;
          newRenderer = JRImageRenderer.getInstance(file, getOnErrorType());
        } else if (String.class.getName().equals(expressionClass.getName())) {
          String location = (String)source;
          newRenderer = JRImageRenderer.getInstance(location, getOnErrorType(), isLazy(), this.filler.reportClassLoader, this.filler.urlHandlerFactory, this.filler.fileResolver);
        } else if (JRRenderable.class.getName().equals(expressionClass.getName())) {
          newRenderer = (JRRenderable)source;
        } 
        if (isUsingCache()) {
          JRPrintImage img = new JRTemplatePrintImage(getJRTemplateImage());
          img.setRenderer(newRenderer);
          this.filler.fillContext.registerLoadedImage(source, img);
        } 
      }  
    setValueRepeating((this.renderer == newRenderer));
    this.renderer = newRenderer;
    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) {
    boolean willOverflow = false;
    if (isPrintWhenExpressionNull() || (!isPrintWhenExpressionNull() && isPrintWhenTrue())) {
      setToPrint(true);
    } else {
      setToPrint(false);
    } 
    if (!isToPrint())
      return willOverflow; 
    boolean isToPrint = true;
    boolean isReprinted = false;
    if (isEvaluateNow()) {
      if (isOverflow && isAlreadyPrinted() && !isPrintWhenDetailOverflows())
        isToPrint = false; 
      if (isToPrint && isPrintWhenExpressionNull() && !isPrintRepeatedValues() && isValueRepeating())
        if ((!isPrintInFirstWholeBand() || !getBand().isFirstWholeOnPageColumn()) && (getPrintWhenGroupChanges() == null || !getBand().isNewGroup(getPrintWhenGroupChanges())) && (!isOverflow || !isPrintWhenDetailOverflows()))
          isToPrint = false;  
      if (isToPrint && availableStretchHeight < getRelativeY() - getY() - getBandBottomY()) {
        isToPrint = false;
        willOverflow = true;
      } 
      if (isToPrint && isOverflow && isPrintWhenDetailOverflows() && (isAlreadyPrinted() || (!isAlreadyPrinted() && !isPrintRepeatedValues())))
        isReprinted = true; 
      if (isToPrint && isRemoveLineWhenBlank() && getRenderer() == null)
        isToPrint = false; 
    } else {
      if (isOverflow && isAlreadyPrinted() && !isPrintWhenDetailOverflows())
        isToPrint = false; 
      if (isToPrint && availableStretchHeight < getRelativeY() - getY() - getBandBottomY()) {
        isToPrint = false;
        willOverflow = true;
      } 
      if (isToPrint && isOverflow && isPrintWhenDetailOverflows() && (isAlreadyPrinted() || (!isAlreadyPrinted() && !isPrintRepeatedValues())))
        isReprinted = true; 
    } 
    setToPrint(isToPrint);
    setReprinted(isReprinted);
    return willOverflow;
  }
  
  protected JRPrintElement fill() throws JRException {
    JRTemplatePrintImage printImage;
    JRRecordedValuesPrintImage recordedValuesImage;
    byte evaluationType = getEvaluationTime();
    if (isEvaluateAuto()) {
      printImage = recordedValuesImage = new JRRecordedValuesPrintImage(getJRTemplateImage());
    } else {
      printImage = new JRTemplatePrintImage(getJRTemplateImage());
      recordedValuesImage = null;
    } 
    printImage.setX(getX());
    printImage.setY(getRelativeY());
    printImage.setWidth(getWidth());
    printImage.setHeight(getStretchHeight());
    if (isEvaluateNow()) {
      copy(printImage);
    } else if (isEvaluateAuto()) {
      initDelayedEvaluationPrint(recordedValuesImage);
    } else {
      this.filler.addBoundElement(this, printImage, evaluationType, getEvaluationGroup(), this.band);
    } 
    return printImage;
  }
  
  protected void copy(JRPrintImage printImage) {
    printImage.setRenderer(getRenderer());
    printImage.setAnchorName(getAnchorName());
    printImage.setHyperlinkReference(getHyperlinkReference());
    printImage.setHyperlinkAnchor(getHyperlinkAnchor());
    printImage.setHyperlinkPage(getHyperlinkPage());
    printImage.setHyperlinkTooltip(getHyperlinkTooltip());
    printImage.setBookmarkLevel(getBookmarkLevel());
    printImage.setHyperlinkParameters(this.hyperlinkParameters);
    transferProperties((JRPrintElement)printImage);
  }
  
  public void collectExpressions(JRExpressionCollector collector) {
    collector.collect(this);
  }
  
  public void visit(JRVisitor visitor) {
    visitor.visitImage(this);
  }
  
  protected void resolveElement(JRPrintElement element, byte evaluation) throws JRException {
    evaluateImage(evaluation);
    copy((JRPrintImage)element);
  }
  
  public int getBookmarkLevel() {
    return ((JRImage)this.parent).getBookmarkLevel();
  }
  
  public JRFillCloneable createClone(JRFillCloneFactory factory) {
    return new JRFillImage(this, factory);
  }
  
  protected void collectDelayedEvaluations() {
    collectDelayedEvaluations(getExpression());
    collectDelayedEvaluations(getAnchorNameExpression());
    collectDelayedEvaluations(getHyperlinkReferenceExpression());
    collectDelayedEvaluations(getHyperlinkAnchorExpression());
    collectDelayedEvaluations(getHyperlinkPageExpression());
  }
  
  public JRHyperlinkParameter[] getHyperlinkParameters() {
    return ((JRImage)this.parent).getHyperlinkParameters();
  }
  
  public String getLinkType() {
    return ((JRImage)this.parent).getLinkType();
  }
  
  public JRExpression getHyperlinkTooltipExpression() {
    return ((JRImage)this.parent).getHyperlinkTooltipExpression();
  }
}
