package net.sf.jasperreports.engine.fill;

import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRVariable;

public class JRFillVariable implements JRVariable, JRCalculable {
  protected JRVariable parent = null;
  
  private JRGroup resetGroup = null;
  
  private JRGroup incrementGroup = null;
  
  private Object previousOldValue = null;
  
  private Object oldValue = null;
  
  private Object estimatedValue = null;
  
  private Object incrementedValue = null;
  
  private Object value = null;
  
  private boolean isInitialized = false;
  
  private Object savedValue;
  
  private JRFillVariable[] helperVariables;
  
  private JRIncrementer incrementer = null;
  
  protected JRFillVariable(JRVariable variable, JRFillObjectFactory factory) {
    factory.put(variable, this);
    this.parent = variable;
    this.resetGroup = factory.getGroup(variable.getResetGroup());
    this.incrementGroup = factory.getGroup(variable.getIncrementGroup());
    this.helperVariables = new JRFillVariable[3];
  }
  
  public String getName() {
    return this.parent.getName();
  }
  
  public Class getValueClass() {
    return this.parent.getValueClass();
  }
  
  public String getValueClassName() {
    return this.parent.getValueClassName();
  }
  
  public Class getIncrementerFactoryClass() {
    return this.parent.getIncrementerFactoryClass();
  }
  
  public String getIncrementerFactoryClassName() {
    return this.parent.getIncrementerFactoryClassName();
  }
  
  public JRExpression getExpression() {
    return this.parent.getExpression();
  }
  
  public JRExpression getInitialValueExpression() {
    return this.parent.getInitialValueExpression();
  }
  
  public byte getResetType() {
    return this.parent.getResetType();
  }
  
  public byte getIncrementType() {
    return this.parent.getIncrementType();
  }
  
  public byte getCalculation() {
    return this.parent.getCalculation();
  }
  
  public boolean isSystemDefined() {
    return this.parent.isSystemDefined();
  }
  
  public JRGroup getResetGroup() {
    return this.resetGroup;
  }
  
  public JRGroup getIncrementGroup() {
    return this.incrementGroup;
  }
  
  public Object getOldValue() {
    return this.oldValue;
  }
  
  public void setOldValue(Object oldValue) {
    this.oldValue = oldValue;
  }
  
  public Object getEstimatedValue() {
    return this.estimatedValue;
  }
  
  public void setEstimatedValue(Object estimatedValue) {
    this.estimatedValue = estimatedValue;
  }
  
  public Object getIncrementedValue() {
    return this.incrementedValue;
  }
  
  public void setIncrementedValue(Object incrementedValue) {
    this.incrementedValue = incrementedValue;
  }
  
  public Object getValue() {
    return this.value;
  }
  
  public void setValue(Object value) {
    this.value = value;
  }
  
  public boolean isInitialized() {
    return this.isInitialized;
  }
  
  public void setInitialized(boolean isInitialized) {
    this.isInitialized = isInitialized;
  }
  
  public JRIncrementer getIncrementer() {
    if (this.incrementer == null) {
      JRIncrementerFactory incrementerFactory;
      Class incrementerFactoryClass = getIncrementerFactoryClass();
      if (incrementerFactoryClass == null) {
        incrementerFactory = JRDefaultIncrementerFactory.getFactory(getValueClass());
      } else {
        incrementerFactory = JRIncrementerFactoryCache.getInstance(incrementerFactoryClass);
      } 
      this.incrementer = incrementerFactory.getIncrementer(getCalculation());
    } 
    return this.incrementer;
  }
  
  public JRFillVariable setHelperVariable(JRFillVariable helperVariable, byte type) {
    JRFillVariable old = this.helperVariables[type];
    this.helperVariables[type] = helperVariable;
    return old;
  }
  
  public JRCalculable getHelperVariable(byte type) {
    return this.helperVariables[type];
  }
  
  public Object getValue(byte evaluation) {
    switch (evaluation) {
      case 1:
        returnValue = this.oldValue;
        return returnValue;
      case 2:
        returnValue = this.estimatedValue;
        return returnValue;
    } 
    Object returnValue = this.value;
    return returnValue;
  }
  
  public void overwriteValue(Object newValue, byte evaluation) {
    switch (evaluation) {
      case 1:
        this.savedValue = this.oldValue;
        this.oldValue = newValue;
        return;
      case 2:
        this.savedValue = this.estimatedValue;
        this.estimatedValue = newValue;
        return;
    } 
    this.savedValue = this.value;
    this.value = newValue;
  }
  
  public void restoreValue(byte evaluation) {
    switch (evaluation) {
      case 1:
        this.oldValue = this.savedValue;
        break;
      case 2:
        this.estimatedValue = this.savedValue;
        break;
      default:
        this.value = this.savedValue;
        break;
    } 
    this.savedValue = null;
  }
  
  public Object getPreviousOldValue() {
    return this.previousOldValue;
  }
  
  public void setPreviousOldValue(Object previousOldValue) {
    this.previousOldValue = previousOldValue;
  }
  
  public Object clone() {
    return null;
  }
}
