package indicator;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Stroke;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import com.dukascopy.api.DataType;
import com.dukascopy.api.IBar;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;
import com.dukascopy.api.feed.IFeedDescriptor;
import com.dukascopy.api.indicators.BooleanOptInputDescription;
import com.dukascopy.api.indicators.ColorListDescription;
import com.dukascopy.api.indicators.DoubleRangeDescription;
import com.dukascopy.api.indicators.IDrawingIndicator;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.indicators.IIndicatorContext;
import com.dukascopy.api.indicators.IIndicatorDrawingSupport;
import com.dukascopy.api.indicators.IndicatorInfo;
import com.dukascopy.api.indicators.IndicatorResult;
import com.dukascopy.api.indicators.InputParameterInfo;
import com.dukascopy.api.indicators.IntegerRangeDescription;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;
import com.dukascopy.api.indicators.PeriodListDescription;
import com.dukascopy.api.indicators.StringOptInputDescription;

/*
 * Copyright (C) GeniuZ http://www.jforexrobot.cz/
 * version 1.0
 * 11.9.2013
 */

public class InputsTest implements IIndicator, IDrawingIndicator
{
    final static private String description = "InputsTest, version 1.0, by GeniuZ (C) 2013 http://www.jforexrobot.cz/";
    static private boolean bDescription = false;
    private IIndicatorContext context;
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private Object[][] outputs;
    Instrument instrument;

    private IBar[] inBar;
    long msShift = 0;
    double tickSize = 1;
    Period periodSource = Period.ONE_MIN;
    Period periodVisual = Period.FOUR_HOURS;
    boolean bShowVolume = true;
    boolean bShowSundays = false;
    Color backgroundColor = Color.white;
    int backgroundTransparency = 65;
    Color valueAreaBgColor = Color.yellow;
    int valueAreaBgTransparency = 80;
    Color volumeColor = Color.gray;
    int histogramWidthRatio = 100;
    int volumeWidthRatio = 100;
    long msInitialBalance = hhmmss2milliseconds("1:00");
    double initialBalanceMultiple = 2.0;

    final static Color[] colorValues = new Color[] {Color.black,Color.white,Color.gray,Color.lightGray,Color.yellow};
    String[] colorNames;

    String title_dayShift = "Day shift";
    String title_periodSource = "Source period";
    String title_periodVisual = "VIsual period";
    String title_showVolume = "Show volume";
    String title_showSundays = "Show sundays";
    String title_backgroundColor = "Background color";
    String title_backgroundTransparency = "Background transparency";
    String title_valueAreaBgColor = "Value Area background color";
    String title_valueAreaBgTransparency = "Value Area transparency";
    String title_volumeColor = "Volume color";
    String title_histogramWidthRatio = "Histogram width ratio";
    String title_volumeWidthRatio = "Volume width ratio";
    String title_initialBalanceDuration = "Initial balance duration";
    String title_initialBalanceMultiple = "Initial balance multiple";

