package jforex.test;

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

import com.dukascopy.api.*;

/**
 * The strategy demonstrates how one can handle himself custom periods,
 * if platform functionality is not available (e.g. for JForex API 2.6.33)
 *
 */

public class CustomPeriodRangeBar implements IStrategy {

    @Configurable("Instrument")
    public Instrument instrument = Instrument.EURUSD;
    @Configurable("Range in PIPs")
    public double Range = 20;
    @Configurable("Offer Side")
    public OfferSide side = OfferSide.BID;
    
    IHistory history;
    IConsole console;
    
    CustomBar customBar;
    ITick prevTick;
    long periodInMillis;
    
    
    @Override
    public void onStart(IContext context) throws JFException {

        history = context.getHistory();
        console = context.getConsole();

        prevTick = history.getLastTick(instrument);
        
    }
    
    private void print(Object o){
        console.getOut().println(o);
    }

    @Override
    public void onTick(Instrument instrument, ITick tick) throws JFException {
        if(instrument != this.instrument){
            return;
        }

        //we have a new period - execute custom bar logic and create a new bar
        if(customBar == null ){
            customBar = new CustomBar(tick, side, tick.getTime());
        }
        if(customBar.getOpen()- Range * instrument.getPipValue() >= tick.getBid() | customBar.getOpen()+ Range * instrument.getPipValue() <= tick.getBid()){
           customBar = new CustomBar(tick, side, tick.getTime());
           onCustomBar(customBar); 
        
        //update current bar's data 
         } else if (customBar != null) {
            customBar.updateBar(tick, side);
        } else {
            //note - here the first bar has not been created yet, so we just need to wait for the time condition to fulfill
            //alternatively one can load some ticks from history in order to create the first bar
        }
        
        
        prevTick = tick;
    }
    
    private void onCustomBar(IBar bar){
        print ("TODO: action on custom bar: " + bar);
    }

    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}
    @Override
    public void onMessage(IMessage message) throws JFException {}
    @Override
    public void onAccount(IAccount account) throws JFException {}
    @Override
    public void onStop() throws JFException {}
    
    public class CustomBar implements IBar {

        public double open;
        public double close;
        public double low;
        public double high;
        public double vol;
        public long time;
        
        @SuppressWarnings("serial")
        private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") {    {setTimeZone(TimeZone.getTimeZone("GMT"));    }};
        private DecimalFormat df = new DecimalFormat("0.00000");

        public CustomBar(ITick tick, OfferSide offerSide, long time) {
            double price = offerSide == OfferSide.BID ? tick.getBid() : tick.getAsk();
            double volume = offerSide == OfferSide.BID ? tick.getBidVolume() : tick.getAskVolume();
            
            open = close = low = high = price;
            vol = volume;
            this.time = time;
        }
        
        public CustomBar(double open, double close, double low, double high, double vol, long time) {
            this.open = open;
            this.close = close;
            this.low = low;
            this.high = high;
            this.vol = vol;
            this.time = time;        
        }
        
        public void updateBar(ITick tick, OfferSide offerSide) {
            double price = offerSide == OfferSide.BID ? tick.getBid() : tick.getAsk();
            double volume = offerSide == OfferSide.BID ? tick.getBidVolume() : tick.getAskVolume();
            
            close = price;
            if(price < low){
                low = price;
            }
            if(price > high){
                high = price;
            }
            //bar volumes are sum of their tick volumes
            vol += volume;
        }

        @Override
        public double getOpen() {
            return open;
        }

        @Override
        public double getClose() {
            return close;
        }

        @Override
        public double getLow() {
            return low;
        }

        @Override
        public double getHigh() {
            return high;
        }

        @Override
        public double getVolume() {
            return vol;
        }

        @Override
        public long getTime() {
            return time;
        }

        @Override
        public String toString() {
            StringBuilder str = new StringBuilder();
            str.append(time).append("[").append(sdf.format(time)).append("] O: ")
                    .append(df.format(open)).append(" C: ").append(df.format(close)).append(" H: ").append(df.format(high)).append(" L: ")
                    .append(df.format(low)).append(" V: ").append(df.format(vol));
            return str.toString();
        }

    }

}
