package singlejartest;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;

import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;
import com.dukascopy.api.IMessage.Type;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.indicators.IndicatorInfo;
import com.dukascopy.api.indicators.IndicatorResult;

@Library("C:/JFLibs/slf4j-log4j12-1.5.8.jar;C:/JFLibs/slf4j-api-1.5.8.jar;c:/JFLibs/xstream-1.4.jar")

@RequiresFullAccess
public class RenkoTradingStrategy implements IStrategy 
{
	private static final Logger LOGGER = LoggerFactory.getLogger(RenkoTradingStrategy.class);
	private final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss") { { setTimeZone(TimeZone.getTimeZone("GMT")); } };
	
	protected IContext _context = null;
	protected IConsole _console = null;
	protected IEngine _engine = null;
	protected IHistory _history;
	protected IIndicators _indicators = null;

	static private Object _lock = new Object();
	
	private class InstrData
	{
		public boolean firstTick = true;
		public boolean historyLoaded = false;
		public boolean historyLoadingStarted = false;
		public List<ITick> ticks = new ArrayList<ITick>();
	}
	
	private HashMap<Instrument, InstrData> _instrData = new HashMap<Instrument, InstrData>();
	
	private boolean _firstTickEUR = true;
		
	// ***** JFOREX API EVENT HANDLERS
	// ****************************************************************

	public void onStart(IContext context) throws JFException 
	{
		LOGGER.info("*** Strategy Started ***");
		_history = context.getHistory();
	}

	public void onStop() throws JFException 
	{
		LOGGER.info("*** Strategy Stopped ***");
	}

	public void onBar(Instrument instrument, Period period, IBar askbar, IBar bidbar) 
	{
	}

	public void onTick(Instrument instrument, ITick tick) 
	{
//		if (_timerTest == true)
//			return;  // 
		
		try 
		{
			InstrData data = _instrData.get(instrument);
			
			if (data == null)
			{
				data = new InstrData();
				_instrData.put(instrument, data);
			}
			
			if (data.firstTick)
			{
				data.firstTick = false;

				// Save live ticks that arrive whilst loading history details.
				data.ticks.add(tick);
			}
			else 
			{
				if (data.historyLoaded == false)
				{
					data.ticks.add(tick);
					LOGGER.info(String.format("Storing %s tick, waiting for history", instrument));

					if (data.historyLoadingStarted == false)
					{
						data.historyLoadingStarted = true;
						final Instrument instr = instrument;
						final ITick firstTick = data.ticks.get(0);
						final InstrData instrData = data;
						
						// This is the thread responsible for loading history data for a particular instrument.
						Runnable r = new Runnable() 
						{
							public void run()
							{
								int tickCount = 0;

								synchronized (_lock)
								{
									try 
									{
										int historyDays = 60;
										long tickTime = firstTick.getTime();
										
										// Split the retrieval up into days and process a days worth of history ticks at a time.  This stops
										// needing a large amount of memory to store all of the ticks.
										Date stopTime = new Date(tickTime);
										Date startTime = new Date(tickTime - Period.DAILY.getInterval() * historyDays);
										LOGGER.info(String.format("Retrieving %d days of history ticks for %s from %s to %s", 
																  historyDays, instr, startTime, new Date(tickTime)));
										Date endTime = null;
										
										for (int i = 0; endTime != stopTime && i < historyDays; i++)
										{
											endTime = new Date(startTime.getTime() + Period.DAILY.getInterval());
											
											if (endTime.getTime() > stopTime.getTime())
											{
												endTime = stopTime;
											}
											
											LOGGER.info(String.format("   %s Tick data from %s to %s", instr, startTime, endTime));
											List<ITick> historyTicks = _history.getTicks(instr, startTime.getTime(), endTime.getTime());
											int size = historyTicks.size();
											LOGGER.info(String.format("       %d Ticks", size));
											
											// If size is 1 or 0 then we are on a weekend, move to next day.
											if (size > 1)
											{
												tickCount += size;
											}
							
											startTime = new Date(startTime.getTime() + Period.DAILY.getInterval());
										}
									}
									catch (Exception e) 
									{
										LOGGER.info(String.format("Get History for %s failed: %s", instr, e.getMessage()));
									}
							
									LOGGER.info(String.format("History tick processing for %s completed, %d records read", instr, tickCount));
								}
								
								instrData.historyLoaded = true;
							}
						};
		
						Thread t = new Thread(r);
						t.start();
					}
					
					return;
				}
				
				if (data.ticks.size() > 0)
				{
					LOGGER.info(String.format("Processing queued ticks (%d) for %s", data.ticks.size(), instrument));
				
					for (ITick queuedTick : data.ticks)
					{
						processLiveTick(instrument, queuedTick);
					}
					
					data.ticks.clear();
					
					LOGGER.info("Live trading commencing for " + instrument);
				}
			}
			
			processLiveTick(instrument, tick);
		} 
		catch (JFException jfe) 
		{
			LOGGER.error("onTick(): JFException caught: " + jfe.getMessage());
		}
	}

	private void processLiveTick(Instrument instrument, ITick tick) throws JFException
	{
		// This is where strategy processing would take place.
	}
	
	public void onAccount(IAccount account) 
	{
	}
	
	public void onMessage(IMessage message) 
	{
	}
}