//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "THelper.h"
#include <IdSSLOpenSSL.hpp>
#pragma package(smart_init)
TFormatSettings _fmtHelper = TFormatSettings::Create(GetThreadLocale());
TRezultatOperacije<AnsiString> *THelper::ProcitajJSON(AnsiString sekcija, AnsiString kljuc,
	AnsiString fajl)
{
	if (!FileExists(fajl))
	{
		bool nasao = false;
		if (ContainsText(fajl, "confIT.json"))
		{
			if (FileExists("c:\\bus\\c11\\confIT.json"))
			{
				nasao = true;
				fajl = "c:\\bus\\c11\\confIT.json";
            }

		}
		if (!nasao)
		{
			return new TRezultatOperacije<AnsiString>(false, "", "Fajl " + fajl + " nije pronadjen.");
        }
	}
	try
	{
		std::unique_ptr<TStringStream> jsonStream(new TStringStream);
		jsonStream->LoadFromFile(fajl);
		TJSONObject *jsonReader = (TJSONObject*)TJSONObject::ParseJSONValue(jsonStream->DataString);
		TJSONObject *sekcijaJSON = (TJSONObject*)jsonReader->GetValue(sekcija);
		if (sekcijaJSON == nullptr)
		{
            delete jsonReader;
			jsonStream->Clear();
			return new TRezultatOperacije<AnsiString>(false, "", "Sekcija " + sekcija + " ne postoji u fajlu " + fajl);
		}

		TJSONValue *vrednost = sekcijaJSON->GetValue(kljuc);
		if (vrednost == nullptr)
		{
            delete jsonReader;
			jsonStream->Clear();
			return new TRezultatOperacije<AnsiString>(false, "", "Kljuc " + kljuc + " ne postoji unutar sekcije " + sekcija + " u fajlu " + fajl);
		}
		AnsiString temp = sekcijaJSON->GetValue(kljuc)->Value();
		delete jsonReader;
		jsonStream->Clear();
		return new TRezultatOperacije<AnsiString>(true, temp);

	}catch (Exception &ex)
	{
		return new TRezultatOperacije<AnsiString>(false, "", ex.Message);
	}catch (std::exception &ex)
	{
		return new TRezultatOperacije<AnsiString>(false, "", ex.what());
    }
}
//---------------------------------------------------------------------------
TRezultatOperacije<std::vector<AnsiString>> *THelper::ProcitajJSONNiz(AnsiString sekcija, AnsiString kljuc, AnsiString fajl)
{
	std::vector<AnsiString> rezultat;
	if (!FileExists(fajl))
	{
		return new TRezultatOperacije<std::vector<AnsiString>>(false, rezultat, "Fajl " + fajl + " nije pronadjen.");
	}
	try
	{
		std::unique_ptr<TStringStream> jsonStream(new TStringStream);
		jsonStream->LoadFromFile(fajl);
		TJSONObject *jsonReader = (TJSONObject*)TJSONObject::ParseJSONValue(jsonStream->DataString);
		TJSONObject *sekcijaJSON = (TJSONObject*)jsonReader->GetValue(sekcija);
		if (sekcijaJSON == nullptr)
		{
			delete jsonReader;
			jsonStream->Clear();
			return new TRezultatOperacije<std::vector<AnsiString>>(false, rezultat, "Sekcija " + sekcija + " ne postoji u fajlu " + fajl);
		}
		TJSONArray* nizJSON = (TJSONArray*)sekcijaJSON->GetValue(kljuc);
		int broj = nizJSON->Size();
		for (int indeks = 0; indeks < broj; indeks++)
		{
			rezultat.push_back(nizJSON->Get(indeks)->Value());
		}

		if (rezultat.size() > 0)
		{
			delete jsonReader;
			jsonStream->Clear();
			return new TRezultatOperacije<std::vector<AnsiString>>(true, rezultat);
		}else
		{
			delete jsonReader;
			jsonStream->Clear();
			return new TRezultatOperacije<std::vector<AnsiString>>(false, rezultat, "Nema elemenata u list, sekcija: " + sekcija +
				" kljuc: " + kljuc);
        }

	}catch (Exception &ex)
	{
		return new TRezultatOperacije<std::vector<AnsiString>>(false, rezultat, ex.Message);
	}catch (std::exception &ex)
	{
        return new TRezultatOperacije<std::vector<AnsiString>>(false, rezultat, ex.what());
    }
}

