package net.sf.jasperreports.engine.fill;

import java.math.BigDecimal;

class JRBigDecimalVarianceIncrementer extends JRAbstractExtendedIncrementer {
  private static JRBigDecimalVarianceIncrementer mainInstance = new JRBigDecimalVarianceIncrementer();
  
  public static JRBigDecimalVarianceIncrementer getInstance() {
    return mainInstance;
  }
  
  public Object increment(JRCalculable variable, Object expressionValue, AbstractValueProvider valueProvider) {
    BigDecimal value = (BigDecimal)variable.getIncrementedValue();
    BigDecimal newValue = (BigDecimal)expressionValue;
    if (newValue == null) {
      if (variable.isInitialized())
        return null; 
      return value;
    } 
    if (value == null || variable.isInitialized())
      return JRBigDecimalIncrementerFactory.ZERO; 
    BigDecimal countValue = (BigDecimal)valueProvider.getValue(variable.getHelperVariable((byte)0));
    BigDecimal sumValue = (BigDecimal)valueProvider.getValue(variable.getHelperVariable((byte)1));
    return countValue.subtract(JRBigDecimalIncrementerFactory.ONE).multiply(value).divide(countValue, 4).add(sumValue.divide(countValue, 4).subtract(newValue).multiply(sumValue.divide(countValue, 4).subtract(newValue)).divide(countValue.subtract(JRBigDecimalIncrementerFactory.ONE), 4));
  }
  
  public Object combine(JRCalculable calculable, JRCalculable calculableValue, AbstractValueProvider valueProvider) {
    BigDecimal value = (BigDecimal)calculable.getIncrementedValue();
    if (calculableValue.getValue() == null) {
      if (calculable.isInitialized())
        return null; 
      return value;
    } 
    if (value == null || calculable.isInitialized())
      return calculableValue.getIncrementedValue(); 
    BigDecimal v1 = value;
    BigDecimal c1 = (BigDecimal)valueProvider.getValue(calculable.getHelperVariable((byte)0));
    BigDecimal s1 = (BigDecimal)valueProvider.getValue(calculable.getHelperVariable((byte)1));
    BigDecimal v2 = (BigDecimal)calculableValue.getIncrementedValue();
    BigDecimal c2 = (BigDecimal)valueProvider.getValue(calculableValue.getHelperVariable((byte)0));
    BigDecimal s2 = (BigDecimal)valueProvider.getValue(calculableValue.getHelperVariable((byte)1));
    c1 = c1.subtract(c2);
    s1 = s1.subtract(s2);
    BigDecimal c = c1.add(c2);
    BigDecimal x1 = s1.divide(c, 4);
    BigDecimal x2 = s2.divide(c, 4);
    BigDecimal x3 = x1.multiply(x2);
    return c1.divide(c, 4).multiply(v1).add(c2.divide(c, 4).multiply(v2)).add(c2.divide(c1, 4).multiply(x1).multiply(x1)).add(c1.divide(c2, 4).multiply(x2).multiply(x2)).subtract(x3).subtract(x3);
  }
  
  public Object initialValue() {
    return JRBigDecimalIncrementerFactory.ZERO;
  }
}
