package jforex.indicators;

import java.awt.Color;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Arrays;
import java.math.BigDecimal;

import com.dukascopy.api.IConsole;
import com.dukascopy.api.IIndicators.AppliedPrice;
import com.dukascopy.api.Instrument;
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.IntegerListDescription;
import com.dukascopy.api.indicators.IntegerRangeDescription;
import com.dukascopy.api.indicators.DoubleRangeDescription;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;

public class TRIXHA3b implements IIndicator {
    
    private static final int OPEN = 0;
    private static final int CLOSE = 1;
    private static final int HIGH = 2;
    private static final int LOW = 3;
    private static final int VOLUME = 4;
    
    private    double sump=0, sumn=0;        
    
    private IndicatorInfo           indicatorInfo;

    // INPUTS
    private InputParameterInfo[]    inputParameterInfos;
    private double[][]              inPrice;

    // OPT INPUTS
    private OptInputParameterInfo[] optInputParameterInfos;    
    private int                     appliedPrice;
    private int                     TRIXper;
        
    // OUTPUTS
    private OutputParameterInfo[]   outputParameterInfos;
    private double[][]              output;


    // CONTEXT
    private IConsole                console;

    // private Instrument instrument;
    private Instrument              instrument = Instrument.EURUSD; // workaround
    
    private int lookback2=0, np=0, nn=0;

    private IIndicator              trix;
    
    public int getLookback() {
        trix.setOptInputParameter(0,TRIXper);
        return trix.getLookback();
    }

    public int getLookforward() {
        return 0;
    }

    /**************
     * CALCULATE
     **************/
    public IndicatorResult calculate(int startIndex, int endIndex) {
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        if (startIndex > endIndex) {
            return new IndicatorResult(0, 0);
        }
        int len = endIndex - startIndex + 1;
        
        trix.setInputParameter(0, inPrice[appliedPrice]);
                
        double[] trixOut = new double[len + lookback2];
        trix.setOutputParameter(0, trixOut);
        
        trix.calculate(startIndex - lookback2, endIndex);
        
        sump=0; sumn=0; np=0; nn=0;

//======== in aceasta bucla se fac calculele preliminare si statistice 
        for (int i = lookback2, outIndex = 0, j=startIndex; outIndex < len; outIndex++, i++, j++) {
            if (trixOut[i]>=0) {np++; sump=sump+trixOut[i];}
            else {nn++; sumn=sumn+trixOut[i];}
            if(np>0) output[0][outIndex] = sump/np;
            if(nn>0) output[1][outIndex] = sumn/nn;
            output[2][outIndex] = trixOut[i];
        }
//========        

        return new IndicatorResult(startIndex, len);
    }

    public void onStart(IIndicatorContext context) {
        
        this.console = context.getConsole();
        
        int[] priceValues = {OPEN, CLOSE, HIGH, LOW, VOLUME};
        String[] priceNames = {"Open", "Close", "High", "Low", "Volume"};

        inputParameterInfos = new InputParameterInfo[] {

                new InputParameterInfo("price", InputParameterInfo.Type.PRICE)

        };

        optInputParameterInfos = new OptInputParameterInfo[] {
                new OptInputParameterInfo("Applied price", 
                                          OptInputParameterInfo.Type.OTHER, 
                                          new IntegerListDescription(AppliedPrice.CLOSE.ordinal(), priceValues, priceNames)),
               new OptInputParameterInfo("TRIX period",
                                         OptInputParameterInfo.Type.OTHER,
                                         new IntegerRangeDescription(9, 2, 1000, 1)),                                         
        };

        outputParameterInfos = new OutputParameterInfo[] {
                new OutputParameterInfo("",
                                        OutputParameterInfo.Type.DOUBLE,
                                        OutputParameterInfo.DrawingStyle.LINE) {
                    {
                        this.setColor(Color.BLACK);
                    }
                },
                new OutputParameterInfo("",
                                        OutputParameterInfo.Type.DOUBLE,
                                        OutputParameterInfo.DrawingStyle.LINE) {
                    {
                        this.setColor(Color.BLACK);
                    }
                },
                new OutputParameterInfo("",
                                        OutputParameterInfo.Type.DOUBLE,
                                        OutputParameterInfo.DrawingStyle.LINE) {
                    {
                        this.setColor(Color.BLACK);
                    }
                }                
               };

        output = new double[outputParameterInfos.length][];
        inPrice = new double[inputParameterInfos.length][];
        
        trix= context.getIndicatorsProvider().getIndicator("TRIX");
                
        indicatorInfo = new IndicatorInfo("THA3b", "TRIXHA3b colored", "My indicators", false, false, false, inputParameterInfos.length, optInputParameterInfos.length, outputParameterInfos.length);
        indicatorInfo.setRecalculateAll(true);
    }

    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }

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

    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) {
        if (array instanceof double[][]) {
            inPrice = (double[][]) array;
        }
    }

    public void setOptInputParameter(int index, Object value) {
        switch (index) {
            case 0:
                appliedPrice = (Integer) value;
                break;
            case 1:
                TRIXper = (Integer) value;                
                break;                
        }
    }

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

    // ________________________________
    // Support: Some helper methods for printing

    private void print(Object... o) {
        for (Object ob : o) {
            console.getOut().print(ob + "  ");
        }
        console.getOut().println();
    }

    private void print(Object o) {
        console.getOut().println(o);
    }

    private void print(double[] arr) {
        print(arrayToString(arr));
    }

    private void print(double[][] arr) {
        print(arrayToString(arr));
    }

    private void printIndicatorInfos(IIndicator ind) {
        for (int i = 0; i < ind.getIndicatorInfo().getNumberOfInputs(); i++) {
            print(ind.getIndicatorInfo().getName() + " Input " + ind.getInputParameterInfo(i).getName() + " " + ind.getInputParameterInfo(i).getType());
        }
        for (int i = 0; i < ind.getIndicatorInfo().getNumberOfOptionalInputs(); i++) {
            print(ind.getIndicatorInfo().getName() + " Opt Input " + ind.getOptInputParameterInfo(i).getName() + " " + ind.getOptInputParameterInfo(i).getType());
        }
        for (int i = 0; i < ind.getIndicatorInfo().getNumberOfOutputs(); i++) {
            print(ind.getIndicatorInfo().getName() + " Output " + ind.getOutputParameterInfo(i).getName() + " " + ind.getOutputParameterInfo(i).getType());
        }
    }

    public static String arrayToString(double[] arr) {
        String str = "";
        for (int r = 0; r < arr.length; r++) {
            str += "[" + r + "] " + (new DecimalFormat("#.#######")).format(arr[r]) + "; ";
        }
        return str;
    }

    public static String arrayToString(double[][] arr) {
        String str = "";
        if (arr == null)
            return "null";
        for (int r = 0; r < arr.length; r++) {
            for (int c = 0; c < arr[r].length; c++) {
                str += "[" + r + "][" + c + "] " + (new DecimalFormat("#.#######")).format(arr[r][c]);
            }
            str += "; ";
        }
        return str;
    }

    public String toDecimalToStr(double d) {
        return (new DecimalFormat("#.#######")).format(d);
    }

    public String dateToStr(long time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") {
            {
                setTimeZone(TimeZone.getTimeZone("GMT"));
            }
        };
        return sdf.format(time);
    }

    // ________________________________

}