package jforex.indicators;

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

import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.Period;
import com.dukascopy.api.indicators.*;
 
public class SMADailySingle5 implements IIndicator {
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private IBar[] chartBars, dailyBars;
    private double[][] outputs = new double[1][];
    private IIndicatorContext context;
    private IIndicator sma;
    
    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") 
        {{setTimeZone(TimeZone.getTimeZone("GMT"));}};
    public static DecimalFormat df = new DecimalFormat("0.00000");
    
    private IConsole console;
    private int lookback = 14;
     
    public void onStart(IIndicatorContext context) {            

        indicatorInfo = new IndicatorInfo("smaDailySingle5", "SMA Daily 5", "My indicators", true, false, true, 2, 1, 1);
 
        inputParameterInfos = new InputParameterInfo[] {
                new InputParameterInfo("Daily bars", InputParameterInfo.Type.BAR){{
                    this.setPeriod(Period.DAILY);
                }},
                new InputParameterInfo("Chart bars", InputParameterInfo.Type.BAR)
        };
 
        optInputParameterInfos = new OptInputParameterInfo[] {
                new OptInputParameterInfo("Time Period", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(14, 2, 100, 1))};
 
        outputParameterInfos = new OutputParameterInfo[] { 
                new OutputParameterInfo("Sma daily", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE)};

        
        IIndicatorsProvider indicatorsProvider = context.getIndicatorsProvider();
        sma = indicatorsProvider.getIndicator("SMA");
        this.console = context.getConsole();
 
    }
 
    public IndicatorResult calculate(int startIndex, int endIndex) {     

        if (startIndex > endIndex || dailyBars == null || chartBars == null || dailyBars.length - lookback + 1 < 0) {    
            return new IndicatorResult(0, 0);
        }               
       
        double [] smaInputs = new double[dailyBars.length];     
        for(int i = 0; i < smaInputs.length; i++){
            //Typical price
            smaInputs[i] = (dailyBars[i].getHigh() + dailyBars[i].getLow() + dailyBars[i].getClose()) / 3d;
        }
        
        double [] dailySmaOutput = new double [smaInputs.length - lookback + 1];        
        
        sma.setInputParameter(0, smaInputs);
        sma.setOutputParameter(0, dailySmaOutput);  
        sma.calculate(0, smaInputs.length - 1);
        
        for(int i = dailyBars.length - 1; i >=0; i--){
            IBar dailyBar = dailyBars[i];
            for(int j = chartBars.length - 1; j >=0; j--){
                IBar chartBar = chartBars[j];              
                if(chartBar.getTime() >= dailyBar.getTime() && chartBar.getTime() < dailyBar.getTime() + Period.DAILY.getInterval()){
                    //index from end
                    int outputPosDaily = dailySmaOutput.length - dailyBars.length + i;
                    int outputPosChart = outputs[0].length - chartBars.length + j;
                    if(outputPosDaily >= 0 && outputPosChart >= 0){
                        outputs[0][outputPosChart] = dailySmaOutput[outputPosDaily];
                    }
                }
            }
        }
        
        IndicatorResult result = new IndicatorResult(lookback, outputs[0].length);
        return result;
    }

 
    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }
 
    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }
 
    public int getLookback() { 
        return lookback ;
    }
 
 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) {
        if(index == 0){
            dailyBars = (IBar[]) array;
        } else {
            chartBars = (IBar[]) array;
        }
    }
 
    public void setOptInputParameter(int index, Object value) {
        lookback = (Integer) value;
        if (index == 0) {
            sma.setOptInputParameter(0, value);
        }
    }
 
    public void setOutputParameter(int index, Object array) {
        outputs[index] = (double[]) array;
    }
    
    
    //________________________________
    //Support: Some helper methods for printing
    private void print(Object o){
        //System.out.println(o);
        console.getOut().println(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 arrayToString(double [] arr){
        return arrayToString(arr, 0);
     }
    
    public static String arrayToString(double [] arr, int minIndex){
        String str = "";
        minIndex = arr.length > minIndex ? minIndex : arr.length - 1;
        for (int r=minIndex; r<arr.length; r++) {
            str += "[" + r + "] "+ df.format(arr[r]) + "; ";
        }
        return str;
     }
    
    public static String arrayToTimeString(IBar [] arr, int minIndex){
        String str = "";
        minIndex = arr.length > minIndex ? minIndex : arr.length - 1;
        for (int r=minIndex; r<arr.length; r++) {
            str += "[" + r + "] "+ sdf.format(arr[r].getTime()) + "; ";
        }
        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 + "] " + df.format(arr[r][c]);
            }
            str += "; ";
        }
        return str;
    }
    //________________________________
}
