package jforex.indicators;

import java.util.Arrays;

import com.dukascopy.api.IConsole;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.indicators.IIndicatorContext;
import com.dukascopy.api.indicators.IndicatorInfo;
import com.dukascopy.api.indicators.IndicatorResult;
import com.dukascopy.api.indicators.InputParameterInfo;
import com.dukascopy.api.indicators.IntegerRangeDescription;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;

/**
 * The indicator accepts PRICE inputs and outputs the average of the last 3 
 * OPEN prices. For debugging purposes, the indicator also logs input, output
 * arrays and other parameters.
 *
 */
public class InputsOutputsPriceTest implements IIndicator{
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private double[][][] inputs = new double[1][][];
    private int timePeriod = 2;
    private double[][] outputs = new double[1][];    
    private IConsole console;
    
    private static final int OPEN=0, CLOSE=1, HIGH=2, LOW=3, VOLUME=4;
    
    public void onStart(IIndicatorContext context) {
        indicatorInfo = new IndicatorInfo("Inputs outputs test", "My custom", "Math Operators", true, false, false, 1, 1, 1);
        inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Price", InputParameterInfo.Type.PRICE)};
        optInputParameterInfos = new OptInputParameterInfo[] {
                new OptInputParameterInfo("Time period", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(timePeriod, 1, 200, 1))};
        outputParameterInfos = new OutputParameterInfo[] {
                new OutputParameterInfo("Average", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE)                                                                  
        };           
        console = context.getConsole();
    }

    public IndicatorResult calculate(int startIndex, int endIndex) {       
        //lookback adjustment
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        if (startIndex > endIndex) {
            return new IndicatorResult(0, 0);
        }   

        for (int i = startIndex, j = 0; i <= endIndex; i++, j++) {
            //average of the last 3 values - mind that we have no risk of negative index i, because of lookback adjustment above
            //if you need more values for average, then increase lookback
            outputs[0][j] = (inputs[0][OPEN][i] + inputs[0][OPEN][i-1]  + inputs[0][OPEN][i-2])/3;
        }
        
        //logging for your convenience, to see with what inputs and outputs we work with and what is the lookback effect
        //change the timePeriod value in the optional parameters to see how the input and output sizes change
        console.getOut().println(String.format("output length = %s, contents = %s, \ninput[OPEN] length = %s, contents = %s,\n" +
                "startIndex=%s, endIndex=%s, getLookback()=%s", 
                outputs[0].length, Arrays.toString(outputs[0]), 
                inputs[0][OPEN].length, Arrays.toString(inputs[0][OPEN]),
                startIndex, endIndex, getLookback()));
        
        return new IndicatorResult(startIndex, endIndex-startIndex + 1);        
    }

    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }

    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }

    public int getLookback() {
        return timePeriod;
    }

    public int getLookforward() {
        return 0;
    }

    public OptInputParameterInfo getOptInputParameterInfo(int index) {
        if (index <= optInputParameterInfos.length) {
            return optInputParameterInfos[index];
        }
        return null;
    }

    public OutputParameterInfo getOutputParameterInfo(int index) {
        if (index <= outputParameterInfos.length) {
            return outputParameterInfos[index];
        }
        return null;
    }

    public void setInputParameter(int index, Object array) {
        inputs[index] = (double[][]) array;
    }

    public void setOptInputParameter(int index, Object value) {
        timePeriod = (Integer) value;
    }

    public void setOutputParameter(int index, Object array) {
        outputs[index] = (double[]) array;
    }        
 }