//---------------------------------------------------------------------------
UnicodeString THelper::TrenutniDatumCist()
{
	_fmtHelper.DateSeparator = '-';
	_fmtHelper.LongDateFormat = "dd-mm-yyyy";
	_fmtHelper.ShortDateFormat = "dd-mm-yyyy";
	return FormatDateTime("dd-mm-yyyy", Now(), _fmtHelper);
}
//---------------------------------------------------------------------------
TRezultatOperacije<bool> *THelper::PokreniProces(AnsiString putanja, AnsiString fajl)
{
	try
	{
		if (!FileExists(TPath::Combine(putanja, fajl)))
		{
			return new TRezultatOperacije<bool>(false, false);
		}
		PROCESS_INFORMATION procInfo;
		STARTUPINFO startInfo;

		memset(&procInfo, 0, sizeof(procInfo));
		memset(&startInfo, 0, sizeof(startInfo));

		startInfo.cb = sizeof(startInfo);
		UnicodeString fullPath = TPath::Combine(putanja, fajl);
		CreateProcess(fullPath.t_str(), nullptr, nullptr, nullptr, false,
			NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP,
			nullptr, UnicodeString(putanja).t_str(), &startInfo, &procInfo);
		return new TRezultatOperacije<bool>(true, true);
	}catch(...)
	{
		return new TRezultatOperacije<bool>(false, false);
    }
}
//---------------------------------------------------------------------------
TRezultatOperacije<bool> *THelper::UgasiProces(AnsiString naziv_programa)
{
	try
	{
		// Pronađi proces sa zadatim imenom
		HANDLE hProcess = NULL;
		DWORD dwProcessId = 0;
		UnicodeString processName = naziv_programa ;
		PROCESSENTRY32 pe32;
		pe32.dwSize = sizeof(PROCESSENTRY32);
		HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
		if (hSnapshot == INVALID_HANDLE_VALUE)
		{
			return new TRezultatOperacije<bool>(false, false);
		}
		if (Process32First(hSnapshot, &pe32))
		{
			do
			{
				if (processName.CompareIC(pe32.szExeFile) == 0)
				{
					dwProcessId = pe32.th32ProcessID;
					break;
				}
			}
			while (Process32Next(hSnapshot, &pe32));
		}
		CloseHandle(hSnapshot);

		// Ako je proces pronađen, otvori ručicu i ugasi ga
		if (dwProcessId != 0)
		{
			hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
			if (hProcess == NULL)
			{
				return new TRezultatOperacije<bool>(false, false);
			}
			if (!TerminateProcess(hProcess, 0))
			{
				CloseHandle(hProcess);
				return new TRezultatOperacije<bool>(false, false);
			}
			CloseHandle(hProcess);
			return new TRezultatOperacije<bool>(true, true);
		}
		else
		{
		// Ako proces nije pronađen, vrati false
			return new TRezultatOperacije<bool>(false, false);
		}
	}
	catch(...)
	{
		return new TRezultatOperacije<bool>(false, false);
	}
}
//---------------------------------------------------------------------------
TRezultatOperacije<int> *THelper::DohvatiProces(AnsiString naziv, ProcessHandle radnja)
{
	try
	{
		HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
		PROCESSENTRY32 pEntry;
		pEntry.dwSize = sizeof (pEntry);
		BOOL hRes = Process32First(hSnapShot, &pEntry);
		int count = 0;
		while (hRes)
		{
			if (CompareText(pEntry.szExeFile, naziv) == 0)
			{
				HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
											  (DWORD) pEntry.th32ProcessID);
				if (hProcess != NULL)
				{
					count++;
					if (radnja == phKill)
					{
						TerminateProcess(hProcess, 9);
					}
					CloseHandle(hProcess);
				}
			}
			hRes = Process32Next(hSnapShot, &pEntry);
		}
		CloseHandle(hSnapShot);
		return new TRezultatOperacije<int>(true, count);
	} catch (Exception &ex)
	{
		return new TRezultatOperacije<int>(false, 0, ex.Message);
	} catch (std::exception &stdex)
	{
		return new TRezultatOperacije<int>(false, 0, stdex.what());
    }
}
//---------------------------------------------------------------------------

std::unique_ptr<TRezultatOperacije<TFBBaza>> THelper::ProcitajIniFB(bool udaljena)
{
	return ProcitajIniFB(udaljena ? AnsiString("bat_2006") : AnsiString("BAZA2006"));
}

