//package jforex;

import com.dukascopy.api.indicators.*;

/**
 * @author Dmitry Shohov
 */
public class SMAOverRSIIndicator implements IIndicator {
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private double[][] inputs = new double[1][];
    private double[][] outputs = new double[2][];
    private IIndicatorContext context;
    private IIndicator rsiIndicator;
    private IIndicator smaIndicator;
    
    public void onStart(IIndicatorContext context) {
        try {
        this.context = context;
        //getting interfaces of RSI and SMA indicators
        IIndicatorsProvider indicatorsProvider = context.getIndicatorsProvider();
        rsiIndicator = indicatorsProvider.getIndicator("RSI");
        smaIndicator = indicatorsProvider.getIndicator("SMA");
        //inicator with one input, two optional params and two outputs
        indicatorInfo = new IndicatorInfo("SMA_RSI", "SMA over RSI", "Common",
                false, false, false, false, 1, 2, 2);
        //one input array of doubles
        inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.DOUBLE)};
        //two optional params, one for every indicator
        optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("RSI Time Period", OptInputParameterInfo.Type.OTHER,
                new IntegerRangeDescription(14, 2, 100, 1)), new OptInputParameterInfo("SMA Time Period", OptInputParameterInfo.Type.OTHER,
                new IntegerRangeDescription(14, 2, 100, 1))};
        //two output arrays, one for RSI and one for SMA over RSI
        outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("RSI line", OutputParameterInfo.Type.DOUBLE,
                OutputParameterInfo.LINE), new OutputParameterInfo("SMA line", OutputParameterInfo.Type.DOUBLE,
                OutputParameterInfo.LINE)};
        } catch(Throwable th) {
            th.printStackTrace();
        }
    }

    public IndicatorResult calculate(int startIndex, int endIndex) {
        //calculating rsi
        int rsiLookback = rsiIndicator.getLookback();
        //first alocate buffer for rsi results
        double[] rsiOutput;
        if (startIndex > endIndex || rsiLookback > endIndex) {
            return new IndicatorResult(0, 0);
        } else {
            rsiOutput = new double[endIndex - (rsiLookback > startIndex ? rsiLookback : startIndex) + 1];
        }
        //init rsi indicator with input data and array for output
        rsiIndicator.setInputParameter(0, inputs[0]);
        rsiIndicator.setOutputParameter(0, rsiOutput);
        IndicatorResult rsiResult = rsiIndicator.calculate(startIndex, endIndex);
        if (rsiResult.getNumberOfElements() < smaIndicator.getLookback()) {
            //not enough data to calculate sma
            return new IndicatorResult(0, 0);
        }
        
        //calculating sma
        smaIndicator.setInputParameter(0, rsiOutput);
        smaIndicator.setOutputParameter(0, outputs[1]);
        IndicatorResult smaResult = smaIndicator.calculate(0, rsiResult.getNumberOfElements() - 1);
        if (smaResult.getNumberOfElements() == 0) {
            //sma returned 0 values
            return new IndicatorResult(0, 0);
        }
        //copy rsi values to output excluding first values used for sma lookback
        System.arraycopy(rsiOutput, smaResult.getFirstValueIndex(), outputs[0], 0, smaResult.getNumberOfElements());
        //creating result, first value index for our input is FVI for rsi + FVI for sma, because we calculated sma starting from 0 element
        IndicatorResult result = new IndicatorResult(rsiResult.getFirstValueIndex() + smaResult.getFirstValueIndex(), smaResult.getNumberOfElements());
        return result;
    }

    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }

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

    public int getLookforward() {
        return rsiIndicator.getLookforward() + smaIndicator.getLookforward();
    }
    public int getLookback() {
        return rsiIndicator.getLookback() + smaIndicator.getLookback();
    }

    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) {
        //set optional params in indicators
        switch (index) {
            case 0:
                rsiIndicator.setOptInputParameter(0, value);
                break;
            case 1:
                smaIndicator.setOptInputParameter(0, value);
                break;
        }
    }

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