package RSXTest;

import com.dukascopy.api.indicators.*;

public class RSXOscillator implements IIndicator {

    private int TimePeriod = 21;

    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;

    private double[][] inputs = new double[1][];
    private double[][] outputs = new double[6][];

    public void onStart(IIndicatorContext context) {
        indicatorInfo = new IndicatorInfo("RSXOscillator", "JRSX", "Momentum Indicators", false, false, false, 1, 1, 6);

        inputParameterInfos = new InputParameterInfo[] {
            new InputParameterInfo("Price", InputParameterInfo.Type.DOUBLE)
        };

        optInputParameterInfos = new OptInputParameterInfo[] {
            new OptInputParameterInfo("Time Period", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(21, 2, 2000, 1))
        };

        outputParameterInfos = new OutputParameterInfo[] {
            new OutputParameterInfo("Zero", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
            new OutputParameterInfo("Positive", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.HISTOGRAM),
            new OutputParameterInfo("Negative", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.HISTOGRAM),
            new OutputParameterInfo("MainLine", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
            new OutputParameterInfo("0.5", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
            new OutputParameterInfo("-0.5", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
        };
    }

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

        int r = 0, k = 0, w;
        double v10, v14, v18, v20, v0C, v1C, v8A;
        double f28 = 0, f30 = 0, f38 = 0, f40 = 0, f48 = 0, f50 = 0, f58 = 0, f60 = 0, f68 = 0, f70 = 0, f78 = 0, f80 = 0, Kg, Hg;

        if (TimePeriod - 1 >= 5)
            w = TimePeriod - 1;
        else
            w = 5;

        Kg = 3 / (TimePeriod + 2.0);
        Hg = 1.0 - Kg;

        double[] v8 = new double[endIndex - startIndex + getLookback() + 2];
        double[] val = new double[endIndex - startIndex + 2 + getLookback()];

        int i, j;
        for (i = startIndex, j = 0; i <= endIndex; i++, j++) {
            if (r >= w)
                r = w + 1;
            else
                r++;

            v8[i] = inputs[0][i] - inputs[0][i - 1];
            v8A = Math.abs(v8[i]);

            f28 = Hg * f28 + Kg * v8[i];
            f30 = Kg * f28 + Hg * f30;
            v0C = 1.5 * f28 - 0.5 * f30;

            f38 = Hg * f38 + Kg * v0C;
            f40 = Kg * f38 + Hg * f40;
            v10 = 1.5 * f38 - 0.5 * f40;

            f48 = Hg * f48 + Kg * v10;
            f50 = Kg * f48 + Hg * f50;
            v14 = 1.5 * f48 - 0.5 * f50;


            f58 = Hg * f58 + Kg * v8A;
            f60 = Kg * f58 + Hg * f60;
            v18 = 1.5 * f58 - 0.5 * f60;

            f68 = Hg * f68 + Kg * v18;
            f70 = Kg * f68 + Hg * f70;
            v1C = 1.5 * f68 - 0.5 * f70;

            f78 = Hg * f78 + Kg * v1C;
            f80 = Kg * f78 + Hg * f80;
            v20 = 1.5 * f78 - 0.5 * f80;

            if ((r <= w) && (v8[i] != 0))
                k = 1;
            if ((r == w) && (k == 0))
                r = 0;

            double JRSX = 0;
            if ((r > w) && (v20 > 0.0000000001)) {
                JRSX = v14 / v20;
                if (JRSX > 1)
                    JRSX = 1;
                if (JRSX < -1)
                    JRSX =-1;
            }

            val[i] = JRSX;

            outputs[0][j] = 0;
            outputs[4][j] = 0.5;
            outputs[5][j] = -0.5;

            if (val[i] >= val[i - 1]) {
                outputs[2][j] = Double.NaN;
                outputs[1][j] = JRSX;
            } else {
                outputs[1][j] = Double.NaN;
                outputs[2][j] = JRSX;
            }
            outputs[3][j] = JRSX;
        }

        return new IndicatorResult(startIndex, j);
    }

    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 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 setOutputParameter(int index, Object array) {
        switch (index) {
            case 0:
                outputs[index] = (double[]) array;
                break;
            case 1:
                outputs[index] = (double[]) array;
                break;
            case 2:
                outputs[index] = (double[]) array;
                break;
            case 3:
                outputs[index] = (double[]) array;
                break;
            case 4:
                outputs[index] = (double[]) array;
                break;
            case 5:
                outputs[index] = (double[]) array;
                break;
            default:
                throw new ArrayIndexOutOfBoundsException(index);
        }
    }

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


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