std::unique_ptr<TRezultatOperacije<TFBBaza>> THelper::ProcitajIniFB(AnsiString konekcija)
{
	auto fbRezultat = std::make_unique<TFBBaza>();
	try
	{
		UnicodeString cashITdir = ParamStr(1);
		if (cashITdir.IsEmpty())
		{
			AnsiString exeFile=Application->ExeName;
			cashITdir = ExtractFilePath(exeFile);
		}else
		{
			cashITdir.Delete(1, 2);
		}
		AnsiString dbx = "";
		AnsiString shared = TPath::Combine(TPath::GetSharedDocumentsPath(),
			"Embarcadero\\Studio\\dbExpress\\22.0");
		if (FileExists(TPath::Combine(shared, "dbxconnections.ini")))
		{
			dbx = TPath::Combine(shared, "dbxconnections.ini");
		}else if (FileExists(TPath::Combine(cashITdir, "dbxconnections.ini")))
		{
			dbx = TPath::Combine(cashITdir,"dbxconnections.ini");
		}else
		{
			return std::make_unique<TRezultatOperacije<TFBBaza>>(false, std::move(fbRezultat), "Ne postoji dbxconnections.ini!");
		}
		auto konekcijaFajl = new TIniFile(dbx);
		AnsiString baza = konekcijaFajl->ReadString(konekcija, "Database", "");
		fbRezultat->_server_pun = baza;

		if (baza.IsEmpty())
		{
			try
			{
				ifstream input(dbx.c_str());
				std::string line;
				bool nasaoKonekciju = false;
				if (input.is_open())
				{
					while (getline(input, line))
					{
						if (nasaoKonekciju && 
							line.rfind("Database", 0) == 0)
						{
							AnsiString db = AnsiString(line.c_str());
							baza = SplitString(db, "=")[1].Trim();
							break;
						}else if (line.find("[" + konekcija + "]") != std::string::npos)
						{
							nasaoKonekciju = true;
                        }
					}
				}
			}catch(...){}
			if (baza.IsEmpty()) 
			{
				delete konekcijaFajl;
				return std::make_unique<TRezultatOperacije<TFBBaza>>(false, std::move(fbRezultat),
					"Ne mogu da procitam podatke o " + konekcija + " iz dbxconnections.ini");
			}
		}


		fbRezultat->_lokacijaBaze = "";

		//1. da li je alias sam
		if (SplitString(baza, ":").Length == 1 &&
			SplitString(baza, "/").Length == 1 &&
			SplitString(baza, "\\").Length == 1)
		{
			fbRezultat->_nazivBaze = baza;
			delete konekcijaFajl;
			return std::make_unique<TRezultatOperacije<TFBBaza>>(true, std::move(fbRezultat));
		}
		//2. alias i host
		if (SplitString(baza, ":").Length == 2 &&
			SplitString(baza, "/").Length == 1 &&
			SplitString(baza, "\\").Length == 1)
		{
			auto hostsplit = SplitString(baza, ":");
			//2a. alias, host i port
			if (SplitString(hostsplit[0], "/").Length == 2)
			{
				auto hostPort = SplitString(hostsplit[0], "/");
				fbRezultat->_server = hostPort[0];
				fbRezultat->_port = hostPort[1];
			}else
			{
				fbRezultat->_server = hostsplit[0];
			}
			fbRezultat->_nazivBaze = hostsplit[1];
			fbRezultat->_lokacijaBaze = "";
			delete konekcijaFajl;
			return std::make_unique<TRezultatOperacije<TFBBaza>>(true, std::move(fbRezultat));
		}
		//3. nema host
		if ((SplitString(baza, ":").Length == 2 &&
			SplitString(baza, "\\").Length > 1) || //windows putanja
			SplitString(baza, ":").Length == 1)
		{
			auto dirSplit = SplitString(baza, "\\").Length > 0 ?
				SplitString(baza, "\\") :
				SplitString(baza, "/");

			fbRezultat->_nazivBaze = dirSplit[dirSplit.Length-1];

			char split = '\\';
			if (SplitString(baza, "/").Length > 1)
			{
				split =  '/';
				fbRezultat->_lokacijaBaze = "/";
			}

			for (int dex = 0; dex < dirSplit.Length-1; dex++)
			{
				fbRezultat->_lokacijaBaze = fbRezultat->_lokacijaBaze
					+ dirSplit[dex] + split;
			}
			delete konekcijaFajl;
			return std::make_unique<TRezultatOperacije<TFBBaza>>(true, std::move(fbRezultat));
		}

		//4. ima host
		if (SplitString(baza, ":").Length == 3 ||
			(SplitString(baza, ":").Length == 2 &&
			SplitString(baza, "/").Length > 1))
		{
			auto hostsplit = SplitString(baza, ":");
			//5a. putanja, host i port
			if (SplitString(hostsplit[0], "/").Length == 2)
			{
				auto hostPort = SplitString(hostsplit[0], "/");
				fbRezultat->_server = hostPort[0];
				fbRezultat->_port = hostPort[1];
			}else //5b. putanja i host
			{
				fbRezultat->_server = hostsplit[0];
			}

			auto temp = SplitString(baza, ":");
			auto putanja = temp.Length == 3 ?
				temp[1] + ':' + temp[2] :
				temp[1];

			auto dirSplit = SplitString(putanja, "\\").Length > 1 ?
				SplitString(putanja, "\\") :
				SplitString(putanja, "/");

			fbRezultat->_nazivBaze = dirSplit[dirSplit.Length-1];

			char split = '\\';
			if (SplitString(putanja, "/").Length > 1)
			{
				split =  '/';
				fbRezultat->_lokacijaBaze = "";
			}
			for (int dex = 0; dex < dirSplit.Length-1; dex++)
			{
				fbRezultat->_lokacijaBaze = fbRezultat->_lokacijaBaze
					+ dirSplit[dex] + split;
			}

			delete konekcijaFajl;
			return std::make_unique<TRezultatOperacije<TFBBaza>>(true, std::move(fbRezultat));
		}

        delete konekcijaFajl;
		return std::make_unique<TRezultatOperacije<TFBBaza>>(false, std::move(fbRezultat),
			"Parsiranje dbx nije proslo ok za: " + baza);

	}catch (...)
	{
		return std::make_unique<TRezultatOperacije<TFBBaza>>(false, std::move(fbRezultat), "Problem u citanju konekcije");
	}


}
//---------------------------------------------------------------------------//---------------------------------------------------------------------------
TRezultatOperacije<TFDConnection*> *THelper::NapraviKonekciju(bool udaljeni)
{
	TFDConnection* conn = new TFDConnection(nullptr);
	auto nazivKonekcijeJSON = ProcitajJSON("FB", udaljeni ? "dbKonekcijaUdaljena" : "dbKonekcija");
	if (!nazivKonekcijeJSON->OperacijaUspela())
	{
		AnsiString greska = "Greska pri citanju konfiga1: " + nazivKonekcijeJSON->DohvatiGresku();
		return new TRezultatOperacije<TFDConnection*>(false, conn, greska);
	}

	AnsiString nazivKonekcije = nazivKonekcijeJSON->DohvatiRezultat();
	delete nazivKonekcijeJSON;

	return NapraviKonekciju(nazivKonekcije);

}
//---------
TRezultatOperacije<TFDConnection*> *THelper::NapraviKonekciju(AnsiString nazivKonekcije)
{
    TFDConnection* conn = new TFDConnection(nullptr);
	auto konekcijaIni = ProcitajIniFB(nazivKonekcije);  //izmena
	if (!konekcijaIni->OperacijaUspela())
	{
		AnsiString greska = "Greska pri citanju konfiga2: " + konekcijaIni->DohvatiGresku();
		//delete nazivKonekcijeJSON;
		return new TRezultatOperacije<TFDConnection*>(false, conn, greska);
	}

	auto konekcija = konekcijaIni->DohvatiRezultat();
	try
	{
		conn->LoginPrompt = false;
		conn->DriverName = "FB";
		conn->Params->Add("Server=" +    konekcija.ServerPun() );      // AnsiString test_server = konekcija._server_pun;  //
		conn->Params->Add("Database=" +  konekcija.BazaPunNaziv() );    // konekcija.BazaPunNaziv()   konekcija._server_pun
		conn->Params->Add("User_name=" + konekcija._user);
		conn->Params->Add("Password=" + konekcija._password);
//		conn->Params->Add("Protocol=ipTCPIP" );
//		ShowMessage( "s="+konekcija.ServerPun() + " b=" + konekcija.BazaPunNaziv() );
//		delete nazivKonekcijeJSON;
		return new TRezultatOperacije<TFDConnection*>(true, conn, "");
	}catch (Exception &ex)
	{
//		delete nazivKonekcijeJSON;
		return new TRezultatOperacije<TFDConnection*>(false, conn, ex.Message);
	}catch (std::exception &stdex)
	{
//		delete nazivKonekcijeJSON;
		return new TRezultatOperacije<TFDConnection*>(false, conn, stdex.what());
	}

}
//---------------------------------------------------------------------------
TRezultatOperacije<TCompInfo> *THelper::DohvatiHostInformacije()
{
	TCompInfo compInfo;
	try
	{
		UnicodeString cashITdir = ParamStr(1);
		if (cashITdir.IsEmpty())
		{
			AnsiString exeFile=Application->ExeName;
			cashITdir = ExtractFilePath(exeFile);
		}else
		{
			cashITdir.Delete(1, 2);
		}
		compInfo._dir = cashITdir;
        AnsiString podesavanja = TPath::Combine(cashITdir, "podesavanje");
		if (!DirectoryExists(podesavanja))
		{
			ForceDirectories(podesavanja);
		}

		TIniFile *ini = new TIniFile(TPath::Combine(podesavanja, "settings.ini"));
		AnsiString guidTxt;
		if (ini->ValueExists("Generalno", "GUID"))
		{
			guidTxt = ini->ReadString("Generalno", "GUID", "");
		}else
		{
			TGUID guid;
			CreateGUID(guid);
			guidTxt = Sysutils::GUIDToString(guid);
			ini->WriteString("Generalno", "GUID", Sysutils::GUIDToString(guid));
		}
		compInfo._uid = guidTxt;
		delete ini;

		//Verzija cashIT
		TDateTime modDate = TFile::GetLastWriteTime(TPath::Combine(cashITdir, "CashIT.exe"));
		Word godina, mesec, dan;
		modDate.DecodeDate(&godina, &mesec, &dan);
		compInfo._verzijaMP = Format(L"%04d%02d%02d", ARRAYOFCONST((godina, mesec, dan)));

		//Verzija pSlanje
		if (FileExists(TPath::Combine(cashITdir, "pSlanjePodataka.exe")))
		{
			modDate = TFile::GetLastWriteTime(TPath::Combine(cashITdir, "pSlanjePodataka.exe"));
			modDate.DecodeDate(&godina, &mesec, &dan);
			compInfo._verzijaSinhro = Format(L"%04d%02d%02d", ARRAYOFCONST((godina, mesec, dan)));
		}

		//IP adrese
		auto GStack = new TIdStackWindows();
		TIdStackLocalAddressList *addressList = new TIdStackLocalAddressList();
		GStack->GetLocalAddressList(addressList);
		for (int i = 0; i < addressList->Count; i++)
		{
			if (addressList->Addresses[i]->IPVersion == Id_IPv4)
			{
				compInfo._ipAdrese.push_back(addressList->Addresses[i]->IPAddress);
			}
		}
		delete addressList;
		delete GStack;

		auto connOp = NapraviKonekciju();
		if (!connOp->OperacijaUspela())
		{
			throw Exception(connOp->DohvatiGresku());
		}

		TFDQuery *dbInfo = new TFDQuery(nullptr);
		dbInfo->Connection = connOp->DohvatiRezultat();
		delete connOp;
		dbInfo->SQL->Text = "SELECT FIRST 1 PIB FROM TBLHOST h";
		dbInfo->Open();
		AnsiString pib = dbInfo->FieldByName("PIB")->AsString;
		dbInfo->Close();

		dbInfo->SQL->Text = "select m.magacin from tblmagacin m "
			"right join hp_fiskal f on m.sifra_magacina = f.def_mp_mg;";
		dbInfo->Open();
		AnsiString mag = dbInfo->FieldByName("magacin")->AsString;

		dbInfo->Close();
		dbInfo->SQL->Text = "SELECT * FROM TBLRACUNARI WHERE GUID = '" + compInfo._uid + "'" ;
		dbInfo->Open();
		if (dbInfo->RecordCount == 1)
		{
			compInfo._SinhroDozvoljen = dbInfo->FieldByName("SINHRO_DOZVOLJEN")->AsInteger == 1;
		}
		if (dbInfo->Connection->InTransaction)
		{
			dbInfo->Connection->Rollback();
		}
		dbInfo->Close();
		dbInfo->Unprepare();
		dbInfo->Connection->Close();
		delete dbInfo->Connection;
		dbInfo->Connection = nullptr;

		delete dbInfo;

		compInfo._hostname = getenv("COMPUTERNAME");
		compInfo._pib = pib;
		compInfo._defMagacin = mag;
	}catch (Exception &ex)
	{
		AnsiString greska = "Greska pri citanju iz baze1: " + ex.Message;
		return new TRezultatOperacije<TCompInfo>(false, compInfo, greska);
	}catch (std::exception &stdex)
	{
		AnsiString greska = "Greska pri citanju iz baze2: " + AnsiString(stdex.what());
		return new TRezultatOperacije<TCompInfo>(false, compInfo, greska);
	}
	return new TRezultatOperacije<TCompInfo>(true, compInfo);

}
//---------------------------------------------------------------------------

