package jforex;

import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.math.BigDecimal;
import java.math.RoundingMode;

import com.dukascopy.api.*;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.Period;
import com.dukascopy.api.feed.*;
import com.dukascopy.api.IIndicators.MaType;
import com.dukascopy.api.IIndicators.AppliedPrice;
import com.dukascopy.api.indicators.IIndicator;

public class BarRetrievalStrategy3 implements IStrategy {
    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private IContext context;
    private IIndicators indicators;
    private IUserInterface userInterface;
    private IRangeBar prevBar;
    private IRangeBar thisBar;
    private SimpleDateFormat sdf;
    
    public void onStart(IContext context) throws JFException {
        this.engine = context.getEngine();
        this.console = context.getConsole();
        this.history = context.getHistory();
        this.context = context;
        this.indicators = context.getIndicators();
        this.userInterface = context.getUserInterface();
        sdf = new SimpleDateFormat("HH:mm:ss.s");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));    
        
        context.subscribeToRangeBarFeed(Instrument.EURUSD, OfferSide.BID, PriceRange.valueOf(5), new IRangeBarFeedListener() {
            public void onBar(Instrument instrument, OfferSide offerSide, PriceRange priceRange, IRangeBar bar) {
                try {
                     List<IRangeBar> rangeBars = history.getRangeBars(instrument, offerSide, priceRange, 36, bar.getTime(), 0);
                    //console.getOut().println(dateToStr(rangeBars.get(35).getTime()) + "; " + rangeBars.get(35).getClose());
                    
                    double[] input = new double[rangeBars.size()];
                    for (int i = 0; i < rangeBars.size(); i++) {
                        input[i] = rangeBars.get(i).getClose();
                    }

                    IIndicator EMA = indicators.getIndicator("EMA");
                    //EMA.setOptInputParameter(1, 12);
                    EMA.setInputParameter(0, input);                    
                    double[] outputEMA = new double[input.length - EMA.getLookback()];
                    EMA.setOutputParameter(0, outputEMA);
                    EMA.calculate(0, input.length - 1);
                    double ema = outputEMA[outputEMA.length - 1];
                    print(dateToStr(rangeBars.get(35).getTime()) + "; " + round(ema, 5));                    
                    
                    IIndicator MACD = indicators.getIndicator("MACD"); 
                    MACD.setInputParameter(0, input);
                    double[][] outputMACD = new double[3][input.length];
                    MACD.setOutputParameter(0, outputMACD[0]);
                    MACD.setOutputParameter(1, outputMACD[1]);
                    MACD.setOutputParameter(2, outputMACD[2]);
                    MACD.calculate(0, input.length - 1);
                    int index = outputMACD[0].length - 1 - MACD.getLookback();
                    double macd1 = outputMACD[0][index];
                    double macd2 = outputMACD[1][index];
                    double macd3 = outputMACD[2][index];
                    print(dateToStr(rangeBars.get(35).getTime()) + "; " + round(macd1, 5) + ", " + round(macd2, 5) + ", " + round(macd3, 5));
                        
                } catch (JFException ex) {
                        ex.printStackTrace(console.getErr());
                }
            }
        });
    }

    public void onAccount(IAccount account) throws JFException {
    }

    public void onMessage(IMessage message) throws JFException {
    }

    public void onStop() throws JFException {
    }

    public void onTick(Instrument instrument, ITick tick) throws JFException {
    }
    
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
    }

    private void print(Object... o) {
        for (Object ob : o) {
            //console.getOut().print(ob + "  ");
            if (ob instanceof double[]) {
                print((double[]) ob);
            } else if (ob instanceof double[]) {
                print((double[][]) ob);
            } else if (ob instanceof Long) {
                print(dateToStr((Long) ob));
            } else if (ob instanceof Double) {
                print((Double) ob);
            } else {
                print2(ob);
            }
            print(" ");
        }

        console.getOut().println();
    }

    private void print(Object o) {
        console.getOut().println(o);
    }

    private void print2(Object o) {
        console.getOut().print(o);
    }

    private void printTime(Long time) {
        console.getOut().println(dateToStr(time));
    }

    private void print(double[] arr) {
        print(arrayToString(arr));
    }

    private void print(double[][] arr) {
        print(arrayToString(arr));
    }

    private void print(double ddd) {
        print((new DecimalFormat("#.#######")).format(ddd));
    }

    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());
        }
        console.getOut().println();
    }

    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);
    }

    public double round(double d, int i) {
        BigDecimal bd = new BigDecimal(d).setScale(i, RoundingMode.HALF_EVEN);
        return bd.doubleValue();
    }    
}