package jforex.strategies.indicators;
 
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;
 
import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.indicators.IIndicator;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
 
public class PivotStrat2 implements IStrategy {
 
    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private int counter = 0;
    private IOrder order;
     
     
    @Configurable("Instrument")
    public Instrument instrument = Instrument.EURUSD;
    @Configurable("Pivot")
    public Period pivotPeriod = Period.DAILY;
    @Configurable("Short period")
    public Period period = Period.ONE_HOUR;
     
     
    @Configurable("Amount")
    public double amount = 0.01;
    @Configurable("Slippage")
    public double slippage = 3;
    @Configurable("Offer side")
    public OfferSide offerSide = OfferSide.ASK;
    @Configurable("Filter")
    public Filter filter = Filter.ALL_FLATS;
     
    @Configurable("Take profit in pips")
    public int takeProfitPips = 30;
     
 
     
     
    @Override
    public void onStart(IContext context) throws JFException {
        this.console = context.getConsole();
        this.history = context.getHistory();
        this.engine = context.getEngine();
    }
 
    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
        if (period != this.period || instrument != this.instrument) {
            return;
        }
         
        long barStart = history.getBarStart(pivotPeriod, askBar.getTime());
    
        List<IBar> pivotBars = history.getBars(instrument, pivotPeriod, offerSide, filter, 2, barStart,0);
        IBar newPivotBar = pivotBars.get(1);
        IBar pivotBar = pivotBars.get(0);
        
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		calendar.setTimeInMillis(history.getLastTick(instrument).getTime());
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		if(hour != 8) {
			return;
		}
        /*if(history.getBarStart(period, newPivotBar.getTime()) != askBar.getTime()) {
            return;
        }//*/
         
        if(!isActive(order)) {
            order = null;
        }
         
      
        IBar bar = offerSide.equals(OfferSide.ASK) ? askBar : bidBar;
         
        OrderCommand orderCommand;
         
        double takeProfit = 0;
        double pivotPrice = getRoundedPrice((pivotBar.getClose() + pivotBar.getHigh() + pivotBar.getLow())/3);
        double stopLoss = pivotPrice;
         
        if(pivotPrice < bar.getClose()) {
            takeProfit = bar.getClose() + getPipPrice(takeProfitPips);
            stopLoss = bar.getClose() - getPipPrice(30);
            orderCommand = OrderCommand.BUY;
        } else {
           takeProfit = bar.getClose() - getPipPrice(takeProfitPips);
           stopLoss = bar.getClose() + getPipPrice(30);
            orderCommand = OrderCommand.SELL;
        }
 
        order = engine.submitOrder(getLabel(instrument), instrument, orderCommand, amount, 0, slippage, stopLoss, takeProfit);       
    }
    
    public void onTick(Instrument instrument, ITick tick) throws JFException {
        if (instrument != this.instrument) {
            return;
        }
    }
     
     
    public void onMessage(IMessage message) throws JFException {
        print(message);
    }
     
    public void onAccount(IAccount account) throws JFException {
    }
 
    public void onStop() throws JFException {
    }
     
    private boolean isActive(IOrder order) throws JFException {
        if (order != null && order.getState() != IOrder.State.CLOSED && order.getState() != IOrder.State.CANCELED) {
            return true;
        }
        return false;
    }
     
    private double getPipPrice(double pips) {
        return pips * this.instrument.getPipValue();
    }
     
    private String getLabel(Instrument instrument) {
        String label = instrument.name();
        label = label + (counter++);
        label = label.toUpperCase();
        return label;
    }
     
    private double getRoundedPrice(double price) {
        BigDecimal bd = new BigDecimal(price);
        bd = bd.setScale(instrument.getPipScale() + 1, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }
     
     
    /**************** debug print functions ***********************/
 
    private void print(Object... o) {
        for (Object ob : o) {
            if (ob instanceof Double) {
                print(toStr((Double) ob));
            } else if (ob instanceof double[]) {
                print((double[]) ob);
            } else if (ob instanceof double[]) {
                print((double[][]) ob);
            } else if (ob instanceof Long) {
                print2(toStr((Long) ob));
            } else if (ob instanceof IBar) {
                print((IBar) ob);
            } else {
                print2(ob);
            }
            print2(" ");
        }
        console.getOut().println();
    }
 
    private void print(Object o) {
        console.getOut().println(o);
    }
 
    private void print2(Object o) {
        console.getOut().print(o);
    }
     
    private void print(double d) {
        print(toStr(d));
    }
 
    private void print(double[] arr) {
        print(toStr(arr));
    }
 
    private void print(double[][] arr) {
        print(toStr(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 String toStr(double[] arr) {
        String str = "";
        for (int r = 0; r < arr.length; r++) {
            str += "[" + r + "] " + (new DecimalFormat("#.#######")).format(arr[r]) + "; ";
        }
        return str;
    }
 
    public String toStr(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 toStr(double d) {
        return (new DecimalFormat("#.#######")).format(d);
    }
 
    public String toStr(long time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") {
            {
                setTimeZone(TimeZone.getTimeZone("GMT"));
            }
        };
        return sdf.format(time);
    }
     
    private void printTime(Long time) {
        console.getOut().println(toStr(time));
    }
     
    private void print(IBar bar) {
        console.getOut().println(toStr(bar.getTime()) + "  O:"+bar.getOpen() + " C:"+bar.getClose() + " H:"+bar.getHigh() + " L:"+bar.getLow());
    }
     
    private void print(List<IBar> bars) {
        console.getOut().println("<<<");
        for(IBar bar : bars) {
            print(bar);
        }
        console.getOut().println("-");
    }

	public Set<Instrument> getSubscribedInstruments() {
		// TODO Auto-generated method stub
		Set<Instrument> instruments = new HashSet<Instrument>();
		instruments.add(instrument);
		return instruments;
	}
     
}