TRezultatOperacije<double> *THelper::PrazanProstor()
{
	__int64 prazanProstor = DiskFree(0);
	if (prazanProstor != -1)
	{
		double prazno = static_cast<double>(prazanProstor / (1024 * 1024 * 1024));
		return new TRezultatOperacije<double>(true, prazno);
	}
	return new TRezultatOperacije<double>(false, 0, "Greska pri citanju slobodnog prostora");
}
TRezultatOperacije<double> *THelper::VelicinaFajla(AnsiString fajl)
{
	struct stat st;
	if (stat(fajl.c_str(), &st) == 0)
	{
		double velicina = static_cast<double>(st.st_size) / (1024 * 1024 * 1024);
		return new TRezultatOperacije<double>(true, velicina);
	} else
	{
		return new TRezultatOperacije<double>(false, 0, "Greska pri citanju velicine fajla");
	}
}

TRezultatOperacije<AnsiString> *THelper::DeparametrizujUpit(TSQLDataSet *dataset)
{
	try
	{
		AnsiString upitUFulu = dataset->CommandText;
		for (int dex = 0; dex < dataset->Params->Count; dex++)
		{
			upitUFulu = StringReplace(AnsiString(upitUFulu),
				AnsiString(" :" + dataset->Params->Items[dex]->Name + " "),
				AnsiString(" " + dataset->Params->Items[dex]->AsString + " "),
				TReplaceFlags() << rfReplaceAll);
		}
		return new TRezultatOperacije<AnsiString>(true, upitUFulu);
	}catch(Exception &ex)
	{
		return new TRezultatOperacije<AnsiString>(false, "", ex.Message);
	}catch(std::exception &stdex)
	{
		return new TRezultatOperacije<AnsiString>(false, "", stdex.what());
	}catch(...)
	{
		return new TRezultatOperacije<AnsiString>(false, "", "Nepoznada greska pri deparametrizaciji upita.");
    }
}

