//---------------------------------------------------------------------------
#include <IniFiles.hpp>
#include <DateUtils.hpp>
#include <stdio.h>
#include <math.h>
//---------------------------------------------------------------------------
#pragma hdrstop
#include "src_finam.h"
#include "frmConfig.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
class TAuth
{ public:
	void __fastcall OnProxyAuth(TObject*, TIdAuthentication *Authentication, bool &Handled)
	{
	   Authentication->Reset();
	   Handled = true;
	}
};

TIdHTTP* Http;
TAuth*   auth;
WORD     crc_url  = 0;
double   crc_data = 0;

char*   url( SET_GROUP*, SET_STOCK*, TDateTime, TDateTime dt2=0);
SERIES* parse( SET_GROUP*, SET_STOCK*);
void    encode_tiker( char*);
void    crc_check( char*, SERIES* &);
double  mj2dt( double);
double  dt2mj( double);
//---------------------------------------------------------------------------
DWORD init()
{
  TMemIniFile*  ini = new TMemIniFile( ".\\finam.ini");


	FinamURL       = ini->ReadString(  "main", "url", "");
	FinamVolTrunc  = ini->ReadInteger( "main", "vol_trunc", 0);
	FinamDivTikers = ini->ReadString(  "main", "div_tikers", "");
	NotDeltemp     = ini->ReadBool(    "main", "not_deltemp", false);
	ConnectTimeout = ini->ReadInteger( "main", "connect_timeout", 30);
	ProxyEnable    = ini->ReadBool(    "main", "proxy_enable", false);
	ProxyPort      = ini->ReadInteger( "main", "proxy_port", 0);
	ProxyServer    = ini->ReadString(  "main", "proxy_server", "");
	ProxyUser      = ini->ReadString(  "main", "proxy_user", "");
	ProxyPassword  = ini->ReadString(  "main", "proxy_password", "");

	Http = new TIdHTTP( NULL);

	Http->Request->AcceptCharSet  = "iso-8859-1,*,utf-8";
	Http->Request->AcceptLanguage = "ru,en-us,en";

	Http->Request->AcceptEncoding = "gzip, deflate";
	Http->Compressor = new TIdCompressorZLib(NULL);

	Http->HTTPOptions << hoForceEncodeParams;

	if( ProxyEnable )
	{
	   Http->HTTPOptions << hoInProcessAuth;
	   auth = new TAuth;
	   Http->OnProxyAuthorization = auth->OnProxyAuth;

	   Http->ProxyParams->ProxyServer   = ProxyServer;
	   Http->ProxyParams->ProxyPort	    = ProxyPort;
	   Http->ProxyParams->ProxyUsername = ProxyUser;
	   Http->ProxyParams->ProxyPassword = ProxyPassword;
	   Http->ProxyParams->BasicAuthentication = false;
	}

	Http->ConnectTimeout = ConnectTimeout * 1000;
	Http->ReadTimeout    = ConnectTimeout * 1000;

	Http->Request->Referer = "http://www.finam.ru/analysis/export/default.asp";

   delete  ini;
   return PLG_SRC_OK;
}
//---------------------------------------------------------------------------
char* ChkTicker( PLG_SRC_DATA* data)
{
  TMemIniFile*  ini = new TMemIniFile( ".\\finam.dat");
  TStringList*  sl = new TStringList;
  AnsiString    s1;
  char          str[200],s2[200],*p;


	sprintf( str, "tiker not found");
//	MessageBox( 0, data->group->sPlatform, "fuck", MB_OK);

	s1 = ini->ReadString( data->group->sPlatform, data->stock->sTicker, "fuck");
	if( s1 == "fuck" )
	{
	   ini->ReadSection( data->group->sPlatform, sl);
	   for( int i=0; i < sl->Count; i++)
	   {
		  s1 = ini->ReadString( data->group->sPlatform, sl->Strings[i], "-1,fuck");
		  sprintf( s2, "%s", s1.c_str());
		  p = strtok( s2, ","); p = strtok( NULL, ","); s1 = p;

		  if( s1.AnsiCompareIC( data->stock->sTicker) == 0 ) sprintf( str, p);
	   }
	}
	else
	{
	   sprintf( s2, "%s", s1.c_str());
	   p = strtok( s2, ",");
	   p = strtok( NULL, ",");
	   sprintf( str, p);
	}

  delete ini;
  delete sl;
  return strdup(str);
}
//---------------------------------------------------------------------------
SERIES* Down( PLG_SRC_DATA* data)
{
  TFileStream* strm;
  AnsiString   str;
  char*        surl;
  SERIES*      ser = NULL;
  bool         err = false;


	if( data->dt2 == 0 )  surl = url( data->group, data->stock, mj2dt(data->dt1), 0);
	else                  surl = url( data->group, data->stock, mj2dt(data->dt1), mj2dt(data->dt2));

	if( surl == NULL ) return NULL;

	str = data->group->sDirectory; str += "\\"; str += data->stock->sTicker; str += ".tmp";
	strm = new TFileStream( str, fmCreate);

	try{ Http->Get( surl, strm); }
	catch(...) { err = true; }

	Http->Disconnect();
	delete strm;

	if( !err )
	ser = parse( data->group, data->stock);
	if( !NotDeltemp )  DeleteFile( str);

	if( !err ) crc_check( surl, ser);

   free( surl);
   return ser;
}
//---------------------------------------------------------------------------
void Config( HWND hwnd)
{
   FormConfig = new TFormConfig( NULL);
   FormConfig->ShowModal();
   delete FormConfig;
}
//---------------------------------------------------------------------------
LST_TICKERS* LstTickers( char* platform)
{
  TMemIniFile*  ini  = new TMemIniFile( ".\\finam.dat");
  TStringList*  s1   = new TStringList;
  LST_TICKERS*  list = new LST_TICKERS;


	ini->ReadSection( platform, s1);
	list->Count = s1->Count;
	list->sName = new char*[list->Count];
	for( int i=0; i < list->Count; i++)
	  list->sName[i] = strdup( s1->Strings[i].c_str());

   delete s1;
   delete ini;
   return list;
}
//---------------------------------------------------------------------------
char* url( SET_GROUP* group, SET_STOCK* stock, TDateTime dt, TDateTime dt2)
{
  TMemIniFile*  ini = new TMemIniFile( ".\\finam.dat");
  char          url[1000], str[200], ss[200],*p;
  AnsiString    s_sec;
  TDateTime     curr = 0;
  int           id, idp, tf;
  ushort        y1,m1,d1,y2,m2,d2;
  AnsiString    s1;
  TStringList*  sl = new TStringList;


	url[0] = '\0';

	sprintf( str, "fuck");

	s1 = ini->ReadString( group->sPlatform, stock->sTicker, "fuck");
	if( s1 == "fuck" )
	{
	   ini->ReadSection( group->sPlatform, sl);
	   for( int i=0; i < sl->Count; i++)
	   {
		  s1 = ini->ReadString( group->sPlatform, sl->Strings[i], "-1,fuck");
		  sprintf( ss, "%s", s1.c_str());
		  p = strtok( ss, ","); id = atoi(p);
		  p = strtok( NULL, ","); s1 = p;

		  if( s1.AnsiCompareIC( stock->sTicker) == 0 )
		  {
			 sprintf( str, sl->Strings[i].c_str());
			 break;
		  }
	   }
	}
	else
	{
	   sprintf( str, "%s", s1.c_str());
	   p = strtok( str, ",");   id = atoi(p);
	   p = strtok( NULL, ",");  sprintf( str, stock->sTicker);
	}

	delete sl;
	delete ini;

//	MessageBox( 0, group->sPlatform, "fuck", MB_OK);
	if( strcmp( str, "fuck") == 0 ) return NULL;

	sprintf( ss, str);

	switch( group->uPlatform )
	{
	  case 0 : idp = FINAM_MICEX        ; break;
	  case 1 : idp = FINAM_MICEX_PIF    ; break;
	  case 2 : idp = FINAM_MICEX_OBL    ; break;
	  case 3 : idp = FINAM_MICEX_OBL_V  ; break;
	  case 4 : idp = FINAM_RTS          ; break;
	  case 5 : idp = FINAM_RTS_GAZ      ; break;
	  case 6 : idp = FINAM_RTS_GTS      ; break;
	  case 7 : idp = FINAM_RTS_BOARD    ; break;
	  case 8 : idp = FINAM_RTS_Standard ; break;
	  case 9 : idp = FINAM_FUTURES_FORTS; break;
	  case 10: idp = FINAM_CURR         ; break;
	  case 11: idp = FINAM_INDEX        ; break;
	  case 12: idp = FINAM_FUTURES      ; break;
	  case 13: idp = FINAM_ADR          ; break;
	  case 14: idp = FINAM_MATERIAL     ; break;
	  case 15: idp = FINAM_SPFR         ; break;
	  case 16: idp = FINAM_ARC_FORTS    ; break;
	  case 17: idp = FINAM_ARC_MICEX    ; break;
	  case 18: idp = FINAM_ARC_RTS      ; break;
	  case 19: idp = FINAM_USA_STOCK    ; break;
	  case 20: idp = FINAM_US_BOND      ; break;
	  case 21: idp = FINAM_USA_INDUSTRY ; break;
	  case 22: idp = FINAM_ETF          ; break;
	  case 23: idp = FINAM_INDEX_IND    ; break;
	}

	switch( group->uTimeFrame )
	{
	  case TF_TIKS : tf = 1;  break;
	  case TF_MIN1 : tf = 2;  break;
	  case TF_MIN5 : tf = 3;  break;
	  case TF_MIN10: tf = 4;  break;
	  case TF_MIN15: tf = 5;  break;
	  case TF_MIN30: tf = 6;  break;
	  case TF_MIN60: tf = 11; break;
	  case TF_HOUR : tf = 7;  break;
	  case TF_DAY  : tf = 8;  break;
	  case TF_WEEK : tf = 9;  break;
	  case TF_MONTH: tf = 10; break;
	}

	if( dt.Val == 0 ) return NULL;
	else
	{
	   if( group->uTimeFrame != TF_TIKS )
	   {
		  dt.DecodeDate( &y1, &m1, &d1);

		  if( dt2.Val == 0.0 )
		  {
			 curr = curr.CurrentDate();
			 curr.DecodeDate( &y2, &m2, &d2);
		  }
		  else
			 dt2.DecodeDate( &y2, &m2, &d2);

		  sprintf( str, "%s", ss); encode_tiker( str);
		  sprintf( url, FinamURL.c_str(), idp, id, tf, d1, m1-1, y1, d2, m2-1, y2, str, 5);   // 5 - формат выходного файла (DTOHLCV)
	   }
	   else
	   {
		  TDateTime t1 = TDateTime( 10, 00, 0, 0);
		  TDateTime t2 = TDateTime( 19, 00, 0, 0);
		  curr = curr.CurrentTime();

		  if( curr >= t1 && curr <= t2 )  // в рабочее время только один день можно качать
		  {
			 if( dt2.Val == 0.0 )
			 {
				curr = curr.CurrentDate();
				curr.DecodeDate( &y1, &m1, &d1);
				curr.DecodeDate( &y2, &m2, &d2);
			 }
			 else
			 {
				dt2.DecodeDate( &y1, &m1, &d1);
				dt2.DecodeDate( &y2, &m2, &d2);
			 }
		  }
		  else
		  {
			 dt.DecodeDate( &y1, &m1, &d1);

			 if( dt2.Val == 0.0 )
			 {
				curr = curr.CurrentDate();
				curr.DecodeDate( &y2, &m2, &d2);
			 }
			 else
			    dt2.DecodeDate( &y2, &m2, &d2);

		  }

		  sprintf( str, "%s", ss); encode_tiker( str);
		  sprintf( url, FinamURL.c_str(), idp, id, tf, d1, m1-1, y1, d2, m2-1, y2, str, 9);  // 9 - формат выходного файла (DTCV)
	   }
	}

   return strdup(url);
}
//---------------------------------------------------------------------------
SERIES* parse( SET_GROUP* group, SET_STOCK* stock)
{
  SERIES*       new_data = NULL;
  FILE*         ff_up;
  AnsiString*   ss  = new AnsiString;
  TStringList*  sl1 = new TStringList;
  TStringList*  sl2 = new TStringList;
  TStringList*  dtl = new TStringList;
  char          str[300];
  int           year=0, month=0, day=0, hour=0, min=0, sec=0;
  TDateTime     dt;
  int           dd;
  bool          trunc = false;


	*ss = group->sDirectory; *ss += "\\"; *ss += stock->sTicker; *ss += ".tmp";
	if( (ff_up = fopen( ss->c_str(), "rt")) != NULL )
	{
	   while( fgets( str, 300, ff_up) != NULL )  sl1->Add( str);
	   fclose( ff_up);
	}

	if( sl1->Count < 1 )
	{
	   delete sl1;
	   delete sl2;
       delete dtl;
	   return NULL;
	}
	else sl1->Delete(0);

	if( sl1->Count == 0 )
	{
	  new_data           = new SERIES;
	  new_data->Count    = 0;
	  new_data->pDate    = NULL;
	  new_data->pfOpen   = NULL;
	  new_data->pfHigh   = NULL;
	  new_data->pfLow    = NULL;
	  new_data->pfClose  = NULL;
	  new_data->pfVolume = NULL;
	  new_data->pfOpInt  = NULL;
	  delete ss;
	  delete sl1;
	  delete sl2;
      delete dtl;
	  return new_data;
	}

	new_data           = new SERIES;
	new_data->Count    = sl1->Count;
	new_data->pDate    = new double[new_data->Count];
	new_data->pfOpen   = new float [new_data->Count];
	new_data->pfHigh   = new float [new_data->Count];
	new_data->pfLow    = new float [new_data->Count];
	new_data->pfClose  = new float [new_data->Count];
	new_data->pfVolume = new float [new_data->Count];
	new_data->pfOpInt  = new float [new_data->Count];
	ZeroMemory( new_data->pDate   , sizeof(double)*new_data->Count);
	ZeroMemory( new_data->pfOpen  , sizeof(float)*new_data->Count);
	ZeroMemory( new_data->pfHigh  , sizeof(float)*new_data->Count);
	ZeroMemory( new_data->pfLow   , sizeof(float)*new_data->Count);
	ZeroMemory( new_data->pfClose , sizeof(float)*new_data->Count);
	ZeroMemory( new_data->pfVolume, sizeof(float)*new_data->Count);
	ZeroMemory( new_data->pfOpInt , sizeof(float)*new_data->Count);

	try{

	sl2->Delimiter = ',';
	sl2->DelimitedText = FinamDivTikers;
	for( int i=0; i < sl2->Count; i++)
	{
		*ss = sl2->Strings[i];
		if( strcmpi( stock->sTicker, ss->c_str()) == 0 ) trunc = true;
	}


	sl2->Delimiter = ',';
	for( int i=0; i < sl1->Count; i++)
	{
	  sl2->Clear();
	  sl2->DelimitedText = sl1->Strings[i];

	  *ss = sl2->Strings[0];
	  dtl->Delimiter = '/';
	  dtl->DelimitedText = *ss;
	  day   = dtl->Strings[0].ToInt();
	  month = dtl->Strings[1].ToInt();
	  year  = dtl->Strings[2].ToInt();
	  if( year < 50 )              year += 2000;
	  if( year > 50 && year < 100) year += 1900;

	  *ss = sl2->Strings[1];
	  dtl->Clear();
	  dtl->Delimiter = ':';
	  dtl->DelimitedText = *ss;
	  hour  = dtl->Strings[0].ToInt();
	  min   = dtl->Strings[1].ToInt();
	  sec   = dtl->Strings[2].ToInt();
	  dt    = TDateTime( year,month,day,hour,min,sec,0);
	  new_data->pDate[i] = dt2mj(dt);

	  if( group->uTimeFrame != TF_TIKS )
	  {
		 *ss = sl2->Strings[2]; new_data->pfOpen[i]  = atof( ss->c_str());
		 *ss = sl2->Strings[3]; new_data->pfHigh[i]  = atof( ss->c_str());
		 *ss = sl2->Strings[4]; new_data->pfLow[i]   = atof( ss->c_str());
		 *ss = sl2->Strings[5]; new_data->pfClose[i] = atof( ss->c_str());
		 *ss = sl2->Strings[6];
	  }
	  else
	  {
		 *ss = sl2->Strings[2]; new_data->pfOpen[i]  = atof( ss->c_str());
								new_data->pfHigh[i]  = new_data->pfOpen[i];
								new_data->pfLow[i]   = new_data->pfOpen[i];
								new_data->pfClose[i] = new_data->pfOpen[i];
		 *ss = sl2->Strings[3];
	  }

	  if( trunc )
	  {
		dd = ss->Length() - FinamVolTrunc + 1;
		*ss = ss->Insert( ".", dd);
	  }
	  new_data->pfVolume[i] = atof( ss->c_str());

	  new_data->pfOpInt[i] = 0;
	}

	}
	catch(...)
	{
	   delete ss;
	   delete sl1;
	   delete sl2;
	   delete dtl;
	   delete [] new_data->pDate;
	   delete [] new_data->pfOpen;
	   delete [] new_data->pfHigh;
	   delete [] new_data->pfLow;
	   delete [] new_data->pfClose;
	   delete [] new_data->pfVolume;
	   delete [] new_data->pfOpInt;
	   delete new_data;
	   return NULL;
	}

  delete ss;
  delete sl1;
  delete sl2;
  delete dtl;
  return new_data;
}
//---------------------------------------------------------------------------
void encode_tiker( char* str)
{
  UTF8String  ss = AnsiToUtf8( str);
  AnsiString  s_out;
  uchar       uc;


	for( int i=1; i <= ss.Length(); i++)
	{
	  uc = ss[i];
	  switch( uc )
	  {
		case 0x20: s_out += "+";                            break;
		case 0x26:
		case 0x2B: s_out = s_out + "%" + IntToHex( uc, 2);  break;
		default:
			 if( uc <= 0x7F ) s_out += (char)uc;
			 else		      s_out = s_out + "%" + IntToHex( uc, 2);
	  }
	}

	sprintf( str, "%s", s_out.c_str());
}
//---------------------------------------------------------------------------
void crc_check( char* url, SERIES* &ser)
{
  WORD    ks_url;
  double  ks_data;
  FILE*   ff;


	if( ser == NULL || ser->Count == 0 ) return;

	ks_url = 65535;
	for( unsigned int i=1; i < strlen(url); i++)
	{
	  ks_url ^= url[i];
	  for( int j=0; j < 8; j++)
		if( (ks_url/2)*2 != ks_url ) ks_url = ks_url/2 ^ 40961;
		else ks_url/=2;
	}

	ks_data = 0;
	for( int i=0; i < ser->Count; i++)
	{
	   ks_data += 1/(ser->pDate[i]+1);
	   ks_data += 1/(ser->pfOpen[i]+1);
	   ks_data += 1/(ser->pfHigh[i]+1);
	   ks_data += 1/(ser->pfLow[i]+1);
	   ks_data += 1/(ser->pfClose[i]+1);
	   ks_data += 1/(ser->pfVolume[i]+1);
	}

	if((ks_url != crc_url) && (ks_data == crc_data))
	{
	   delete [] ser->pDate;
	   delete [] ser->pfOpen;
	   delete [] ser->pfHigh;
	   delete [] ser->pfLow;
	   delete [] ser->pfClose;
	   delete [] ser->pfVolume;
	   delete [] ser->pfOpInt;
	   delete ser;
	   ser = NULL;

	   ff = fopen( "finam.err", "at");
	   fprintf( ff, "xx ks_url=%d\t crc_url=%d\t ks_data=%f\t crc_data=%f\t url=%s\n",
				ks_url, crc_url, ks_data, crc_data, url);
	   fclose(ff);
	}

	if((ks_url != crc_url) && (ks_data != crc_data))
	{
	   crc_url  = ks_url;
	   crc_data = ks_data;

//	   fprintf( ff, "-- ks_url=%d , crc_url=%d , ks_data=%d, crc_data=%d, url=%s\n", ks_url, crc_url, ks_data, crc_data, url);
	}

  return;
}
//---------------------------------------------------------------------------
double round_int( double param)
{
  double integer, fractional;
  double Result = 0.0;


	fractional = modf( param, &integer);

	if(param > 0)
	{
	  if( fractional >= 0.5 )  Result = ceil(param);
	  else                     Result = floor(param);
	}
	else
	{
	  if( fractional <= -0.5 ) Result = floor(param);
	  else                     Result = ceil(param);
	}

	return Result;
}
//---------------------------------------------------------------------------
double mj2dt( double JD)
{
  unsigned long d,m,y;
  unsigned long h,mm,s;
  unsigned long j = JD;


	if( j == 0 ) return 0;

	j += 2415019l; // modified Julian day

	j -= 1721119l;
	y = (4l*j-1l)/146097l;
	d = (4l*j-1l-146097l*y)/4l;
	j = (4l*d+3l)/1461l;
	d = (4l*d+7l-1461l*j)/4l;
	m = (5l*d-3l)/153l;
	d = (5l*d+2l-153l*m)/5l;
	y = 100l*y+j;
	if( m < 10 ) m += 3;
	else       { m -= 9; y++; }

	JD = JD - Int(JD);

//	unsigned long t= JD * 86400;
	double tt = JD*86400.0;             // fucking float conversion!
	unsigned long t = round_int(tt);

	s  = t%60l; t/=60l;
	mm = t%60l;
	h  = t/60l;

  return TDateTime( y, m, d, h, mm, s, 0);
}
//---------------------------------------------------------------------------
double dt2mj( double dd)
{
  ushort    Year=0, Month=0, Day=0, Hour=0, Minute=0, Second=0, ms;
  TDateTime dt = dd;


	dt.DecodeDate( &Year, &Month, &Day);
	dt.DecodeTime( &Hour, &Minute, &Second, &ms);

	if( Month > 2 ) Month -= 3;
	else
	{
	   Month += 9;
	   Year--;
	}

  long   c  = Year/100l;
  long   ya = Year-100l*c;
  double jd, FracDay = Hour / 24.0 + Minute / 1440.0 + Second / 86400.0;

	jd = (146097l*c)/4l+(1461l*ya)/4l+(153l*Month+2l)/5l+Day+1721119l-2415019l;
	jd += FracDay;

   return jd;
}
//---------------------------------------------------------------------------

