package jforex.strategies.indicators;

import java.util.*;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import com.dukascopy.api.indicators.IIndicator;

import com.dukascopy.api.*;
import com.dukascopy.api.drawings.*;
import java.awt.Color;

public class Volumes implements IStrategy {
    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private IContext context;
    private IIndicators indicators;
    private IUserInterface userInterface;
    @Configurable("Instrument")
    public Instrument instrument = Instrument.EURUSD;
    private IChart chart;
    
    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();
        this.chart = context.getChart(instrument);
    }

    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 {
        if(!instrument.equals(this.instrument)){
            return;
        }
        
        double[] askVolumes = tick.getAskVolumes();
        double[] asks = tick.getAsks();
        double totalVolume = 0;
        double y = tick.getAsk();
        
        double yShift;
        long labelShift;
        long widthFull;
        
        if(chart.getSelectedPeriod().equals(Period.TICK)) {            
            yShift = instrument.getPipValue() / 4;
                      
            widthFull = 10000L;            
            labelShift = 1000L;
            
        } else {
            double max = indicators.max(instrument, chart.getSelectedPeriod(), chart.getSelectedOfferSide(), IIndicators.AppliedPrice.HIGH, chart.getBarsCount(), 0);
            double min = indicators.min(instrument, chart.getSelectedPeriod(), chart.getSelectedOfferSide(), IIndicators.AppliedPrice.LOW, chart.getBarsCount(), 0);
            double hight = max - min;
            yShift = hight / 2 / asks.length;
                     
            widthFull = chart.getSelectedPeriod().getInterval() * chart.getBarsCount() /2;            
            labelShift = Math.round(widthFull / 10);
        }
        
        for(int i = 0; i < asks.length; i++) {
            totalVolume += askVolumes[i];
        }
        for(int i = 0; i < asks.length; i++) {
            y += yShift;
            long width = Math.round(widthFull * askVolumes[i]/totalVolume);
            draw("ask"+i, tick.getTime(), y, width, yShift/2, labelShift, askVolumes[i], Color.GREEN);            
        }
        
        double[] bidVolumes = tick.getBidVolumes();
        double[] bids = tick.getBids();
        totalVolume = 0;
        y = tick.getBid();
        
        for(int i = 0; i < bids.length; i++) {
            totalVolume += bidVolumes[i];
        }
        for(int i = 0; i < bids.length; i++) {
            y -= yShift;
            long width = Math.round(widthFull * bidVolumes[i]/totalVolume);
            draw("bid"+i, tick.getTime(), y, width, -yShift/2, labelShift, bidVolumes[i], /*y-yShift/2,*/ Color.RED);            
        }
    }
    
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
    }
    
    private void draw(String label, long x, double y, long width, double hight, long labelShift, double volume, Color color){
        
        IChartObjectFactory factory = chart.getChartObjectFactory();
        double labelY = y;
        if(hight < 0) {
            labelY = y + hight;
        }
        ILabelChartObject label3 = factory.createLabel("l"+label, x + labelShift/5, labelY);
        
        label3.setText(""+volume);
        label3.setColor(Color.BLACK);
        chart.addToMainChart(label3);
                
        IRectangleChartObject line = factory.createRectangle(label, 
                x + labelShift, y, 
                x + labelShift + width, y + hight);
        line.setColor(color);
        
        chart.addToMainChart(line);
   }
    
    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 {
                print(ob);
            }
            print(" ");
        }
        console.getOut().println();
    }
    
    private void print(Object o) {
        console.getOut().print(o);
    }
    
    private void println(Object o) {
        console.getOut().println(o);
    }

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

    private void print(double[][] arr) {
        println(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());
        }
        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);
    }
}