TRezultatOperacije<TJSONArray*> *THelper::RezultatJSON(TClientDataSet *upit)
{
	TJSONArray *niz = new TJSONArray();
	AnsiString greska = "";

	char LDecimalSeparator  		= FormatSettings.DecimalSeparator;
	char LThousandSeparator 		= FormatSettings.ThousandSeparator;
	String lOldDateFormat  = FormatSettings.ShortDateFormat;
	char lOldDateSeparator = FormatSettings.DateSeparator;
	FormatSettings.ShortDateFormat = "mm/dd/yyyy";
	FormatSettings.DateSeparator = '/';
	FormatSettings.DecimalSeparator  = '.';
	FormatSettings.ThousandSeparator = ',';

	try
	{
		if (!upit->Active)
		{
			upit->Open();
		}else
		{
			upit->First();
		}

		while(!upit->Eof)
		{
			TJSONObject *red = new TJSONObject();
			for (auto polje : upit->Fields )
			{
				if (polje->IsNull)
				{
					 continue;
				}
				switch (polje->DataType)
				{
					case ftInteger:
					case ftSmallint:
					case ftLargeint:
						red->AddPair(polje->FieldName, new TJSONNumber(polje->AsInteger));
						break;

					case ftFloat:
						red->AddPair(polje->FieldName, new TJSONNumber(polje->AsFloat));
						break;
					case ftBCD:
					case ftFMTBcd:
					{
						TBcd bcdValue = polje->AsBCD;
						Currency currValue;
						BCDToCurr(bcdValue, currValue);
						double dabl = static_cast<double>(currValue);
						red->AddPair(polje->FieldName, new TJSONNumber(dabl));
						break;
					}
					case ftDate:
					{
						_fmtHelper.DateSeparator = '/';
						_fmtHelper.TimeSeparator = ':';
						_fmtHelper.LongDateFormat = "mm/dd/yyyy";
						_fmtHelper.ShortDateFormat = "mm/dd/yyyy";
						_fmtHelper.LongTimeFormat = "hh:nn";
						_fmtHelper.ShortTimeFormat = "hh:nn";

						TDateTime dateTimeValue = polje->AsDateTime;
						AnsiString fVreme;
						fVreme = FormatDateTime("mm/dd/yyyy", dateTimeValue, _fmtHelper);
						red->AddPair(polje->FieldName, new TJSONString(fVreme));
						break;
					}
					case ftTime:
					case ftDateTime:
					case ftTimeStamp:
					{
						_fmtHelper.DateSeparator = '/';
						_fmtHelper.TimeSeparator = ':';
						_fmtHelper.LongDateFormat = "mm/dd/yyyy";
						_fmtHelper.ShortDateFormat = "mm/dd/yyyy";
						_fmtHelper.LongTimeFormat = "hh:nn";
						_fmtHelper.ShortTimeFormat = "hh:nn";

						TDateTime dateTimeValue = polje->AsDateTime;
						AnsiString fVreme;

//						if (dateTimeValue == TDateTime(dateTimeValue.Date))
//						{
//							fVreme = FormatDateTime("mm/dd/yyyy", dateTimeValue, _fmtHelper);
//						}
//						else
//						{
							fVreme = FormatDateTime("mm/dd/yyyy hh:nn", dateTimeValue, _fmtHelper);
//						}
						red->AddPair(polje->FieldName, new TJSONString(fVreme));
						break;
					}
					case ftString:
						red->AddPair(polje->FieldName, new TJSONString( escapeSpecialCharacters(polje->AsString) ));
						break;

					default:
					{
						int fieldTypeInt = static_cast<int>(polje->DataType);
						String err = IntToStr(fieldTypeInt);
						throw Exception("Ne mogu da parsiram tip sa id-em: " + err);
						break;
					}
				}
			}
			niz->AddElement(red);
			upit->Next();
		}
		FormatSettings.DecimalSeparator = LDecimalSeparator;
		FormatSettings.ThousandSeparator = LThousandSeparator;
		FormatSettings.DateSeparator   = lOldDateSeparator;
		FormatSettings.ShortDateFormat = lOldDateFormat;
		return new TRezultatOperacije<TJSONArray*>(true, niz);
	}catch(Exception &ex)
	{
		greska = "Greska pri prevodu cdsa u JSON: " + ex.Message;
	}catch (std::exception &stdex)
	{
		greska = "Greska pri prevodu cdsa u JSON: " + AnsiString(stdex.what());
	}catch(...)
	{
		greska = "Greska pri prevodu cdsa u JSON";
	}
	FormatSettings.DecimalSeparator = LDecimalSeparator;
	FormatSettings.ThousandSeparator = LThousandSeparator;
	FormatSettings.DateSeparator   = lOldDateSeparator;
    FormatSettings.ShortDateFormat = lOldDateFormat;
	return new TRezultatOperacije<TJSONArray*>(false, niz, greska);


}

