package jforex;

import com.dukascopy.api.indicators.*;
import com.dukascopy.api.IConsole;

public class HMABands implements IIndicator{

    private IndicatorInfo myIndicatorInfo;
    private InputParameterInfo[] myInputParameterInfos;
    private OptInputParameterInfo[] myOptInputParameterInfos;
    private OutputParameterInfo[] myOutputParameterInfos;
    
    private IConsole myConsole;
    
    private double[][] myInputs=new double[1][];
    private double[][] myOutputs=new double[3][];
    
    private int hmaTimePeriod=14;
    private int stdTimePeriod=14;
    private double ndDev=0.5;
    
    private IIndicatorContext myContext;
    private IIndicator hmaIndicator;
    private IIndicator stdDevIndicator;
    
    
    @Override
    public void onStart(IIndicatorContext context) {
        // getting interface of HMA/
        IIndicatorsProvider myIndicatorsProvider=context.getIndicatorsProvider();
        hmaIndicator=myIndicatorsProvider.getIndicator("HMA");
        stdDevIndicator=myIndicatorsProvider.getIndicator("STDDEV");
        //indicator with one input,three optional params and two outputs
        myIndicatorInfo=new IndicatorInfo("HMABands","HMA added stdDevBands","My indicators",
                false,false,false,1,3,3);
        //one input array of doubles
        myInputParameterInfos=new InputParameterInfo[]{
                new InputParameterInfo("myInput data",InputParameterInfo.Type.DOUBLE)};
        //three optional params:two for indicator,one for degree of stdDev.
        myOptInputParameterInfos=new OptInputParameterInfo[]{
                new OptInputParameterInfo("HMA Time Period",OptInputParameterInfo.Type.OTHER,
                    new IntegerRangeDescription(hmaTimePeriod,2,100,1)),
                new OptInputParameterInfo("stdDev Time Period",OptInputParameterInfo.Type.OTHER,
                    new IntegerRangeDescription(stdTimePeriod,2,100,1)),
                new OptInputParameterInfo("Degree of stdDev",OptInputParameterInfo.Type.OTHER, 
                    new DoubleRangeDescription(ndDev,0.5,5,0.01,2))};
        //Three output arrays,one for HMA and two for upper/lower bands
        myOutputParameterInfos=new OutputParameterInfo[]{
                new OutputParameterInfo("HMA line",OutputParameterInfo.Type.DOUBLE,
                    OutputParameterInfo.DrawingStyle.LINE),
                new OutputParameterInfo("Upper Band",OutputParameterInfo.Type.DOUBLE,
                    OutputParameterInfo.DrawingStyle.LINE),
                new OutputParameterInfo("Lower Band",OutputParameterInfo.Type.DOUBLE,
                    OutputParameterInfo.DrawingStyle.LINE)};
                    
        myConsole=context.getConsole();
        myConsole.getInfo().println("Indicator initializing...");
        
    }
    

    public IndicatorResult calculate(int startIndex, int endIndex) {
        if(startIndex-getLookback()<0){
            startIndex-=startIndex-getLookback();
        }
        //calculating hma and stdDev
        int hmaLookback=hmaIndicator.getLookback();
        int stdDevLookback=stdDevIndicator.getLookback();
        int maxLookback=Math.max(hmaLookback, stdDevLookback);
        //first allocate buffer for hma and stdDev results;
        double[] hmaOutput;
        double[] stdDevOutput;
        if(startIndex>endIndex || maxLookback>endIndex){
            return new IndicatorResult(0,0);
        }else{
            //take the greater value (startIndex/lookback)
            hmaOutput=new double[endIndex-(maxLookback>startIndex?maxLookback:startIndex)+1];
            stdDevOutput=new double[endIndex-(maxLookback>startIndex?maxLookback:startIndex)+1];
        }        
        
        // initializing hma and stdDev input data.
        hmaIndicator.setInputParameter(0, myInputs[0]);
        stdDevIndicator.setInputParameter(0, myInputs[0]);
        
        //calculating hma and stdDev;
//        hmaIndicator.setOptInputParameter(0, hmaTimePeriod);
        hmaIndicator.setOutputParameter(0, hmaOutput);
        IndicatorResult hmaResult=hmaIndicator.calculate(startIndex, endIndex);
        
//        stdDevIndicator.setOptInputParameter(0, stdTimePeriod);
        stdDevIndicator.setOutputParameter(0, stdDevOutput);
        IndicatorResult stdDevResult=stdDevIndicator.calculate(startIndex, endIndex);
        
        myConsole.getOut().println("stdDevOutput: "+stdDevOutput);  //----OK!
        myConsole.getOut().println("numberOfElements: "+hmaResult.getNumberOfElements());


        //copy hma values to myOutputs[0]
        System.arraycopy(hmaOutput, hmaResult.getFirstValueIndex(),myOutputs[0], 0, hmaResult.getNumberOfElements());        
                        
        //calculating upper-band and lower-band: reference to MultiInputIndicator.java.
/*        int i,j;
        for(i=startIndex,j=0;i<=endIndex;i++,j++){
            
            myOutputs[1][j]=hmaOutput[i]+stdDevOutput[i];
            myOutputs[2][j]=hmaOutput[i]-stdDevOutput[i];

        }
*/
        
        IndicatorResult result=new IndicatorResult(stdDevResult.getFirstValueIndex(),
                stdDevResult.getNumberOfElements());
        return result;
    }


    public IndicatorInfo getIndicatorInfo() {
        // TODO Auto-generated method stub
        return myIndicatorInfo;
    }


    public InputParameterInfo getInputParameterInfo(int index) {
        if(index<=myInputParameterInfos.length){
            return myInputParameterInfos[index];
        }
        return null;
    }

    @Override
    public OptInputParameterInfo getOptInputParameterInfo(int index) {
        if(index<=myOptInputParameterInfos.length){
            return myOptInputParameterInfos[index];
        }
        return null;
    }

    @Override
    public OutputParameterInfo getOutputParameterInfo(int index) {
        if(index<=myOutputParameterInfos.length){
            return myOutputParameterInfos[index];
        }
        return null;
    }

    @Override
    public void setInputParameter(int index, Object array) {
        // TODO Auto-generated method stub
        myInputs[index]=(double[]) array;
    }

    @Override
    public void setOptInputParameter(int index, Object value) {
        // TODO Auto-generated method stub
        switch(index){
        case 0:
            hmaTimePeriod=(Integer) value;
            hmaIndicator.setOptInputParameter(0, hmaTimePeriod);
            break;
        case 1:
            stdTimePeriod=(Integer) value;
            stdDevIndicator.setOptInputParameter(0, stdTimePeriod);
            break;
        case 2:
            ndDev=(Double) value;
            stdDevIndicator.setOptInputParameter(1, ndDev);
            break;
        default:
            throw new ArrayIndexOutOfBoundsException(index);
        
        }
    }

    @Override
    public void setOutputParameter(int index, Object array) {
        // TODO Auto-generated method stub
        myOutputs[index]=(double[]) array;
    }

    @Override
    public int getLookback() {
        //calculating HMA and stdDev
        return Math.max(hmaIndicator.getLookback(), 
                stdDevIndicator.getLookback());
    }

    @Override
    public int getLookforward() {
        // TODO Auto-generated method stub
        return 0;
    }



}