    @Override
    public void onStart(IIndicatorContext context)
    {
        this.context = context;

        colorNames = new String[colorValues.length];
        for( int i=0; i<colorValues.length; i++)
        	colorNames[i] = colorValues[i].toString();

        if( !bDescription )
        {
        	bDescription = true;
        	context.getConsole().getOut().println(description);
        }

        inputParameterInfos = new InputParameterInfo[]{
                new InputParameterInfo("price", InputParameterInfo.Type.BAR)
            };


        optInputParameterInfos = new OptInputParameterInfo[]{
				new OptInputParameterInfo(title_dayShift,   OptInputParameterInfo.Type.OTHER,   new StringOptInputDescription("0:00")),
				new OptInputParameterInfo(title_periodSource,   OptInputParameterInfo.Type.OTHER,   new PeriodListDescription(Period.ONE_MIN,new Period[] {Period.TEN_SECS,Period.ONE_MIN,Period.FIVE_MINS})),
				new OptInputParameterInfo(title_periodVisual,   OptInputParameterInfo.Type.OTHER,   new PeriodListDescription(Period.DAILY,new Period[] {Period.TEN_MINS,Period.FIFTEEN_MINS,Period.ONE_HOUR,Period.FOUR_HOURS,Period.DAILY,Period.WEEKLY,Period.MONTHLY})),
				new OptInputParameterInfo(title_initialBalanceDuration,   OptInputParameterInfo.Type.OTHER,   new StringOptInputDescription("1:00")),
				new OptInputParameterInfo(title_initialBalanceMultiple,   OptInputParameterInfo.Type.OTHER,   new DoubleRangeDescription(initialBalanceMultiple,0,100,1,1)),
				new OptInputParameterInfo(title_showVolume,   OptInputParameterInfo.Type.OTHER,   new BooleanOptInputDescription(bShowVolume)),
				new OptInputParameterInfo(title_showSundays,   OptInputParameterInfo.Type.OTHER,   new BooleanOptInputDescription(bShowSundays)),
				new OptInputParameterInfo(title_backgroundColor,   OptInputParameterInfo.Type.OTHER,   new ColorListDescription(backgroundColor,colorValues,colorNames)),
				new OptInputParameterInfo(title_backgroundTransparency,   OptInputParameterInfo.Type.OTHER,   new IntegerRangeDescription(backgroundTransparency,0,100,5)),
				new OptInputParameterInfo(title_valueAreaBgColor,   OptInputParameterInfo.Type.OTHER,   new ColorListDescription(valueAreaBgColor,colorValues,colorNames)),
				new OptInputParameterInfo(title_valueAreaBgTransparency,   OptInputParameterInfo.Type.OTHER,   new IntegerRangeDescription(valueAreaBgTransparency,0,100,5)),
				new OptInputParameterInfo(title_volumeColor,   OptInputParameterInfo.Type.OTHER,   new ColorListDescription(volumeColor,colorValues,colorNames)),
				new OptInputParameterInfo(title_histogramWidthRatio,   OptInputParameterInfo.Type.OTHER,   new IntegerRangeDescription(histogramWidthRatio,0,100,10)),
				new OptInputParameterInfo(title_volumeWidthRatio,   OptInputParameterInfo.Type.OTHER,   new IntegerRangeDescription(volumeWidthRatio,0,100,10)),
        };

        outputParameterInfos = new OutputParameterInfo[]{
                new OutputParameterInfo("InputsTest", OutputParameterInfo.Type.OBJECT, OutputParameterInfo.DrawingStyle.LINE)
        };

        outputParameterInfos[0].setDrawnByIndicator(true);

        indicatorInfo = new IndicatorInfo("InputsTest", "InputsTest Indicator", "CUSTOM", true, false, true, inputParameterInfos.length, optInputParameterInfos.length, outputParameterInfos.length);
        indicatorInfo.setRecalculateAll(true);
        indicatorInfo.setSupportedDataTypes(DataType.TIME_PERIOD_AGGREGATION);

        outputs = new Object[outputParameterInfos.length][];

        IFeedDescriptor fd = context.getFeedDescriptor();
        if( fd != null )
            instrument = fd.getInstrument();

    }

    @Override
    public int getLookback()
    {
        return 0;
    }

    @Override
    public int getLookforward()
    {
        return 0;
    }

    @Override
    public IndicatorResult calculate(int startIndex, int endIndex)
    {
        if (startIndex - getLookback() < 0)
        {
            startIndex -= startIndex - getLookback();
        }

        instrument = context.getFeedDescriptor().getInstrument();

        int i,j;

        ITick lastTick = null;
        try { lastTick = context.getHistory().getLastTick(instrument); }
        catch( JFException e ) { e.printStackTrace(context.getConsole().getErr()); }

        double ask = lastTick.getAsk();
        double bid = lastTick.getBid();
        double spread = (ask - bid) / instrument.getPipValue();
           spread = Math.round(10*spread)/10.0;

        for(i = startIndex, j=0; i <= endIndex; i++, j++)
        {
            if( i < endIndex )
                outputs[0][j] = new Long(0);
            else
                outputs[0][j] = new Long(lastTick.getTime());
        }

        return new IndicatorResult(startIndex, j);
    }