TRezultatOperacije<TJSONObject*> *THelper::PostAPI(AnsiString server, AnsiString api, TJSONObject *sadrzaj, std::map<AnsiString, AnsiString> hederi)
{
	TIdHTTP *http1 = nullptr;
	TIdSSLIOHandlerSocketOpenSSL *ssl = nullptr;

	try {
		 http1 = new TIdHTTP(NULL);


		if (ContainsText(server, "https")) {
		   ssl = new TIdSSLIOHandlerSocketOpenSSL(nullptr);
		   http1->IOHandler = ssl;
		   ssl->SSLOptions->Method = sslvTLSv1_2;
		}

		http1->Request->ContentType = "application/json";
		for (const auto& kv : hederi)
		{
			http1->Request->CustomHeaders->Values[kv.first] = kv.second;

		}
		http1->Request->CharSet = "utf-8";
		bool uspeh = false;
		AnsiString greska = "";
		TJSONObject *jsonObject = nullptr;
		
		TStringStream *jsonStream = new TStringStream(sadrzaj->ToString());
		TStringStream *responseStream = new TStringStream(UnicodeString(""));
		try
		{
			AnsiString full = server + api;

			http1->Post(full, jsonStream, responseStream);

			TJSONValue *jsonValue = TJSONObject::ParseJSONValue(responseStream->DataString);
			jsonObject = dynamic_cast<TJSONObject*>(jsonValue);

			if (jsonObject == nullptr)
			{
				jsonObject = new TJSONObject();
				delete jsonValue;
			}
			uspeh = true;
		}catch(Exception &ex)
		{
			greska = ex.Message;
		}catch (std::exception &stdex)
		{
			greska = stdex.what();
		}catch(...)
		{
			greska = "Greska pri slanju zahteva na Rest API";
		}

		delete jsonStream;
		delete responseStream;
		return new TRezultatOperacije<TJSONObject*>(uspeh, jsonObject, greska);

	} catch (...) {
		delete ssl;
		delete http1;
		throw;
	}
}

