#include <chrono>
#include "sierrachart.h"

SCDLLName("Timestamp Data Feed")


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FileExists (const std::string& name)          
 {
    std::ifstream f(name.c_str());
    return f.good();
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string ConversionFloat(float number)
{
	std::string MyString ;
	// Conversion of the float number into a string
	{
		std::ostringstream oss;  
		oss << number;       
		MyString = oss.str() ;
	}
	
/* 	// Replacement of '.' by ','     This is a fix to an Excel issue in some countries (France, ...)
	{ std::replace( MyString.begin(), MyString.end(), '.', ',') ;  } */
	
	return MyString ;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

SCSFExport scsf_TimestampDataFeed(SCStudyInterfaceRef sc) 
{
	
	int& Clicks_PreviousCycle = sc.GetPersistentInt(1);  
	int& PreviousUpdateLastIndex = sc.GetPersistentInt(3);  
	int& IndexResetIntraday = sc.GetPersistentInt(4);  
	
	SCString& NameLogFile = sc.GetPersistentSCString(1);
	
	float& TimeDifference = sc.GetPersistentFloat(1); 
	
	int NotAFullRecalculation = 1 ;
	int const LastIndex = sc.ArraySize-1 ;
	
	SCString Texte ; 
	
	clock_t Clicks = clock() ;
	
	
	
	// sc.SetDefaults /////////////////////////////////////////////////////////////////////////////////////////////
	if (sc.SetDefaults)
	{
		sc.GraphName = "Timestamp Data Feed" ;
		sc.GraphRegion = 2 ;  
		sc.ValueFormat = 0 ;
		sc.AutoLoop = 0 ;  
		sc.DisplayStudyName = 1;
		sc.DisplayStudyInputValues = 1;
		sc.GlobalDisplayStudySubgraphsNameAndValue  = 0 ;
		sc.IncludeInSpreadsheet=0;
		sc.IncludeInStudySummary=0;
		
		sc.ResetAllScales = 1 ; 
	
		return ;	
	} 
	
	

	
	// Conversion of PC time into SCDateTime /////////////////////////////
	SCDateTime ComputerLocalTime ;
	{
		time_t now = time(0) ;
		tm *ltm = localtime(&now) ; 
		
		int Annee = 1900 + ltm->tm_year ;
		int Mois = 1 + ltm->tm_mon ;
		int JourDuMois = ltm->tm_mday ;
		int Heure = ltm->tm_hour ;
		int Minute = ltm->tm_min ;
		int Seconde = ltm->tm_sec ;

		ComputerLocalTime.SetDateTimeYMDHMS(Annee, Mois, JourDuMois, Heure, Minute, Seconde) ;   
	}
	
	
	
	if ( sc.UpdateStartIndex == 0 )
	{
		// Initialisations
		sc.GraphRegion = 2 ;  		
		NotAFullRecalculation = 0 ; 
		PreviousUpdateLastIndex = 999999999 ;
		IndexResetIntraday = 0 ;
		
		// Symbol and IndexResetIntraday
		SCString ChartSymbol = sc.GetChartSymbol(sc.ChartNumber) ;
		if ( ChartSymbol.Compare("$",1) == 0 ) 
		{
			if ( DATE_PART ( sc.BaseDateTimeIn[LastIndex] ) != DATE_PART( ComputerLocalTime ) )   
			{ IndexResetIntraday = LastIndex + 1 ;  }
			else
			{
				for ( int index = LastIndex ; index != 0 ; index -- )
				{
					if  (  sc.BaseDateTimeIn.TimeAt(index) <  sc.BaseDateTimeIn.TimeAt(index-1)  )   
					{
						IndexResetIntraday = index ;
						break ;
					}
				}
				
			}
		}
		else 
		{
			for ( int index = LastIndex ; index != 0 ; index -- )
			{
				if  (  sc.BaseDateTimeIn.TimeAt(index) == 64800    and   sc.BaseDateTimeIn.TimeAt(index-1)!= 64800   )     // futures are reset at 18:00:00 (NY time)   64800=18*3600
				{
					IndexResetIntraday = index ;
					break ;
				}
			}
		}
		
		// Creation of the .csv file   // Format is "Timestamps - [Symbol] - [TU] - [Date session]" 
		{
			NameLogFile.Format("Timestamps - ") ;
			
			// Name of symbol
			SCString SymbolAppend ;
			if 			( ChartSymbol.Compare("NQ-",3) == 0 ) { SymbolAppend = "Fut NQ100" ;  }
			else if 	( ChartSymbol.Compare("ES-",3) == 0 ) { SymbolAppend = "Fut SP500" ;  }
			else if 	( ChartSymbol == "$IUXX" ) 					{ SymbolAppend = "Ind NQ100" ;  }
			else if 	( ChartSymbol == "$SPX" ) 					{ SymbolAppend = "Ind SP500" ;  }
			else 																	{ SymbolAppend = ChartSymbol ;  }
			NameLogFile.Append(SymbolAppend) ;
			
			// GetBarPeriodParameters
			NameLogFile.AppendFormat(" - TU ") ;
			n_ACSIL :: s_BarPeriod BarPeriod ;
			sc.GetBarPeriodParameters(BarPeriod) ;
			int QuantiteUnite = BarPeriod.IntradayChartBarPeriodParameter1 ; 
			NameLogFile.AppendFormat("%d", QuantiteUnite) ;
			SCString Unite ;  // second or tick
			if ( BarPeriod.IntradayChartBarPeriodType == IBPT_DAYS_MINS_SECS ) { Unite = " sec - " ; }   else if ( BarPeriod.IntradayChartBarPeriodType == IBPT_NUM_TRADES_PER_BAR ) { Unite = " tick - " ; }  else { Unite = " TU_n.d. - " ; }
			NameLogFile.Append(Unite) ;
			
			// Date
			int Year, Month, Day ;
			SCDateTime DateSeance ;  
			if ( ChartSymbol.Compare("$",1) == 0 )  { DateSeance = ComputerLocalTime ;  }  
			else 														{ DateSeance = sc.BaseDateTimeIn[IndexResetIntraday] + 1 ;  }    // for future, session = settlement day
			DateSeance.GetDateYMD(Year, Month, Day) ;
			NameLogFile.AppendFormat("%04d-%02d-%02d", Year, Month, Day) ;
			
			// To avoid adding data when a replay is played
			if ( sc.ReplayStatus != REPLAY_STOPPED ) 
			{ NameLogFile.AppendFormat(" - Data issu d'un replay") ;  }
			
		
			// End of file name
			NameLogFile.AppendFormat(".csv") ;
			
			// Message to log
			SCString message ;
			message.Format("Writing in file ''%s''", NameLogFile.GetChars() ) ;   
			sc.AddMessageToLog(message,0) ;
		}
		
		// Column names for first file opening
		std::string string_NomFichierLog = NameLogFile.GetChars(); 
		if ( ! FileExists(string_NomFichierLog) )  
		{ 
			std::ofstream myStream ;
			myStream.open(NameLogFile, std::ofstream::out | std::ofstream::app) ;
			if ( myStream.is_open() )
			{	 
				myStream << "IntradayIndex" << ";" << "official Timestamp" << ";" << "DeltaTimestamp (ms)" << ";" << "Refresh SC (ms)"<< ";" << "Price" << ";" << "Volume" << ";" << "PC Timestamp" << ";" << "PC milliseconds" << ";" << "PC Date" <<  "\n" ; 
			}  
			else {	SCString message ;  message.Format("File Open : error") ;  sc.AddMessageToLog(message, 1) ;  }
		
		}

		// TimeDifference between PC (local time) and markat data
		SCDateTime Delta = ComputerLocalTime - sc.BaseDateTimeIn[LastIndex] ;
		TimeDifference = round ( Delta * 24 ) ;   
		
		
	} 

	
	// Refresh
	int Refresh ;
	{ 
		int Clicks_PresentCycle = clock() ;
		Refresh = Clicks_PresentCycle - Clicks_PreviousCycle ; 
		
		Clicks_PreviousCycle = Clicks_PresentCycle ;
	}
	
	
	
	// Get the millisecond part   /////////////// 
	int milliseconds ;
	{
		using namespace std;
		using namespace std::chrono;
		system_clock::time_point now = system_clock::now();     
		system_clock::duration tp = now.time_since_epoch();
		tp -= duration_cast<seconds>(tp);  
		milliseconds =   tp.count() / 1000000 ;
	}	
	
	

	if ( NotAFullRecalculation  and  ! sc.ChartIsDownloadingHistoricalData(sc.ChartNumber) ) 
	{
		if ( LastIndex > PreviousUpdateLastIndex )   // new ticks have arrived since refresh
		{

			std::ofstream myStream ;
			myStream.open(NameLogFile, std::ofstream::out | std::ofstream::app) ;
			if ( myStream.is_open() ) 	{	/* SCString message ;  message.Format("File Open: OK") ;  sc.AddMessageToLog(message, 0) ; */  }  else {	SCString message ;  message.Format("File Open : error") ;  sc.AddMessageToLog(message, 0) ;  }
			
			for (int index = PreviousUpdateLastIndex + 1 ; index < LastIndex + 1 ; index++)        
			{
				
				int Delta_Second ;
				SCDateTime Time_Tick = sc.BaseDateTimeIn[index] ;
				{
					Time_Tick.RoundDateTimeDownToSecond() ;
					double Delta = ComputerLocalTime - Time_Tick - TimeDifference/24.0 ;  
					Delta_Second = round(Delta*86400) ; 
				}
				
				// DeltaTimeStamp = Delta_Second + milliseconds ;
				int DeltaTimeStamp = Delta_Second*1000 + milliseconds ;
				
				// IntradayIndex
				int IntradayIndex = index - IndexResetIntraday ;
				
				// writing to file
				myStream << IntradayIndex << ";" << ConversionFloat(Time_Tick.GetTimeAsSCDateTime()) << ";" << DeltaTimeStamp << ";" << Refresh << ";" << ConversionFloat(sc.Close[index]) << ";" << sc.Volume[index] << ";" << ConversionFloat(ComputerLocalTime.GetTimeAsSCDateTime()) << ";" << milliseconds << ";" << ComputerLocalTime.GetDate() <<  "\n" ; 

			}
		}
	}
	
	
	// PreviousUpdateLastIndex
	if ( ! sc.ChartIsDownloadingHistoricalData(sc.ChartNumber) )
	{ PreviousUpdateLastIndex = LastIndex ;  }
	else 
	{ PreviousUpdateLastIndex = 999999999 ;  }
	
	sc.UpdateAlways = 1 ;   // 
	
	
}