    @Override
    public IndicatorInfo getIndicatorInfo()
    {
        return indicatorInfo;
    }

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

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

    @Override
    public OutputParameterInfo getOutputParameterInfo(int index)
    {
        if (index <= outputParameterInfos.length)
        {
            return outputParameterInfos[index];
        }
        return null;
    }

    @Override
    public void setInputParameter(int index, Object array)
    {
        inBar = (IBar[]) array;
    }

    @Override
    public void setOptInputParameter(int index, Object value)
    {
    	context.getConsole().getOut().println("input: " + index);
    	context.getConsole().getOut().println("input: " + optInputParameterInfos[index].getName());

    	String title = optInputParameterInfos[index].getName();

    	if( title.compareTo(title_dayShift) == 0 )
    	{
            msShift = hhmmss2milliseconds( (String) value );
            if( msShift >= 1000*60*60*24 ) msShift = 0;
    	}
        else
       	if( title.compareTo(title_periodSource) == 0 )
            periodSource = (Period) value;
        else
       	if( title.compareTo(title_periodVisual) == 0 )
            periodVisual = (Period) value;
       	else
    	if( title.compareTo(title_initialBalanceDuration) == 0 )
           	msInitialBalance = hhmmss2milliseconds( (String) value );
       	else
    	if( title.compareTo(title_initialBalanceMultiple) == 0 )
    		initialBalanceMultiple = (Double) value;
       	else
    	if( title.compareTo(title_showVolume) == 0 )
           	bShowVolume = (Boolean) value;
       	else
    	if( title.compareTo(title_showSundays) == 0 )
           	bShowSundays = (Boolean) value;
    	else
       	if( title.compareTo(title_backgroundColor) == 0 )
            backgroundColor = (Color) value;
       	else
    	if( title.compareTo(title_backgroundTransparency) == 0 )
            backgroundColor = transparentColor( backgroundColor, (Integer) value );
    	else
       	if( title.compareTo(title_valueAreaBgColor) == 0 )
            valueAreaBgColor = (Color) value;
       	else
    	if( title.compareTo(title_valueAreaBgTransparency) == 0 )
            valueAreaBgColor = transparentColor( valueAreaBgColor, (Integer) value );
    	else
       	if( title.compareTo(title_volumeColor) == 0 )
            volumeColor = (Color) value;
    	else
       	if( title.compareTo(title_histogramWidthRatio) == 0 )
            histogramWidthRatio = (Integer) value;
    	else
       	if( title.compareTo(title_volumeWidthRatio) == 0 )
            volumeWidthRatio = (Integer) value;
    }

    Color transparentColor(Color color, int transparency)
    {
    	return new Color(color.getRed(),color.getGreen(),color.getBlue(),255 - 255*transparency/100);
    }

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

    @Override
    public Point drawOutput(Graphics _g, int outputIdx, Object output, Color color, Stroke stroke, IIndicatorDrawingSupport ids, List<Shape> shapes, Map<Color, List<Point>> handles)
    {
    	context.getConsole().getOut().println("redraw: " + outputIdx);
        return null;
    }

	public static long hhmmss2milliseconds(String str_hhmmss)
	{
		StringTokenizer tok = new StringTokenizer(str_hhmmss, ":");
		int nTokens = tok.countTokens();
		int hours = 0;
		int minutes = 0;
		int seconds = 0;
		hours = Integer.parseInt(tok.nextToken());
		if( nTokens > 1 ) minutes = Integer.parseInt(tok.nextToken());
		if( nTokens > 2 ) seconds = Integer.parseInt(tok.nextToken());
		return 1000L * (hours * 60 * 60 + minutes * 60 + seconds);
	}
}