TRezultatOperacije<bool> *THelper::ProveraAPI()
{
	bool rezultat = false;
	bool uspeh = false;
	AnsiString greska = "";
	try
	{
		std::unique_ptr<TFDQuery> provera = std::make_unique<TFDQuery>(nullptr);
		provera->Connection = NapraviKonekciju()->DohvatiRezultat();
		provera->SQL->Text = "SELECT FIRST 1 REST_API FROM TBLHOST";

		provera->Open();
		rezultat = provera->FieldByName("REST_API")->AsInteger == 1;


		if (provera->Connection->InTransaction)
		{
			provera->Connection->Rollback();
		}
		provera->Unprepare();
		provera->Connection->Close();
		provera->Close();
		delete provera->Connection;
		provera->Connection = nullptr;
		provera.reset();


		uspeh = true;
	}catch(Exception &ex)
	{
		greska = ex.Message;
	}catch (std::exception &stdex)
	{
		greska = stdex.what();
	}catch(...)
	{
		greska = "Greska pri proveri Rest API vrednosti u tblhost.";
	}
	return new TRezultatOperacije<bool>(uspeh, rezultat, greska);
}

String THelper::escapeSpecialCharacters(String input) {
	String escaped;
	for (int i = 1; i <= input.Length(); ++i) {
		switch (input[i]) {
			case '\"': escaped += "\\\""; break;
			case '\\': escaped += "\\\\"; break;
			case '\b': escaped += "\\b"; break;
			case '\f': escaped += "\\f"; break;
			case '\n': escaped += "\\n"; break;
			case '\r': escaped += "\\r"; break;
			case '\t': escaped += "\\t"; break;
			default:
			if (input[i] >= 0 && input[i] <= 31) {
				escaped += "\\u" + IntToHex(static_cast<int>(input[i]), 4);
			} else {
				escaped += input[i];
			}
		}
	}
	return escaped;
}

