/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package kornell.jforex.indicator.test;

import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.drawings.IChartObjectFactory;
import com.dukascopy.api.drawings.IScreenLabelChartObject;
import com.dukascopy.api.drawings.IScreenLabelChartObject.Corner;
import com.dukascopy.api.indicators.*;
import java.awt.Color;
import java.awt.Font;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.UUID;

/*
 * https://www.dukascopy.com/wiki/#Indicator_draws_chart_objects
 */
public class AskBidSpreadIndicator implements IIndicator {

    private static final String GUID = UUID.randomUUID().toString();

    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;

    //Indicator input used in calculations
    private double[][] inputs = new double[0][];
    //Default value of optional parameter
    private int timePeriod = 0;
    //Array of indicator output values
    private double[][] outputs = new double[2][];

    private Instrument mainChartInstrument;
    private IIndicatorChartPanel chart;
    private IChartObjectFactory factory;
    private IIndicatorContext context;
    private IScreenLabelChartObject spreadLabel;

    NumberFormat formatter = new DecimalFormat("#0.00");

    public void onStart(IIndicatorContext context) {
        this.context = context;
        // Indicator name is [EXAMPIND], indicator group is [My indicators], indicator is displayed in a subwindow and doesn't have an unstable period, 
        // it has one input, one optional parameter and one output.
        indicatorInfo = new IndicatorInfo("KHELPER", "Ask Bid Spred", "Kornell", true, false, false, 0, 0, 2);
        // Input of type double
//        inputParameterInfos = new InputParameterInfo[] {
//            new InputParameterInfo("Input data #1", InputParameterInfo.Type.DOUBLE),
//            new InputParameterInfo("Input data #2", InputParameterInfo.Type.DOUBLE)
//        };
        //Type: integer, default value: 4, minimum value: 2, maximum value: 100, incremental step: 1. 
//        optInputParameterInfos = new OptInputParameterInfo[]{new OptInputParameterInfo("Time period", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(4, 2, 100, 1))};
        //Output of type double, output is displayed as a line.
        outputParameterInfos = new OutputParameterInfo[]{
            new OutputParameterInfo("askLine", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LEVEL_LINE),
            new OutputParameterInfo("bidLine", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LEVEL_LINE)
        };
        outputParameterInfos[0].setColor(Color.RED);
        outputParameterInfos[1].setColor(Color.BLUE);
    }

    public IndicatorResult calculate(int startIndex, int endIndex) {
        if (mainChartInstrument == null) {
            Instrument[] instruments = context.getChartInstruments();
            for (Instrument instrument : instruments) {
                mainChartInstrument = instrument;
                break;
            }
        }

        double askLevel = 0.0;
        double bidLevel = 0.0;
        try {
            ITick lastTick = context.getHistory().getLastTick(mainChartInstrument);
            askLevel = lastTick.getAsk();
            bidLevel = lastTick.getBid();
        } catch (JFException e) {
            context.getConsole().getOut().println(e.getMessage());
        }
        if (factory == null) {
            chart = context.getIndicatorChartPanel();
            //no chart opened - either indicator called from strategy or indicator
            if (chart == null) {
                return new IndicatorResult(startIndex, endIndex - startIndex + 1);
            }
            factory = chart.getChartObjectFactory();
            if (chart.get(GUID + "screenLabel") == null) {
                spreadLabel = chart.getChartObjectFactory().createScreenLabel(GUID + "screenLabel");
                spreadLabel.setCorner(Corner.BOTTOM_RIGHT);
                spreadLabel.setxDistance(5);
                spreadLabel.setyDistance(5);
                spreadLabel.setColor(Color.RED);
                chart.add(spreadLabel);
            }
        }
        if (spreadLabel != null) {
            spreadLabel.setText("Spread " + formatter.format((askLevel - bidLevel) / mainChartInstrument.getPipValue()), new Font("Verdana", Font.PLAIN, 10));
        }

        //calculating startIndex taking into an account the lookback value
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        int i, j;
        for (i = startIndex, j = 0; i <= endIndex; i++, j++) {
            outputs[0][j] = askLevel;
            outputs[1][j] = bidLevel;
        }

        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() {
        //calculate indicator lookBack
        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;
    }
}
