package jforex.indicators;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

import com.dukascopy.api.IBar;
import com.dukascopy.api.ITick;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.IConsole;
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.IMinMax;
import com.dukascopy.api.indicators.IndicatorInfo;
import com.dukascopy.api.indicators.IndicatorResult;
import com.dukascopy.api.indicators.InputParameterInfo;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;
import com.dukascopy.api.indicators.DoubleRangeDescription;
import com.dukascopy.api.indicators.IntegerRangeDescription;
 
public class SAR1 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 IIndicator sarIndicator;
    private double[] sar_custom;
        
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
     
    private double[][] inputs;
    private double[][] outputs = new double[1][];  
    
    private IConsole console;
     
    public void onStart(IIndicatorContext context) 
    {
        this.console = context.getConsole();
        sarIndicator = context.getIndicatorsProvider().getIndicator("SAR"); 
        
        // set the parameters of SAR, needed for calculating lookback       
        sarIndicator.setOptInputParameter(0, 0.0003);
        sarIndicator.setOptInputParameter(1, 0.2);
        
        indicatorInfo = new IndicatorInfo("SAR1", "SAR1", "Custom", true, false, true, 1, 0, 1);
        
        // changed to InputParameterInfo.Type.PRICE, since SAR requires PRICE input, not DOUBLE
        inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.PRICE)};
        
        outputParameterInfos = new OutputParameterInfo[] {
                new OutputParameterInfo("SAR1", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),                
        };
    }
 
    public IndicatorResult calculate(int startIndex, int endIndex) 
    {
        // setting startIndex to take into account the lookback of SAR
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        if (startIndex > endIndex) {
            return new IndicatorResult(0, 0);
        }
        int len = endIndex - startIndex + 1;
        
        sarIndicator.setInputParameter(0, inputs);        
        sar_custom = new double[len];
        sarIndicator.setOutputParameter(0, sar_custom);
        sarIndicator.calculate(startIndex, endIndex);
         
        for (int i = 0; i < len; i++) {
            outputs[0][i] = sar_custom[i];
        }
        
        return new IndicatorResult(startIndex, len);
    }
 
 
    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }
 
    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }
 
    // need to set lookback
    public int getLookback() {
        return sarIndicator.getLookback(); 
    }
 
    public int getLookforward() {
        return 0;
    }
     
    public OutputParameterInfo getOutputParameterInfo(int index) {
        if (index <= outputParameterInfos.length) {
            return outputParameterInfos[index];
        }
        return null;
    }
 
    public void setInputParameter(int index, Object array) {
        inputs = (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) {              
         default:
             throw new ArrayIndexOutOfBoundsException(index);
        }
    }
 
    public void setOutputParameter(int index, Object array) {
        outputs[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);
    }

    // ________________________________
}