package ch.epfl.bigdata.ts.pattern.fitness;

import ch.epfl.bigdata.ts.dataparser.Tick;
import ch.epfl.bigdata.ts.dataparser.Utils;
import ch.epfl.bigdata.ts.ga.Chromosome;

import java.io.FileNotFoundException;
import java.util.*;


public class DoubleTop extends FitnessFunction {

    public static final int GENE_TOP_1 = 0;
    public static final int GENE_TOP_2 = 1;
    public static final int GENE_PROTECT_BUY_GAIN = 2;
    public static final int GENE_PROTECT_BUY_LOSS = 3;
    public static final int GENE_TREND_STRENGTH = 4;


    private double top1;
    private double top2;
    private double bottom;

    private boolean openPosition = false;

    private double lastPrice;

    private double buyLoss;
    private double buyGain;

    private int startingAmountOfMoney;
    private int amount;
    private int numOfShares;

    private int numOfDays;

    private Map<String, List<Tick>> data = new HashMap<String, List<Tick>>();

    public DoubleTop(int numOfDays, int startingAmountOfMoney) {
        this.numOfDays = numOfDays;
        this.startingAmountOfMoney = startingAmountOfMoney;
        Calendar calendar = new GregorianCalendar();
        calendar.set(Utils.STARTING_YEAR, Utils.STARTING_MONTH, Utils.STARTING_DAY);
        for (int i = 0; i < numOfDays; ) {
            try {
                List<Tick> ticks = Utils.readCSV(Utils.SDF.format(calendar.getTime()));
                data.put(Utils.SDF.format(calendar.getTime()), ticks);
                i++;

            } catch (FileNotFoundException e) {

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                calendar.add(Calendar.DATE, 1);
            }
        }
    }

    public DoubleTop(int numOfDays, int startingAmountOfMoney, int startingYear, int startingMonth, int startingDay) {
        // Year 2014, month 1 (Feb), day 21
        // numofDays = 18
        this.numOfDays = numOfDays;
        this.startingAmountOfMoney = startingAmountOfMoney;
        Calendar calendar = new GregorianCalendar();
        calendar.set(startingYear, startingMonth, startingDay);
        for (int i = 0; i < numOfDays; ) {
            try {
                List<Tick> ticks = Utils.readCSV(Utils.SDF.format(calendar.getTime()));
                data.put(Utils.SDF.format(calendar.getTime()), ticks);
                i++;

            } catch (FileNotFoundException e) {

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                calendar.add(Calendar.DATE, 1);
            }
        }
    }

    public void calcFitness(Chromosome chr) {

        init();

        Calendar calendar = new GregorianCalendar();
        calendar.set(Utils.STARTING_YEAR, Utils.STARTING_MONTH, Utils.STARTING_DAY);
        for (int i = 0; i < numOfDays; ) {
            //System.out.println(i);

            List<Tick> ticks1 = data.get(Utils.SDF.format(calendar.getTime()));
            calendar.add(Calendar.DATE, 1);
            if (ticks1 == null) {
                continue;
            }
//            System.out.println("Day "+Utils.SDF.format(calendar.getTime())+", amount "+amount);

            for (Tick tick : ticks1) {
                trade(tick, chr);
            }

            //buy everything
            //buy();
            //top1 = -1
            i++;

        }
        buy();

        chr.setFitness(amount);
    }

    private void trade(Tick transaction, Chromosome chr) {
        lastPrice = transaction.getPrice();

        if (openPosition) {
            if (lastPrice <= buyLoss) {
                top1 = lastPrice;
                buy();
            } else if (lastPrice >= buyGain) {
                top1 = top2;
                buy();
            }
        } else {
            if (top1 == -1) {
                top1 = lastPrice;
            } else if (bottom == -1) {
                if (lastPrice > top1) {
                    top1 = lastPrice;
                } else if ((top1 - lastPrice) >= chr.getGenes().get(GENE_TOP_1).getValue()) {
                    bottom = lastPrice;
                }
            } else if (top2 == -1) {
                if (lastPrice < bottom) {
                    bottom = lastPrice;
                } else if ((lastPrice - bottom) >= chr.getGenes().get(GENE_TOP_2).getValue()) {
                    top2 = lastPrice;

                    //sell
                    openPosition = true;
                    numOfShares = (int) Math.floor(amount / lastPrice);
                    amount += numOfShares * lastPrice;
                    double avg = top1 - bottom + top2 - bottom;
                    avg /= 2;
                    buyLoss = lastPrice - chr.getGenes().get(GENE_PROTECT_BUY_LOSS).getValue() * avg;
                    buyGain = lastPrice + chr.getGenes().get(GENE_PROTECT_BUY_GAIN).getValue() * avg;
                }
            }
        }
    }

    private void init() {
        top1 = -1;
        top2 = -1;
        bottom = -1;

        openPosition = false;

        lastPrice = 0;

        amount = startingAmountOfMoney;
    }

    private void buy() {
        openPosition = false;
        amount -= numOfShares * lastPrice;
        numOfShares = 0;
        top2 = bottom = -1;
    }
}

@@ -995,21 +995,22 @@
 AmountOf
-Money
+Shares
 ) %7B%0A    
@@ -1054,37 +1054,27 @@
    this.
-startingAmountOfMoney
+numOfShares
  = start
@@ -1076,37 +1076,38 @@
 startingAmountOf
-Money
+Shares
 ;%0A        Calend
@@ -1753,21 +1753,22 @@
 AmountOf
-Money
+Shares
 , int st
@@ -1936,37 +1936,27 @@
    this.
-startingAmountOfMoney
+numOfShares
  = start
@@ -1962,29 +1962,30 @@
 tingAmountOf
-Money
+Shares
 ;%0A        Ca
@@ -3320,32 +3320,34 @@
 i++;%0A%0A        %7D%0A
+//
         buy();%0A%0A
@@ -3358,29 +3358,137 @@
     
-chr.setFitness(amount
+//the fitness is the amount of money we have and the shares current price%0A        chr.setFitness(amount + numOfShares * lastPrice
 );%0A 
@@ -4511,80 +4511,8 @@
 ue;%0A
-                    numOfShares = (int) Math.floor(amount / lastPrice);%0A
     
@@ -4554,32 +4554,69 @@
 es * lastPrice;%0A
+                    numOfShares = 0;%0A
                 
@@ -5189,16 +5189,76 @@
  false;%0A
+        numOfShares = (int) Math.floor(amount / lastPrice);%0A
         
@@ -5296,33 +5296,8 @@
 ce;%0A
-        numOfShares = 0;%0A
     

fix implementation errors