TRezultatOperacije<bool> *THelper::UpdateLokalniInfo(TCompInfo info)
{
	bool rezultat = false;
	bool uspeh = false;
	AnsiString greska = "";

	try
	{
		AnsiString ipRed = "";
		for (const auto& ip : info._ipAdrese)
		{
			if (!ipRed.IsEmpty())
			{
				ipRed += "|";
			}
			ipRed += ip;
		}

		std::unique_ptr<TFDQuery> provera = std::make_unique<TFDQuery>(nullptr);
		provera->Connection = NapraviKonekciju()->DohvatiRezultat();
		provera->SQL->Text = "SELECT * FROM TBLRACUNARI WHERE GUID = '" + info._uid + "'" ;
		provera->Open();

		if (provera->RecordCount == 0)
		{
			provera->Close();
			provera->SQL->Text = "INSERT INTO TBLRACUNARI "
				"(GUID, VERZIJA_MP, VERZIJA_SINHRO, NAZIV_RACUNARA, IP) "
				"VALUES ('" + info._uid + "', '" + info._verzijaMP + "', '" + info._verzijaSinhro +
				"', '" + info._hostname + "', '" + ipRed + "'); ";
			provera->ExecSQL();
		}else
		{
			int brojIzmena = provera->FieldByName("INFO_BROJ_PROMENA")->AsInteger;
			AnsiString stariNaziv = "";
			AnsiString stariIP = "";
			if (CompareText(provera->FieldByName("NAZIV_RACUNARA")->AsString, info._hostname) != 0 ||
				CompareText(provera->FieldByName("IP")->AsString, ipRed) != 0)
			{
				stariNaziv = provera->FieldByName("NAZIV_RACUNARA")->AsString;
				stariIP = provera->FieldByName("IP")->AsString;
				brojIzmena++;
			}
			provera->Close();
			provera->SQL->Text = "UPDATE TBLRACUNARI "
				"SET VERZIJA_MP = '" + info._verzijaMP + "', VERZIJA_SINHRO = '" + info._verzijaSinhro +
				"', NAZIV_RACUNARA = '" + info._hostname + "', IP = '" + ipRed + "', INFO_BROJ_PROMENA = " + IntToStr(brojIzmena) +
				", STARI_NAZIV = '" + stariNaziv + "', STARI_IP = '" + stariIP + "' "
				" WHERE GUID = '" + info._uid + "'; ";
			provera->ExecSQL();
		}

		if (provera->Connection->InTransaction)
		{
			provera->Connection->Rollback();
		}
		provera->Unprepare();
		provera->Connection->Close();
		provera->Close();
		delete provera->Connection;
		provera->Connection = nullptr;
		provera.reset();


		uspeh = true;
        rezultat = true;
	}catch(Exception &ex)
	{
		greska = ex.Message;
	}catch (std::exception &stdex)
	{
		greska = stdex.what();
	}catch(...)
	{
		greska = "Greska pri proveri Rest API vrednosti u tblhost.";
	}


	return new TRezultatOperacije<bool>(uspeh, rezultat, greska);
}

TRezultatOperacije<float> *THelper::ZauzetoRadne(bool privatna)
{
	float ram = 0;
	bool uspeh = false;
	if (privatna)
	{
		PROCESS_MEMORY_COUNTERS_EX pmcex;
		if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmcex, sizeof(pmcex)))
		{
			ram = pmcex.PrivateUsage / (1024.0 * 1024.0);
			uspeh = true;
		}
	}else
	{
        PROCESS_MEMORY_COUNTERS pmc;
		if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
		{
			ram = pmc.WorkingSetSize / (1024.0 * 1024.0);
            uspeh = true;
		}
	}
	return new TRezultatOperacije<float>(uspeh, ram, "");
}
