package jforex;

import com.dukascopy.api.IIndicators;
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.IntegerListDescription;
import com.dukascopy.api.indicators.IIndicatorsProvider;

import java.awt.*;
import java.util.Map;
import java.awt.geom.GeneralPath;

/**
 * Created by: chriz aka Indiana Pips
 * Date: March 08, 2011
 * email: puntasabbioni/AT/gmail.com 
 */


public class AllAveragesInColors implements IIndicator , IDrawingIndicator {

    
    private IIndicator MaIndi;
    private int TimePeriod = 120;
    private int TickNess = 2 ;
    private Color upTrendColor = GREEN ;
    private Color downTrendColor = RED ;
        
    public static final Color GREEN = new Color(0x00, 0x80, 0x00);
    public static final Color RED = new Color(0xc0, 0x00, 0x00);
    public static final Color LIGHT_GREEN = new Color(0x80, 0xFF, 0x80);
    public static final Color LIGHT_RED  = new Color(0xFF, 0x80, 0x80);
    public static final Color VERY_DARK_YELLOW = new Color(0x80, 0x80, 0x00);
    public static final Color DARK_RED = new Color(0xc0, 0x00, 0x00);
    public static final Color VERY_DARK_RED = new Color(0x80, 0x00, 0x00);
    public static final Color VERY_DARK_GREEN = new Color(0x00, 0x80, 0x00);
    public static final Color DARK_GREEN = new Color(0x00, 0xC0, 0x00);

    private final GeneralPath generalPath = new GeneralPath();
                
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private double[][] inputs = new double[2][];
    private double[][] outputs = new double[1][];
    private Object[][] output = new Object[1][];

    private IIndicatorContext context ;

    private InputParameterInfo inputParam1 ;

    public void onStart(IIndicatorContext context) {
        this.context = context ;
        
        IIndicatorsProvider indicatorsProvider = context.getIndicatorsProvider();
        MaIndi = indicatorsProvider.getIndicator("MA");
        
        indicatorInfo = new IndicatorInfo("AllAveragesInColor", "All avg in colors", "Overlap Studies", true, false, true, 1, 5, 2);
        
        inputParam1 = new InputParameterInfo("MA Applied Price", InputParameterInfo.Type.DOUBLE);
        inputParam1.setAppliedPrice(IIndicators.AppliedPrice.CLOSE);
        
        inputParameterInfos = new InputParameterInfo[] { inputParam1 };

        int[] maValues = new int[IIndicators.MaType.values().length];
        String[] maNames = new String[IIndicators.MaType.values().length];
        for (int i = 0; i < maValues.length; i++) {
            maValues[i] = i;
            maNames[i] = IIndicators.MaType.values()[i].name();
        }

        int[] availColorsValues = new int[AvailableColors.values().length];
        String[] availColorsNames = new String[AvailableColors.values().length];
        for (int i = 0; i < availColorsValues.length; i++) {
            availColorsValues[i] = i;
            availColorsNames[i] = AvailableColors.values()[i].name();
        }
        
        optInputParameterInfos = new OptInputParameterInfo[] {
            new OptInputParameterInfo("MA Time Period", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(120, 2, 2000, 1)),
            new OptInputParameterInfo("MA Type", OptInputParameterInfo.Type.OTHER, new IntegerListDescription(IIndicators.MaType.EMA.ordinal(), maValues, maNames)),
            new OptInputParameterInfo("Line TickNess", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(2, 1, 50, 1)),
            new OptInputParameterInfo("UpTrend Color", OptInputParameterInfo.Type.OTHER, new IntegerListDescription(AvailableColors.GREEN.ordinal(), availColorsValues, availColorsNames)),
            new OptInputParameterInfo("DownTrend Color", OptInputParameterInfo.Type.OTHER, new IntegerListDescription(AvailableColors.RED.ordinal(), availColorsValues, availColorsNames))            
        };
        
        outputParameterInfos = new OutputParameterInfo[] {
            new OutputParameterInfo("MA", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE) {{
                setColor(Color.BLUE);
            }},
            new OutputParameterInfo("MA line", OutputParameterInfo.Type.OBJECT, OutputParameterInfo.DrawingStyle.LINE) {{
                setDrawnByIndicator(true);
            }}            
        };
    }

