package misc.support.jforex.strategies.template;

import com.dukascopy.api.*;

import java.text.DecimalFormat;
import java.util.Currency;
import java.util.HashSet;
import java.util.Set;

public class RiskAmountStrat implements IStrategy {

    private IConsole console;
    private IContext context;
    private double amount;
    
    @Configurable("Instrument")
    public Instrument instrument = Instrument.XAGUSD;
    @Configurable("Risk percent")
    public double risk = 3;
    @Configurable("Offer side")
    public OfferSide offerSide = OfferSide.BID;
    
    @Configurable("SL pips")
    public double stopLossPips = 100;

    @Override
    public void onStart(IContext context) throws JFException {
        this.context = context;
        this.console = context.getConsole();
                
        IAccount account = context.getAccount();
        double amount;
        try{



            amount = XRate.getAmount(context, account, instrument, risk, stopLossPips);
            ITick tick = context.getHistory().getLastTick(instrument);
            double sl = tick.getAsk() - instrument.getPipValue() * stopLossPips;

            context.getEngine().submitOrder("order", instrument, IEngine.OrderCommand.BUY, amount, 0, 2, sl, 0);
            
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public String toStr(double d) {
        return (new DecimalFormat("#.#######")).format(d);
    }

    public void onTick(Instrument instrument, ITick tick) throws JFException {
        if (instrument != this.instrument) {
            return;
        }
    }
    
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
    }

    public void onMessage(IMessage message) throws JFException {
        console.getOut().println(message);
    }

    public void onAccount(IAccount account) throws JFException {
    }

    public void onStop() throws JFException {
    }

    static private class XRate {

        private IHistory history;
        private IContext context;
        private IConsole console;

        public XRate(IContext context) {
            this.history = context.getHistory();
            this.context = context;
            this.console = context.getConsole();
            
            System.out.println(history +" "+ context +" "+ console);
        }
        private String[] mainCurrencies = {"USD", "GBP", "AUD", "CAD", "CHF", "GBP", "HKD", "NZD"};

        private double getExchangeRate(Currency c1, Currency c2) throws JFException {

            Instrument instr = getInstrument(c1.getCurrencyCode(), c2.getCurrencyCode());

            if (instr != null) {
                subscribe(instr);
                return getPrice(instr);
            } else {
                instr = getInstrument(c2.getCurrencyCode(), c1.getCurrencyCode());
                if (instr != null) {
                    subscribe(instr);
                    return 1 / getPrice(instr);
                }
            }

            double EURCUR1 = exchangeRateEUR(c1);
            double EURCUR2 = exchangeRateEUR(c2);
            return EURCUR2 / EURCUR1;
        }

        private double exchangeRateEUR(Currency CUR) throws JFException {

            if (CUR.equals(Currency.getInstance("EUR"))) {
                return 1;
            }

            Instrument instr2 = null;
            Instrument instr = getInstrument("EUR", CUR.getCurrencyCode());

            if (instr == null) {
                for (String mainCUR : mainCurrencies) {

                    if (mainCUR.equals(CUR.getCurrencyCode())) {
                        instr = getInstrument("EUR", mainCUR);
                        break;
                    }

                    instr = getInstrument(mainCUR, CUR.getCurrencyCode());
                    if (instr != null) {
                        instr2 = getInstrument("EUR", mainCUR);
                        if (instr2 == null) {
                            throw new JFException("[XRate] Error in currency exchange rate calculation.");
                        }
                        break;
                    }
                }
            }

            if (instr != null) {
                if (instr2 == null) {
                    return getPrice(instr); // EUR <-> MAIN_CUR
                } else {
                    return getPrice(instr) * getPrice(instr2); // EUR <-> MAIN_CUR + MAIN_CUR <-> CUR
                }
            } else {
                if (CUR.equals(Currency.getInstance("XAU")) || CUR.equals(Currency.getInstance("XAG"))) {
                    instr = Instrument.EURUSD;
                    instr2 = getInstrument(CUR.getCurrencyCode(), "USD");
                } else {
                    throw new JFException("[XRate] Error in currency exchange rate calculation.");
                }
                subscribe(instr);
                subscribe(instr2);

                // EURUSD * (1 / XXXUSD) = EURUSD * USDXXX = EURXXX
                return getPrice(instr) * (1 / getPrice(instr2)); // EUR <-> MAIN_CUR + MAIN_CUR <-> CUR
            }
        }

        private Instrument getInstrument(String c1, String c2) {

            if (Instrument.contains(c1 + "/" + c2)) {
                return Instrument.valueOf(c1 + c2);
            }
            return null;
        }

        private void subscribe(Instrument instr) throws JFException {
            Set<Instrument> instruments = context.getSubscribedInstruments();
            Set<Instrument> newInstr = new HashSet<Instrument>();
            if (!instruments.contains(instr)) {
                
                newInstr.add(instr);
                context.setSubscribedInstruments(newInstr);
                
                int i = 10;
                while (!context.getSubscribedInstruments().containsAll(newInstr) && i>0) {
                    try {
                        console.getOut().println("[XRate] Instruments not subscribed yet " + i + " "+newInstr);
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        console.getOut().println(e.getMessage());
                    }
                    i--;
                }
                
            }
        }

        private double getPrice(Instrument instr) throws JFException {
            subscribe(instr);
            ITick tick = history.getLastTick(instr);
            return (tick.getAsk() + tick.getBid()) / 2;
        }

        static private double getAmount(IContext context, IAccount account, Instrument instrument, double risk, double slPips) throws JFException {
            return getAmount(context, account, instrument, account.getEquity(), risk, slPips);
        }

        static private double getAmount(IContext context,  IAccount account, Instrument instrument, double totalAmount, double risk, double slPips) throws JFException {
            // !!! USD EUR and JPY in variable names are used only for simplicity
            // this method is universal and USD EUR and JPY can be any other currencies
            // EURJPY - pInstrument, USD account currency

            risk = risk / 100;
            if (risk < 0.0 || risk > 1.0) {
                throw new JFException("Risk must be from 0.0 to 1.0.");
            }
            double riskUSD = totalAmount * risk;
            double pipJPY = instrument.getPipValue(); // USDJPY pip value in JPY
            XRate xrate = new XRate(context);
            double USDJPY = xrate.getExchangeRate(account.getCurrency(), instrument.getSecondaryCurrency());
            double riskJPY = riskUSD * USDJPY;
            double amountEUR = riskJPY / (slPips * pipJPY);

            if(!instrument.getSecondaryCurrency().getSymbol().equals("XAU") &&
                    !instrument.getSecondaryCurrency().getSymbol().equals("XAG")) {
                amountEUR = amountEUR/ 1000000;
            }
            
            return amountEUR;
        }
        
        static void print(double d, IContext context) {
            context.getConsole().getOut().println((new DecimalFormat("#.#######")).format(d));
        }
    }
}
