package com.dukascopy;

import java.awt.Color;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.TimeZone;

import com.dukascopy.api.*;
import com.dukascopy.api.indicators.*;

public class TicksInBar implements IIndicator {

    public static final int OPEN = 0;
    public static final int CLOSE = 1;
    public static final int HIGH = 2;
    public static final int LOW = 3;
    public static final int VOLUME = 4;
    private IndicatorInfo indicatorInfo;
    // INPUTS
    private InputParameterInfo[] inputParameterInfos;
    private IBar[] inBar;
    private double[] inPrice;
    // OPT INPUTS
    private OptInputParameterInfo[] optInputParameterInfos;

    // OUTPUTS
    private OutputParameterInfo[] outputParameterInfos;
    private double[] output;
    // CONTEXT
    private IConsole console;
    private IHistory history;
    private IIndicatorContext context;

    private IIndicator ma;

    public int getLookback() {
        return 0;
    }

    public int getLookforward() {
        return 0;
    }

    /*************
     * CALCULATE *
     *************/
    public IndicatorResult calculate(int startIndex, int endIndex) {

        if (startIndex > endIndex) {
            return new IndicatorResult(0, 0);
        }
        int len = endIndex - startIndex + 1;


        Instrument instrument = context.getChartInstruments()[0];
        int outputLength = output.length;


        long timeStart = inBar[0].getTime();
        long lastTickTime = 0;
        List<ITick> ticks;
        try {
            lastTickTime = history.getLastTick(instrument).getTime();
            ticks = history.getTicks(instrument, timeStart, lastTickTime);
        } catch (JFException e) {
            e.printStackTrace();
            return new IndicatorResult(0, 0);
        }

        int j = 0;
        for (int i = 0; i < outputLength; i++) {
            int tickCount = 0;
            long barEndTime;
            if(i + 1 == outputLength) {
                barEndTime = lastTickTime;
            } else {
                barEndTime = inBar[i + 1].getTime();
            }

            while(ticks.get(j).getTime() < barEndTime) {
                tickCount++;
                j++;
            }

            output[i] = tickCount;
        }

        return new IndicatorResult(startIndex, len);
    }

    /***********
     *  START  *
     ***********/
    public void onStart(IIndicatorContext context) {
        this.console = context.getConsole();
        this.history = context.getHistory();
        this.context = context;


        int[] mode = {0, 1, 2};
        String[] modeNames = {"Duration", "Volume", "Moving Average"};

        int[] maTypeValues = new int[IIndicators.MaType.values().length];
        String[] maTypeNames = new String[IIndicators.MaType.values().length];
        for (int i = 0; i < maTypeValues.length; i++) {
            maTypeValues[i] = i;
            maTypeNames[i] = IIndicators.MaType.values()[i].name();
        }

        inputParameterInfos = new InputParameterInfo[]{
                new InputParameterInfo("Bar", InputParameterInfo.Type.BAR),
        };

        optInputParameterInfos = new OptInputParameterInfo[]{
        };

        outputParameterInfos = new OutputParameterInfo[]{
                new OutputParameterInfo("Main",
                                        OutputParameterInfo.Type.DOUBLE,
                                        OutputParameterInfo.DrawingStyle.HISTOGRAM) {
                    {
                        this.setColor(Color.GREEN);
                    }
                },
        };

        indicatorInfo = new IndicatorInfo("BAR_PERIOD", "Asymmetric Stochastic", "My indicators", false, false, false, inputParameterInfos.length, optInputParameterInfos.length, outputParameterInfos.length);

        ma = context.getIndicatorsProvider().getIndicator("MA");
    }

    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) {
        switch (index) {
            case 0:
                inBar = (IBar[]) array;
                break;
        }


    }

    public void setOptInputParameter(int index, Object value) {

    }

    public void setOutputParameter(int index, Object array) {
        output = (double[]) array;
    }

    // ________________________________
    // Support: Some helper methods for printing
    private void print(Object... o) {
        for (Object ob : o) {
            //console.getOut().print(ob + "  ");
            if (ob instanceof double[]) {
                print((double[]) ob);
            } else if (ob instanceof double[]) {
                print((double[][]) ob);
            } else if (Long.class.isInstance(ob)) {
                print2(toStr((Long) ob));
            } else if (ob instanceof IBar) {
                print((IBar) ob);
            } else {
                print2(ob);
            }
            print2(" ");
        }
        console.getOut().println();
    }

    private void print(Object o) {
        console.getOut().println(o);
    }

    private void print2(Object o) {
        console.getOut().print(o);
    }

    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 toStr(double[] arr) {
        String str = "";
        for (int r = 0; r < arr.length; r++) {
            str += "[" + r + "] " + (new DecimalFormat("#.#######")).format(arr[r]) + "; ";
        }
        return str;
    }

    public static String toStr(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 toStr(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);
    }
    // ________________________________
}