    public IndicatorResult calculate(int startIndex, int endIndex) {

        //calculating startIndex taking into account lookback value
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        
        if (startIndex > endIndex) {
            return new IndicatorResult(0, 0);
        }        
                
        double[] MAOut = new double[endIndex - startIndex + 1 + getLookback()];

        // calculation on selected applied price
        MaIndi.setInputParameter(0, inputs[0]);
        MaIndi.setOutputParameter(0, MAOut);

        IndicatorResult MaIndiResult = MaIndi.calculate(startIndex , endIndex);

        int i, k;
        for (i = 0, k = MaIndiResult.getNumberOfElements(); i < k; i++) {
            outputs[0][i] = MAOut[i] ;
            
            double[] toDraw = new double[1];
            toDraw[0] = MAOut[i] ;
            // for drawing
            output[0][i] = toDraw;
        }

        return new IndicatorResult(startIndex, i );
    }

    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }

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

    public int getLookback() {
        int MaLookBack = MaIndi.getLookback();
        return MaLookBack ;
    }

    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 OptInputParameterInfo getOptInputParameterInfo(int index) {
        if (index <= optInputParameterInfos.length) {
            return optInputParameterInfos[index];
        }
        return null;
    }

    public void setOptInputParameter(int index, Object value) {
        switch (index) {
            case 0:
                TimePeriod = (Integer) value;
                MaIndi.setOptInputParameter(0, TimePeriod);
                break;
            case 1:
                int maType = (Integer) value;
                MaIndi.setOptInputParameter(1,IIndicators.MaType.values()[maType].ordinal()); 
                break;                                              
            case 2:
                TickNess = (Integer) value;
                break;                                                       
            case 3:
                int selUpColor = (Integer) value;
                upTrendColor = AvailableColors.values()[selUpColor].getColor();
                break;                 
            case 4:
                int selDownColor = (Integer) value;
                downTrendColor = AvailableColors.values()[selDownColor].getColor();
                break;                 
            default:
                throw new ArrayIndexOutOfBoundsException(index);
        }
    }

    public void setOutputParameter(int index, Object array) {
        if(index<1)
        {
            outputs[index] = (double[]) array;
        }else
        {
            output[0] = (Object[]) array;
        }
    }

    public int getLookforward() {
        return 0;
    }

    public Point drawOutput(Graphics g, int outputIdx, Object values2, Color color, Stroke stroke,
                           IIndicatorDrawingSupport indicatorDrawingSupport, java.util.List<Shape> shapes,
                           Map<Color, java.util.List<Point>> handles) {
        Object[] values = (Object[]) values2;
        Graphics2D g2 = (Graphics2D) g;
        g2.setStroke(new BasicStroke(TickNess));
               
        if (values2 != null) {
            for (int j = indicatorDrawingSupport.getIndexOfFirstCandleOnScreen(), k =
                    j + indicatorDrawingSupport.getNumberOfCandlesOnScreen() ; j < k; j++) {
                if (j > 0) {
                                                                                    
                    if (values[j] != null) {
                        
                        double[] pointPrev = (double[]) values[j - 1];
                        double[] point = (double[]) values[j];
                                            
                        int barMiddle = (int) indicatorDrawingSupport.getMiddleOfCandle(j);
                        int barMiddlePrev = (int) indicatorDrawingSupport.getMiddleOfCandle(j - 1);
                        
                        if (point[0] > pointPrev[0]) {
                            //g.setColor(upTrendColor);
                            g2.setColor(upTrendColor);
                        } else if (point[0] < pointPrev[0]) {
                            //g.setColor(downTrendColor);
                            g2.setColor(downTrendColor);
                        } else if (point[0] == pointPrev[0])
                        {
                            //g.setColor(VERY_DARK_YELLOW);
                            g2.setColor(VERY_DARK_YELLOW);
                        }
                        
                        int[] xPoints = new int[2];
                        int[] yPoints = new int[2];
                        
                        generalPath.reset();
                        
                        if (pointPrev[0] != 0 && (!Double.isNaN(pointPrev[0]))  && point[0] != 0 && (!Double.isNaN(point[0]) ) ) 
                        {
                            yPoints[0] = (int) indicatorDrawingSupport.getYForValue(pointPrev[0]);
                            yPoints[1] = (int) indicatorDrawingSupport.getYForValue(point[0]);

                            xPoints[0] = barMiddlePrev;
                            xPoints[1] = barMiddle;
                            
                            generalPath.moveTo(xPoints[0], yPoints[0]);    
                            generalPath.lineTo(xPoints[1], yPoints[1]);
                            
                            //g.drawLine(xPoints[0] , yPoints[0] , xPoints[1], yPoints[1]) ;
                            //drawThickLine(g,xPoints[0] , yPoints[0] , xPoints[1], yPoints[1], TickNess);                            
                            g2.draw(generalPath);
                        }
                        
                        int fontSize = 9;
                        g2.setFont(new Font(g2.getFont().getName(), g2.getFont().getStyle(), fontSize));
                        g2.setColor(Color.BLACK);
                        //g2.setStroke(new BasicStroke(1));
                        String text = "AllAveragesInColor © by chriz [Indiana Pips]" ;
                        g2.drawString(text, 10  ,  indicatorDrawingSupport.getChartHeight() - 10);
                                                
                    }
                }
            }           
                                    
            
        }
        
        return null;
    }
    
	public void drawThickLine(
		Graphics g, int x1, int y1, int x2, int y2, int thickness) {
		// The thick line is in fact a filled polygon
		int dX = x2 - x1;
		int dY = y2 - y1;
		// line length
		double lineLength = Math.sqrt(dX * dX + dY * dY);
		
		double scale = (double)(thickness) / (2 * lineLength);
		
		// The x,y increments from an endpoint needed to create a rectangle...
		double ddx = -scale * (double)dY;
		double ddy = scale * (double)dX;
		ddx += (ddx > 0) ? 0.5 : -0.5;
		ddy += (ddy > 0) ? 0.5 : -0.5;
		int dx = (int)ddx;
		int dy = (int)ddy;
		
		// Now we can compute the corner points...
		int xPoints[] = new int[4];
		int yPoints[] = new int[4];
		
		xPoints[0] = x1 + dx; yPoints[0] = y1 + dy;
		xPoints[1] = x1 - dx; yPoints[1] = y1 - dy;
		xPoints[2] = x2 - dx; yPoints[2] = y2 - dy;
		xPoints[3] = x2 + dx; yPoints[3] = y2 + dy;
		
		g.fillPolygon(xPoints, yPoints, 4);
	}

    private void print(String sss)
    {
        context.getConsole().getOut().println(sss) ;
    }

	private static enum AvailableColors {
		GREEN(Color.GREEN), 
		RED (Color.RED), 
		LIGHT_GREEN(new Color(0x80, 0xFF, 0x80)), 
		LIGHT_RED(new Color(0xFF, 0x80, 0x80)), 
		VERY_DARK_YELLOW(new Color(0x80, 0x80, 0x00)),
		DARK_RED ( new Color(0xc0, 0x00, 0x00)),
		VERY_DARK_RED (new Color(0x80, 0x00, 0x00)),
		VERY_DARK_GREEN (new Color(0x00, 0x80, 0x00)),
		DARK_GREEN (new Color(0x00, 0xC0, 0x00)),
		BLACK ( Color.BLACK ),
        BLUE ( Color.BLUE  ),
        CYAN ( Color.CYAN ),
        DARK_GRAY  ( Color.DARK_GRAY ),
        GRAY ( Color.GRAY ),
        LIGHT_GRAY ( Color.LIGHT_GRAY ),
        MAGENTA ( Color.MAGENTA ),
        ORANGE ( Color.ORANGE ),
        PINK ( Color.PINK),
        WHITE ( Color.WHITE ),
        YELLOW ( Color.YELLOW );
        
		Color theColor ;
		
		private AvailableColors(Color c) {
		    theColor = c;
		}
		
		private Color getColor() {
		    return theColor;
		}
	 }
	                                               
}


 