#include "MobileService.h"
#include <CtrlLib/CtrlLib.h>
#include "Calculation.h"
#include "EditorLayout.h"

/**
 * Main application entry point
 * Initializes UTF-8 character set and runs the MobileService application
 */
GUI_APP_MAIN {
	SetDefaultCharset(CHARSET_UTF8);
	MobileService().Run();
}

/**
 * Saves application settings to INI file
 * Writes paths and configuration values to settings.ini in executable folder
 */
void MobileServiceSettings::Save() {
	String ss = WinPath(GetExeFolder() + "\\settings.ini");
	FileOut f(ss);
	if (f) {
		f.PutLine(PathToTopo);
		f.PutLine(PathToMorpho);
		f.PutLine(PathToBorders);
		f.PutLine(LastPathForOpeningDialog);
		f.PutLine(AsString(MaxCalcDistance));
	}
	f.Close();
}

/**
 * Loads application settings from INI file
 * Reads paths and configuration values, sets defaults if files don't exist
 */
void MobileServiceSettings::Load() {
	FileIn f(WinPath(GetExeFolder() + "\\settings.ini"));
	try{
		if (f) {
			PathToTopo = f.GetLine();
			if (!DirectoryExists(PathToTopo)) PathToTopo = GetExeFolder();
			PathToMorpho = f.GetLine();
			if (!DirectoryExists(PathToMorpho)) PathToMorpho = GetExeFolder();
			PathToBorders = f.GetLine();
			if (!DirectoryExists(PathToBorders)) PathToBorders = GetExeFolder();
			LastPathForOpeningDialog = f.GetLine();
			if (!DirectoryExists(LastPathForOpeningDialog)) LastPathForOpeningDialog = GetExeFolder();
			String maxD = f.GetLine();
			if (maxD.IsEmpty()) maxD = "500";
			MaxCalcDistance = ScanInt(maxD);
		}
	}catch(...){

	}
	f.Close();

	if (PathToTopo.IsEmpty()) PathToTopo = "c:\\Maps\\Topo\\";
	if (PathToMorpho.IsEmpty()) PathToMorpho = "c:\\Maps\\Morpho\\";
	if (PathToBorders.IsEmpty()) PathToBorders = "c:\\Maps\\Border\\";
	if (LastPathForOpeningDialog.IsEmpty()) LastPathForOpeningDialog = GetExeFolder();
	MaxCalcDistance = std::min(AcceptedMaxCalculateDistanceKm, std::max(AcceptedMinCalculateDistanceKm, MaxCalcDistance));

	FileWithCountriesCodes = WinPath(GetExeFolder() + "\\Files\\ListOfCountries.txt");
}

/**
 * Stations tab dialog constructor
 * Initializes the stations management interface
 */
StationsTabDlg::StationsTabDlg() {
	typedef StationsTabDlg CLASSNAME;
	CtrlLayout(*this);
}

/**
 * Updates map display options based on user selections
 * Applies topographic, morphologic, and Google map visibility settings
 */
void MapsTabDlg::ChangeOptions() {
	map.options.showTopo = optionTopo;
	map.options.showMorpho = optionMorpho;
	map.options.showDegreeLines = optionDegLines;
	map.options.showGoogleHybrid = optionGoogleHybrid;
	map.options.showGoogle = optionGoogle;
	Refresh();
}

/**
 * Maps tab dialog constructor
 * Sets up map display with status bar and real-time coordinate updates
 */
MapsTabDlg::MapsTabDlg() {
	typedef MapsTabDlg CLASSNAME;
	CtrlLayout(*this);
	AddFrame(statusBar);

	statusBar.AddFrame(infoLongLati.Right(250));
	statusBar.AddFrame(infoZoom.Right(90));
	statusBar.AddFrame(infoTopo.Right(110));
	statusBar.AddFrame(infoMorpho.Right(90));
	statusBar = "[ctrl] to show Height at point. [shift] to Distance. [double click][+ctrl] generate Heigth/Morpho Map";

	SetTimeCallback(-100, [=] {
		String txt = CoordinateToString(map.PointMoveGrad);
		txt.Insert(8, " ");
		txt += "  " + FormatDouble(map.PointMoveGrad.x, 8) << " " << FormatDouble(map.PointMoveGrad.y, 8);
		infoLongLati.Set(txt);
		infoZoom = "Zoom = " + AsString(map.zoom);
		infoTopo = "Height = " + AsString(map.lastTopo);
		infoMorpho = "Morpho = " + AsString(map.lastMorpho);
	});

	optionTopo.WhenAction = optionMorpho.WhenAction = optionGoogle.WhenAction =
		optionDegLines.WhenAction = optionGoogleHybrid.WhenAction = THISBACK(ChangeOptions);
}

/**
 * Stations test dialog constructor
 * Initializes the test stations management interface
 */
StationsTestDlg::StationsTestDlg() {
	typedef StationsTestDlg CLASSNAME;
	CtrlLayout(*this);

}

/**
 * Results layout for line calculations constructor
 * Sets up the display for line mode calculation results
 */
ResultsLayoutDlgLine::ResultsLayoutDlgLine() {
	typedef ResultsLayoutDlgLine CLASSNAME;
	CtrlLayout(*this);
	SetDarkThemeEnabled(false);
}

/**
 * Results layout for point-to-point calculations constructor
 * Sets up the display for P2P mode calculation results
 */
ResultsLayoutDlgP2p::ResultsLayoutDlgP2p() {
	typedef ResultsLayoutDlgP2p CLASSNAME;
	CtrlLayout(*this);
	SetDarkThemeEnabled(false);
}

/**
 * Results layout for CBR calculations constructor
 * Sets up the display for CBR mode calculation results
 */
ResultsLayoutDlgCbr::ResultsLayoutDlgCbr() {
	typedef ResultsLayoutDlgCbr CLASSNAME;
	CtrlLayout(*this);
	SetDarkThemeEnabled(false);
}

/**
 * Combined results layout constructor
 * Sets up the interface for combining all calculation results
 */
ResultLayoutDlgCombine::ResultLayoutDlgCombine() {
	typedef ResultLayoutDlgCombine CLASSNAME;
	CtrlLayout(*this);
	SetDarkThemeEnabled(false);
}

/**
 * Generates a unique filename for a new station file
 * @param iReferenceStation: true for reference stations, false for test stations
 * @return String: Unique filename with sequential numbering
 */
String MobileService::GetNewStationFileName(bool iReferenceStation) {
	String fname = "", path = pathTest;
	if (iReferenceStation) path = pathRef;

	for (int i = 1; i <= 99999999; i++) {
		fname = path + "Station_" + Format("%08d", i) + ".txt";
		if (!FileExists(fname)) return fname;
	}
	return path + ToUpper("Station_0.txt");
}

/**
 * Checks and loads country codes list file
 * Creates default country codes file if it doesn't exist
 */
void MobileService::CheckAndLoadCountriesCodes(){
	if (!FileExists(cnfg.FileWithCountriesCodes)) {

	    String defaultFilePath = AppendFileName(AppendFileName(GetFileFolder(GetExeFilePath()), "file"), "ListOfCountries.txt");
	    RealizePath(GetFileDirectory(defaultFilePath));
	    FileOut file(defaultFilePath);
	    if (file.IsOpen()) {
	        file << "AFS\nZA1\nAGL\nAO1\nALG\nBDI\nBEN\nBFA\nBOT\nCAF\n"
	             << "CME\nCOD\nCOG\nCOM\nCPV\nCTI\nDJI\nEGY\nERI\nETH\n"
	             << "GAB\nGHA\nGMB\nGNB\nGNE\nGQ1\nGUI\nKEN\nLBR\nLBY\n"
	             << "LSO\nMAU\nMDG\nMLI\nMOZ\nMRC\nMTN\nMWI\nNGR\nNIG\n"
	             << "NMB\nRRW\nSDN\nSEN\nSEY\nSOM\nSRL\nSSD\nSTP\nSWZ\n"
	             << "TCD\nTGO\nTUN\nTZA\nTZ1\nUGA\nZMB\nZWE\n";
	        file.Close();
	    }
	    cnfg.FileWithCountriesCodes = defaultFilePath;
	}
	LoadFileToDropList(cnfg.FileWithCountriesCodes, tabResLine.lineLandTo);
}

/**
 * Prepares the line calculation results layout
 * Initializes UI controls and event handlers for line mode
 */
void MobileService::PrepareResultLayoutLine(){
	CheckAndLoadCountriesCodes();
	
	
	tabResLine.lineLandTo.SetIndex(0);
	tabResLine.lineLandTo.SetIndex(0);
	tabResLine.lineCross.SetText("6");
	tabResLine.linePermFS.SetText("0");
	tabResLine.lineCross2.SetText("0");
	tabResLine.linePermFS2.SetText("0");
	tabResLine.Line2CheckBox = true;
	tabResLine.CorrectionCheckBox = true;
	tabResLine.Line2CheckBox << [=] {
		tabResLine.lineCross2.Enable(tabResLine.Line2CheckBox);
		tabResLine.linePermFS2.Enable(tabResLine.Line2CheckBox);
	};
	tabResLine.drlLine.Clear();
	tabResLine.drlLine
		.Add("-9 = P2L non strict HCM t%=10 h2=3")
		.Add("-10 = P2L non strict HCM t%=10 h2=10")
		.Add("-11 = P2L non strict HCM t%=50 h2=3")
		.SetIndex(0);
	tabResLine.statusLabel.AlignCenter();
	tabResLine.statusLabel.SetFont(fnt);
	tabResLine.statusLabel.SetInk(textColor);
	tabResLine.statusLabel.SetText("The calculation results are published here.");
	tabResLine.BtnLine << [=] {
		tabResLine.BtnLine.Enable(false);
		tabResLine.statusLabel.SetText("The calculation results for Line mode");
		CalculationLine();
		tabResLine.BtnLine.Enable(true);
	};
	tabResLine.BtnClearTable << [=]{
		ClearResultTableLine();
	};
	tabResLine.BtnSaveToExcel << [=]{
		SaveTableToExcel(tabResLine.table, 23);
	};
	tabResLine.BtnSaveToJson.Hide();
	tabResLine.BtnSaveToJson << [=]{
		SaveTableToJson(tabResLine.table, 23);
	};
	tabResLine.table.WhenLeftDouble << [=] {
		int num = tabResLine.table.GetCursor();
		if (debugFiles.GetCount() == 0) return;
		if (num > debugFiles.GetCount() - 1) return;
		WinExec("notepad " + debugFiles[num], SW_SHOW);
	};
	tabResLine.table.OddRowColor(Color(255, 255, 191), Black());
	tabResLine.table.EvenRowColor(Color(220, 236, 249), Black());

}

/**
 * Prepares the point-to-point calculation results layout
 * Initializes UI controls and event handlers for P2P mode
 */
void MobileService::PrepareResultLayoutP2p(){
	tabResP2p.p2pPermFS.SetText("0");
	tabResP2p.p2pDepolLoss.SetText("0");
	tabResP2p.drlPointToPoint.Clear();
	tabResP2p.drlPointToPoint.Add("0 = normal Agreement")
		.Add("10 = P2P non strict HCM t%=10")
		.Add("11= P2P non strict HCM t%=50")
		.Add("12 = P2P non strict HCM t%=1")
		.SetIndex(0);
	tabResP2p.statusLabel.AlignCenter();
	tabResP2p.statusLabel.SetFont(fnt);
	tabResP2p.statusLabel.SetInk(textColor);
	tabResP2p.statusLabel.SetText("The calculation results are published here.");

	tabResP2p.BtnPtoP << [=] {
		tabResP2p.BtnPtoP.Enable(false);
		tabResP2p.statusLabel.SetText("The calculation results for P2P mode");
		CalculationP2p();
		tabResP2p.BtnPtoP.Enable(true);
	};

	tabResP2p.BtnSaveToExcel << [=]{
		SaveTableToExcel(tabResP2p.table, 23);

	};
	tabResP2p.BtnClearTable << [=]{
		ClearResultTableP2p();
	};
	tabResP2p.BtnSaveToJson.Hide();
	tabResP2p.BtnSaveToJson << [=]{
		SaveTableToJson(tabResP2p.table, 23);
	};
	tabResP2p.table.WhenLeftDouble << [=] {
		int num = tabResP2p.table.GetCursor();
		if (debugFiles.GetCount() == 0) return;
		if (num > debugFiles.GetCount() - 1) return;
		WinExec("notepad " + debugFiles[num], SW_SHOW);
	};
	tabResP2p.table.OddRowColor(Color(255, 255, 191), Black());
	tabResP2p.table.EvenRowColor(Color(220, 236, 249), Black());
}

/**
 * Prepares the CBR calculation results layout
 * Initializes UI controls and event handlers for CBR mode
 */
void MobileService::PrepareResultLayoutCbr(){

	LoadFileToDropList(cnfg.FileWithCountriesCodes, tabResCbr.cbrLandTo);
	tabResCbr.cbrLandTo.SetIndex(0);
	tabResCbr.cbrLandTo.SetIndex(0);
	tabResCbr.cbrCross.SetText("6");
	tabResCbr.cbrPermFS.SetText("0");
	tabResCbr.drlCbr.Clear();
	tabResCbr.drlCbr.Add("-1 = Coordination line calculation (h2 = 10m)")
		.Add("-9 = P2L non strict HCM t%=10 h2=3")
		.Add("-10 = P2L non strict HCM t%=10 h2=10")
		.Add("-11 = P2L non strict HCM t%=50 h2=3")
		.SetIndex(0);
	tabResCbr.statusLabel.AlignCenter();
	tabResCbr.statusLabel.SetFont(fnt);
	tabResCbr.statusLabel.SetInk(textColor);
	tabResCbr.statusLabel.SetText("The calculation results are published here.");
	tabResCbr.BtnCbr << [=] {
		tabResCbr.BtnCbr.Enable(false);
		tabResCbr.statusLabel.SetText("The calculation results for CBR mode");
		CalculationCbr();
		tabResCbr.BtnCbr.Enable(true);
	};
	tabResCbr.BtnClearTable << [=]{
		ClearResultTableCbr();
	};
	tabResCbr.BtnSaveToExcel << [=]{
		SaveTableToExcel(tabResCbr.table, 23);
	};
	tabResCbr.BtnSaveToJson.Hide();
	tabResCbr.BtnSaveToJson << [=]{
		SaveTableToJson(tabResCbr.table, 23);
	};
	tabResCbr.table.WhenLeftDouble << [=] {
		int num = tabResCbr.table.GetCursor();
		if (debugFiles.GetCount() == 0) return;
		if (num > debugFiles.GetCount() - 1) return;
		WinExec("notepad " + debugFiles[num], SW_SHOW);
	};
	tabResCbr.table.OddRowColor(Color(255, 255, 191), Black());
	tabResCbr.table.EvenRowColor(Color(220, 236, 249), Black());
}

/**
 * Prepares the combined results layout
 * Initializes UI controls for combining all calculation modes
 */
void MobileService::PrepareResultLayoutCombine(){

	tabResCombine.statusLabel.SetText("Combine results to construct answer");
	tabResCombine.statusLabel.AlignCenter();
	tabResCombine.statusLabel.SetFont(fnt);
	tabResCombine.statusLabel.SetInk(textColor);

	UpdateImageResultsCombineLayout();

	tabResCombine.ImgP2pResultsExists.SetUHDEnabled(false);
	tabResCombine.ImgLineResultsExists.SetUHDEnabled(false);
	tabResCombine.ImgCbrResultsExists.SetUHDEnabled(false);
	tabResCombine.ExceedP2p.SetText("0");
	tabResCombine.ExceedLine.SetText("0");
	tabResCombine.ExceedCbr.SetText("0");

	tabResCombine.text13YJam.ClearList();
	tabResCombine.text13YNoJam.ClearList();

	tabResCombine.text13YJam.Add("A").Add("B").Add("C").Add("D").Add("E")
		.Add("F").Add("G").Add("H").Add("M").Add("P")
		.Add("R").Add("W").Add("Z");

	for (int i = 0; i < tabResCombine.text13YJam.GetCount(); i++) {
		tabResCombine.text13YNoJam.Add(tabResCombine.text13YJam.GetKey(i));
	}

	tabResCombine.text13YJam.SetIndex(tabResCombine.text13YJam.GetCount()-1);
	tabResCombine.text13YNoJam.SetIndex(2);
	tabResCombine.h03.Clear();
	tabResCombine.h03.Add("O");
	tabResCombine.h03.Add("D");
	tabResCombine.h03.Add("N");
	tabResCombine.h03.Add("A");
	tabResCombine.h03.SetIndex(0);

	int widMinimun = 60;
	int widStandart = 140;
	int widMaximum = 240;

	LoadFileToDropList(cnfg.FileWithCountriesCodes, tabResCombine.h11);

	tabResCombine.h01.MaxChars(2);
	tabResCombine.h02.MaxChars(80);
	tabResCombine.h04.MaxChars(3);
	tabResCombine.h05.MaxChars(40);
	tabResCombine.h06.MaxChars(20);
	tabResCombine.h07.MaxChars(20);
	tabResCombine.h08.MaxChars(20);
	tabResCombine.h09.MaxChars(6);
	tabResCombine.h10.MaxChars(8);
	tabResCombine.h12.MaxChars(3);
	tabResCombine.h13.MaxChars(7);

	int wSmall = 30, wMiddle = 60, wLarge=100, wNote = 160;

	EditString ed;
	tabResCombine.Table.SetEditable(true);
	tabResCombine.Table.Editing();

	tabResCombine.Table.AddColumn("№", wSmall, 0);
	tabResCombine.Table.AddColumn("4A name of station", wNote, 1);
	tabResCombine.Table.AddColumn("2W date of request", wMiddle, 2);
	tabResCombine.Table.AddColumn("13Z remarks", wNote, 3).Edit(ed);
	tabResCombine.Table.AddColumn("13Y status of coor", wSmall, 4);
	tabResCombine.Table.AddColumn("4B country", wMiddle, 5);
	tabResCombine.Table.AddColumn("4C coordinates", wLarge, 6);
	tabResCombine.Table.AddColumn("1A txFreq", wLarge, 7);


	tabResCombine.Table.AddColumn("1Y rxFreq", wLarge, 8);
	tabResCombine.Table.AddColumn("1Z freq category", wMiddle, 9);
	tabResCombine.Table.AddColumn("6A class", wMiddle, 10);
	tabResCombine.Table.AddColumn("6B service", wMiddle, 11);
	tabResCombine.Table.AddColumn("6Z categ of use", wMiddle, 12);
	tabResCombine.Table.AddColumn("10Z ch.occup", wMiddle, 13);
	tabResCombine.Table.AddColumn("2C date of use", wMiddle, 14);
	tabResCombine.Table.AddColumn("4Z height sea", wMiddle, 15);
	tabResCombine.Table.AddColumn("7A emission", wLarge, 16);
	tabResCombine.Table.AddColumn("8B1 power", wMiddle, 17);
	tabResCombine.Table.AddColumn("8B2 type ant", wMiddle, 18);
	tabResCombine.Table.AddColumn("9A azim", wMiddle, 19);
	tabResCombine.Table.AddColumn("9B elev", wMiddle, 20);
	tabResCombine.Table.AddColumn("9D polar", wMiddle, 21);
	tabResCombine.Table.AddColumn("9G gain", wMiddle, 22);
	tabResCombine.Table.AddColumn("9Y height ground", wMiddle, 23);
	tabResCombine.Table.AddColumn("9XH ant horiz", wMiddle, 24);
	tabResCombine.Table.AddColumn("9XV ant vert", wMiddle, 25);
	tabResCombine.Table.AddColumn("2Z data or coord", wMiddle, 26);
	tabResCombine.Table.AddColumn("13Y coord reference", wMiddle, 27);
	tabResCombine.Table.AddColumn("4D radius", wMiddle, 27);

	tabResCombine.Table.SetEditable(true);
	tabResCombine.Table.Editing();

	tabResCombine.Table.HorzScroll().Enable(true);
	tabResCombine.Table.VertScroll().Enable(true);
	tabResCombine.Table.AutoHideSb(false);
	tabResCombine.Table.AutoHideHorzSb(false);
	tabResCombine.Table.AutoHideVertSb(false);

	tabResCombine.BtnClearTable << [=]{
		ClearResultTableCombine();
	};
	tabResCombine.BtnSaveToFile << [=]{

		String typesForResult = "Station Txt format (*.txt)\t*.txt\nStation JSON format (*.json)\t*.json\nStation Excel (*.xlsx)\t*.xlsx";
		fsSaveStations.ClearTypes();
		fsSaveStations.Types(typesForResult);
		fsSaveStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsSaveStations.ExecuteSaveAs()) {
			String ext = ToUpper(GetFileExt(fsSaveStations.GetFile(0)));
			if (ext == ".JSON"){
				ConvertStationFileToJSON(fsSaveStations.GetFile(0), ResultResponceData);
			}else if (ext == ".XLSX"){
				ConvertStationFileToExcel(fsSaveStations.GetFile(0), ResultResponceData);
			} else {
				ConvertJSONToStationFile(fsSaveStations.GetFile(0), ResultResponceData);
			}
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsSaveStations.GetFile(0));
			cnfg.Save();
		}
		fsSaveStations.ClearTypes();
		fsSaveStations.Types(cnfg.ExtensionsForRecordSave);
	};

	tabResCombine.BtnUpdate << [=]{
		LoadeStationFileData();

		if (flagCbrCalcDone == false & flagLineCalcDone == false & flagP2pCalcDone == false ){
			Prompt(Null, 0, "Error", CtrlImg::error(), "No calculations were made", true, "Ok");
			return;
		};
		double levelP2p = tabResCombine.ExceedP2p;
		double levelCbr = tabResCombine.ExceedCbr;
		double levelLine = tabResCombine.ExceedLine;
		String letterJam = tabResCombine.text13YJam.GetData().ToString();
		String letterNoJam = tabResCombine.text13YNoJam.GetData().ToString();


		Array<String> uStations;

		auto AddUnique = [&](const String& s) {
			for(int i = 0; i < uStations.GetCount(); ++i) {
				if (uStations[i] == s) return;
			}
			uStations.Add(Trim(s));
		};

		for (int i=0; i<tabResP2p.table.GetCount(); ++i){AddUnique(tabResP2p.table.Get(i,1));};
		for (int i=0; i<tabResLine.table.GetCount(); ++i){AddUnique(tabResLine.table.Get(i,1));};
		for (int i=0; i<tabResCbr.table.GetCount(); ++i){AddUnique(tabResCbr.table.Get(i,1));};

		for (int j=0; j<ResultResponceData.stations.GetCount(); ++j){
			ResultResponceData.stations[j]._13Z = "";
			ResultResponceData.stations[j]._13Y = letterNoJam;
		}

		if (flagP2pCalcDone & tabResCombine.ChBAddP2p){
			for (int j=0; j<uStations.GetCount(); ++j){
				double maxP2p = 1001;
				for (int i=0; i<tabResP2p.table.GetCount(); ++i){
					if (Trim(tabResP2p.table.Get(i,1)) != uStations[j]) continue;
					double level = ScanDouble(tabResP2p.table.Get(i,20).ToString());
					if (level<maxP2p){
						maxP2p = level;
					}
				};
				for (int i=0; i<ResultResponceData.stations.GetCount(); ++i){
					if (Trim(ResultResponceData.stations[i]._4A) != uStations[j]) continue;
					if (maxP2p < levelP2p){
						ResultResponceData.stations[i]._13Z = Trim(ResultResponceData.stations[i]._13Z) + "P2P=" +AsString(maxP2p)+";";
						ResultResponceData.stations[i]._13Y = letterJam;
					}
					break;
				}
			}
		}

		if (flagLineCalcDone & tabResCombine.ChBAddLine){
			for (int j=0; j<uStations.GetCount(); ++j){
				double maxLine = 1001;
				for (int i=0; i<tabResLine.table.GetCount(); ++i){
					if (Trim(tabResLine.table.Get(i,1)) != uStations[j]) continue;
					double level = ScanDouble(tabResLine.table.Get(i,20).ToString());
					if (level<maxLine){
						maxLine = level;
					}
				};
				for (int i=0; i<ResultResponceData.stations.GetCount(); ++i){
					if (Trim(ResultResponceData.stations[i]._4A) != uStations[j]) continue;
					if (maxLine < levelLine){
						ResultResponceData.stations[i]._13Z = Trim(ResultResponceData.stations[i]._13Z) + "Line=" +AsString(maxLine)+";";
						ResultResponceData.stations[i]._13Y = letterJam;
					}
					break;
				}
			}
		}
		if (flagCbrCalcDone & tabResCombine.ChBAddCrb){
			for (int j=0; j<uStations.GetCount(); ++j){
				double maxCbr = 1001;
				for (int i=0; i<tabResCbr.table.GetCount(); ++i){
					if (Trim(tabResCbr.table.Get(i,1)) != uStations[j]) continue;
					double level = ScanDouble(tabResCbr.table.Get(i,20).ToString());
					if (level<maxCbr){
						maxCbr = level;
					}
				};
				for (int i=0; i<ResultResponceData.stations.GetCount(); ++i){
					if (Trim(ResultResponceData.stations[i]._4A) != uStations[j]) continue;
					if (maxCbr < levelCbr){
						ResultResponceData.stations[i]._13Z = Trim(ResultResponceData.stations[i]._13Z) + "Cbr=" +AsString(maxCbr)+";";
						ResultResponceData.stations[i]._13Y = letterJam;
					}
					break;
				}
			}
		}
		if (UpdateResCombineStationFileData() == false){
			return;
		}
	};



}

/**
 * Initializes all result layouts for different calculation modes
 * Calls individual preparation methods for Line, P2P, CBR and Combine layouts
 */
void MobileService::PrepareResultLayouts() {
	PrepareResultLayoutLine();
	PrepareResultLayoutP2p();
	PrepareResultLayoutCbr();
	PrepareResultLayoutCombine();
}

/**
 * Updates the status indicators for calculation results in combine layout
 * Shows which calculation modes have completed results available
 */
void MobileService::UpdateImageResultsCombineLayout(){
	tabResCombine.ImgP2pResultsExists.SetImage( flagP2pCalcDone ? CtrlImg::Add() : CtrlImg::Remove());
	tabResCombine.ImgLineResultsExists.SetImage( flagLineCalcDone ? CtrlImg::Add() : CtrlImg::Remove());
	tabResCombine.ImgCbrResultsExists.SetImage( flagCbrCalcDone ? CtrlImg::Add() : CtrlImg::Remove());
	tabResCombine.ChBAddP2p = flagP2pCalcDone;
	tabResCombine.ChBAddLine = flagLineCalcDone;
	tabResCombine.ChBAddCrb = flagCbrCalcDone;

}

/**
 * Clears point-to-point calculation results table
 * Resets the P2P calculation completion flag
 */
void MobileService::ClearResultTableP2p(){
	tabResP2p.table.Clear();
	flagP2pCalcDone = false;
	UpdateImageResultsCombineLayout();
};

/**
 * Clears line calculation results table
 * Resets the line calculation completion flag
 */
void MobileService::ClearResultTableLine(){
	tabResLine.table.Clear();
	flagLineCalcDone = false;
	UpdateImageResultsCombineLayout();
};

/**
 * Clears CBR calculation results table
 * Resets the CBR calculation completion flag
 */
void MobileService::ClearResultTableCbr(){
	tabResCbr.table.Clear();
	flagCbrCalcDone = false;
	UpdateImageResultsCombineLayout();
};

/**
 * Clears combined results table
 * Removes all entries from the combine results display
 */
void MobileService::ClearResultTableCombine(){
	tabResCombine.Table.Clear();
};

/**
 * Clears all result tables
 * Resets all calculation results and completion flags
 */
void MobileService::ClearResultTablesAll(){
	ClearResultTableP2p();
	ClearResultTableLine();
	ClearResultTableCbr();
	ClearResultTableCombine();
};

/**
 * Loads station data from file into memory
 * @return bool: true if stations were loaded successfully, false otherwise
 */
bool MobileService::LoadeStationFileData(){
	tabResCombine.Table.Clear();

	String fileName = pathTest + "stations.txt";

	if (!ParseFixedLengthFile(fileName, ResultResponceData)) {
		Prompt(Null, 0, "Error", CtrlImg::error(), "No stations available", true, "Ok");
		return false;
	} else return true;

}

/**
 * Updates the combined results table with station data
 * @return bool: true if data was updated successfully
 */
bool MobileService::UpdateResCombineStationFileData(){

	tabResCombine.h01.SetData(Trim(ResultResponceData.header.H01)); // File number on media
	tabResCombine.h02.SetData(Trim(ResultResponceData.header.H02)); // File contents
	tabResCombine.h03.SetData(Trim(ResultResponceData.header.H03)); // File contents code
	tabResCombine.h04.SetData(Trim(ResultResponceData.header.H04)); // Originating country
	tabResCombine.h05.SetData(Trim(ResultResponceData.header.H05));// E-mail address
	tabResCombine.h06.SetData(Trim(ResultResponceData.header.H06));// Phone
	tabResCombine.h07.SetData(Trim(ResultResponceData.header.H07)); // Telefax
	tabResCombine.h08.SetData(Trim(ResultResponceData.header.H08));// Name of responsible person
	tabResCombine.h09.SetData(AsString(ResultResponceData.stations.GetCount()));// Number of records

		String tmp = ResultResponceData.header.H10.ToString();
		int tmp1 = ScanInt(tmp.Mid(0,2));
		int tmp2 = ScanInt(tmp.Mid(2,2));
		int tmp3 = ScanInt(tmp.Mid(4,4));
		if(IsNull(tmp1) || IsNull(tmp2) || IsNull(tmp3)){
			StationEditor.h10.SetText("");
		}else{
			tabResCombine.h10.SetDate(tmp3, tmp2, tmp1);
		};// Writing date

	tabResCombine.h11.SetData(Trim(ResultResponceData.header.H11));// Destination country
	tabResCombine.h12.SetData(Trim(ResultResponceData.header.H12)); // Unique file number
	tabResCombine.h13.SetData(Trim(ResultResponceData.header.H13));// File version
	tabResCombine.h14.SetData(Trim(ResultResponceData.header.H14));// Reserved for future use
	
	// Make some changes
	// Change Dest and Source coutries
	String ss = tabResCombine.h11.GetData().ToString();
	tabResCombine.h11.SetData(tabResCombine.h04.GetData());
	tabResCombine.h04.SetData(ss);
	// clear data, phone email
	tabResCombine.h05.Clear();
	tabResCombine.h06.Clear();
	tabResCombine.h07.Clear();
	tabResCombine.h08.Clear();
	tabResCombine.h03.SetData("A");
	
	Date today = GetSysDate();
	//(int y, int m, int d)
	tabResCombine.h10.SetDate(today.year, today.month, today.day);

	

	tabResCombine.Table.SetRowCount(ResultResponceData.stations.GetCount());
	for (int i = 0; i < ResultResponceData.stations.GetCount(); i++) {
		tabResCombine.Table.Set(i,0,AsString(i+1));
		tabResCombine.Table.Set(i,1,ResultResponceData.stations[i]._4A);
		tabResCombine.Table.Set(i,2,ResultResponceData.stations[i]._2W);
		tabResCombine.Table.Set(i,3,ResultResponceData.stations[i]._13Z);
		tabResCombine.Table.Set(i,4,ResultResponceData.stations[i]._13Y);
		tabResCombine.Table.Set(i,5,ResultResponceData.stations[i]._4B);
		tabResCombine.Table.Set(i,6,ResultResponceData.stations[i]._4C);
		tabResCombine.Table.Set(i,7,ResultResponceData.stations[i]._1A);
		tabResCombine.Table.Set(i,8,ResultResponceData.stations[i]._1Y);

		tabResCombine.Table.Set(i,9,ResultResponceData.stations[i]._1Z);
		tabResCombine.Table.Set(i,10,ResultResponceData.stations[i]._6A);
		tabResCombine.Table.Set(i,11,ResultResponceData.stations[i]._6B);
		tabResCombine.Table.Set(i,12,ResultResponceData.stations[i]._6Z);
		tabResCombine.Table.Set(i,13,ResultResponceData.stations[i]._10Z);
		tabResCombine.Table.Set(i,14,ResultResponceData.stations[i]._2C);
		tabResCombine.Table.Set(i,15,ResultResponceData.stations[i]._4Z);
		tabResCombine.Table.Set(i,16,ResultResponceData.stations[i]._7A);
		tabResCombine.Table.Set(i,17,ResultResponceData.stations[i]._8B1);
		tabResCombine.Table.Set(i,18,ResultResponceData.stations[i]._8B2);
		tabResCombine.Table.Set(i,19,ResultResponceData.stations[i]._9A);
		tabResCombine.Table.Set(i,20,ResultResponceData.stations[i]._9B);
		tabResCombine.Table.Set(i,21,ResultResponceData.stations[i]._9D);
		tabResCombine.Table.Set(i,22,ResultResponceData.stations[i]._9G);
		tabResCombine.Table.Set(i,23,ResultResponceData.stations[i]._9Y);
		tabResCombine.Table.Set(i,24,ResultResponceData.stations[i]._9XH);
		tabResCombine.Table.Set(i,25,ResultResponceData.stations[i]._9XV);
		tabResCombine.Table.Set(i,26,ResultResponceData.stations[i]._2Z);
		tabResCombine.Table.Set(i,27,ResultResponceData.stations[i]._13Y);
		tabResCombine.Table.Set(i,28,ResultResponceData.stations[i]._4D);
	}
	return true;
}

/**
 * Creates the main application menu
 * @param bar: Reference to the menu bar to populate
 */
void MobileService::MainMenu(Bar& bar) {
	bar.Add("Paths", [=] { SettingsLO.Execute(); });
	bar.Add("About", [=] { AboutApp(); });
	bar.Add("Exit", [=] { Close(); });
}

/**
 * Displays the about dialog with application information
 * Shows version, copyright and description
 */
void MobileService::AboutApp(){
	WithAboutDlg<TopWindow> dlg;
	CtrlLayoutCancel(dlg, t_("About CalcMS4A"));

	dlg.image.SetImage(Images::icon96x96);
	Font fnt = StdFont().Height(18);
	String aboutStr = String() << "HCM software is used for co-ordination of mobile service stations according to HCM4A-Agreement";
	aboutStr << "\n\nVersion: " << APP_VERSION;
	aboutStr << "\nCopyrite © \"International Telecommunication Union (ITU)\"";
	dlg.richText.SetQTF(DeQtf(aboutStr));
	dlg.Execute();
}

/**
 * Refreshes application settings and updates map data paths
 * Reloads geographic data if paths have changed
 */
void MobileService::RefreshSettings() {

	SettingsLO.EdBorderPath.SetText(cnfg.PathToBorders);
	SettingsLO.EdTopoPath.SetText(cnfg.PathToTopo);
	SettingsLO.EdMorphoPath.SetText(cnfg.PathToMorpho);
	cnfg.MaxCalcDistance = std::min(AcceptedMaxCalculateDistanceKm, std::max(AcceptedMinCalculateDistanceKm, cnfg.MaxCalcDistance));

	SettingsLO.EdMaxCalcDistKm.SetText(AsString(cnfg.MaxCalcDistance));

	bool flag = !PathIsEqual(tabMap.map.geodata.pathToBorders, cnfg.PathToBorders) ||
				!PathIsEqual(tabMap.map.geodata.pathToMorpho, cnfg.PathToMorpho) ||
				!PathIsEqual(tabMap.map.geodata.pathToTopo, cnfg.PathToTopo);

	tabMap.map.geodata.pathToBorders = cnfg.PathToBorders;
	tabMap.map.geodata.fileWithCountriesCodes = cnfg.FileWithCountriesCodes;
	tabMap.map.geodata.pathToMorpho = cnfg.PathToMorpho;
	tabMap.map.geodata.pathToTopo = cnfg.PathToTopo;
	tabMap.map.ter.PathToTopo = cnfg.PathToTopo;
	tabMap.map.ter.PathToMorpho = cnfg.PathToMorpho;

	cnfg.Save();

	if (flag) {
		tabMap.map.geodata.LoadGeoData();
	}
}

/**
 * Prepares the settings dialog interface
 * Sets up event handlers for path selection and configuration acceptance
 */
void MobileService::PrepareSettings() {
	SettingsLO.BtnBorderPath << [=] {
		faSettings.Set(cnfg.PathToBorders + "\\need.this");
		if (faSettings.ExecuteSelectDir("Choose folder with Borders [*.ALL; *.000 etc.]")) {
			cnfg.PathToBorders = PutSepToEndPath(faSettings.Get().Mid(0, 163));
			RefreshSettings();
		}
	};
	SettingsLO.BtnMorphoPath << [=] {
		faSettings.Set(cnfg.PathToMorpho + "\\need.this");
		if (faSettings.ExecuteSelectDir("Choose folder with MORPHO maps [*.33M *.63M]")) {
			cnfg.PathToMorpho = PutSepToEndPath(faSettings.Get().Mid(0, 163));
			RefreshSettings();
		}
	};
	SettingsLO.BtnTopoPath << [=] {
		faSettings.Set(cnfg.PathToTopo + "\\need.this");
		if (faSettings.ExecuteSelectDir("Choose folder with TOPO maps [*.33E *.63E]")) {
			cnfg.PathToTopo = PutSepToEndPath(faSettings.Get().Mid(0, 163));
			RefreshSettings();
		}
	};
	SettingsLO.Accept << [=] {
		cnfg.MaxCalcDistance = SettingsLO.EdMaxCalcDistKm;
		cnfg.Save();
		SettingsLO.Close();
	};
	SettingsLO.Deny << [=] {
		SettingsLO.Close();
	};

}

/**
 * Recursively finds files matching specified mask in directory
 * @param directory: Path to search in
 * @param mask: File pattern to match
 * @param result: Array to store found file paths
 */
void MobileService::FindFiles(const String& directory, const String& mask, Array<String>& result) {
	FindFile ff(AppendFileName(directory, "*"));
	while (ff) {
		String fullPath = AppendFileName(directory, ff.GetName());
		if (ff.IsFile() && PatternMatchMulti(mask, ff.GetName())) {
			result.Add(ToUpper(fullPath));
		} else if (ff.IsFolder() && ff.GetName() != "." && ff.GetName() != "..") {
			FindFiles(fullPath, mask, result);
		}
		ff.Next();
	}
}

/**
 * Reads station data from file and adds to StationsList
 * @param filename: Path to station file
 * @param index: Index in file list
 * @param isRefList: true if reference station, false if test station
 */
void MobileService::ReadFileWithStation(String filename, int index, bool isRefList) {
	int countStations = GetCountStationsInFile(filename);
	MobileStation station;
	int offet = 0;
	Pointf pnt;
	String allString;

	for (int i = 0; i < countStations; i++) {
		try {
			allString = ReadStationFromFile(filename, i);

			station.Name = TrimLeft(TrimRight(allString.Mid(offet + 28, 20)));
			isRefList ? station.Filename = ListRefStationFiles[index] : station.Filename = ListTestStationFiles[index];
			station.isRefList = isRefList;
			station.IndexInFile = i;
			pnt = ReadCoordinate(allString.Mid(offet + 51, 15));
			station.Longitude = pnt.x;
			station.Latitude = pnt.y;
			try {
				station.Azimut = ScanDouble(allString.Mid(offet + 91, 5));
			} catch (...) {
				station.Azimut = 0;
			}
			try {
				station.Heigth = ScanDouble(allString.Mid(offet + 107, 4));
			} catch (...) {
				station.Heigth = 0;
			}
			station.FreqTx = ReadFreq(allString.Mid(offet + 0, 12));
			station.FreqRx = ReadFreq(allString.Mid(offet + 125, 12));
			station.Land = allString.Mid(offet + 48, 3);
			try {
				station.Radius = ScanDouble(allString.Mid(offet + 66, 5));
			} catch (...) {
				station.Radius = 0;
			}
			StationsList.Add(station);
		} catch (...) {
			// Handle exceptions
		}
	}
}

/**
 * Reads all station files from reference and test directories
 * Populates the StationsList with all available stations
 */
void MobileService::ReadAllFileStations() {
	String fname = "";
	StationsList.Clear();

	int countPathToStations = WinPath(pathRef).ToString().GetCount();
	tabStations.RefTable.Clear();
	for (int i = 0; i < ListRefStationFiles.GetCount(); i++) {
		fname = ListRefStationFiles.At(i);
		ReadFileWithStation(fname, i, true);
	}

	for (int i = 0; i < ListTestStationFiles.GetCount(); i++) {
		fname = ListTestStationFiles.At(i);
		ReadFileWithStation(fname, i, false);
	}
}

/**
 * Prepares the map tree control for station navigation
 * Sets up event handlers for tree item selection
 */
void MobileService::PrepareMapTree() {
	tabMap.optionResults = true;
	tabMap.map.showResults = true;
	tabMap.optionResults.WhenAction = [=] {
		tabMap.map.showResults = tabMap.optionResults;
		tabMap.map.Refresh();

	};
	tabMap.mapTree.WhenCursor = [=] {

		int cur = tabMap.mapTree.GetCursor();
		if (cur < 0) return;

		for (int i = 0; i < mapTreeCoordArray.GetCount(); i++) {
			if (mapTreeCoordArray[i].id != cur) continue;
			tabMap.map.LookAt(mapTreeCoordArray[i].longitude, mapTreeCoordArray[i].latitude, mapTreeCoordArray[i].zoom);
			break;
		}
	};
}

/**
 * Refreshes the map tree with current station and line data
 * Updates the navigation tree with stations and calculation results
 */
void MobileService::RefreshMapTree() {
	tabMap.mapTree.Clear();
	tabMap.mapTree.SetRoot(Null, "");
	tabMap.mapTree.Open(0);

	tabMap.mapTree.Add(0, Null, "Stations");


	mapTreeCoordArray.Clear();

	MapStation mapS;
	tabMap.map.MapStation.Clear();
	for (int i = 0; i < StationsList.GetCount(); i++) {
		mapS.Longitude = StationsList[i].Longitude;
		mapS.Latitude = StationsList[i].Latitude;
		mapS.Azimut = StationsList[i].Azimut;
		mapS.Name = StationsList[i].Name;
		mapS.Radius = StationsList[i].Radius;
		mapS.isRef = StationsList[i].isRefList;
		tabMap.map.MapStation.Add(mapS);
	}
	tabMap.map.MapLines.clear();
	MapLine mp;
	for (int i = 0; i < LinesOnMap.GetCount(); i++) {
		mp.LineColor = LinesOnMap[i].LineColor;
		mp.Name = LinesOnMap[i].Name;
		mp.Points.clear();
		mp.Points.Append(LinesOnMap[i].Points);
		tabMap.map.MapLines.Add(pick(mp));
	}


	int refTree = tabMap.mapTree.Add(1, Null, "Reference list");
	int testTree = tabMap.mapTree.Add(1, Null, "Test list");
	int id;
	for (int i = 0; i < StationsList.GetCount(); i++) {
		if (StationsList[i].isRefList) {
			id = tabMap.mapTree.Add(refTree, Null, StationsList[i].Name);
		} else {
			id = tabMap.mapTree.Add(testTree, Null, StationsList[i].Name);
		}
		mapTreeCoordArray.Add(mapCoord{ id, StationsList[i].Longitude, StationsList[i].Latitude, 12 });
	}

	int linesTree = tabMap.mapTree.Add(0, Null, "Results");
	for (int i = 0; i < LinesOnMap.GetCount(); i++) {
		id = tabMap.mapTree.Add(linesTree, Null, LinesOnMap[i].Name);
		mapTreeCoordArray.Add(mapCoord{ id, LinesOnMap[i].Points[0].x, LinesOnMap[i].Points[0].y, 12 });
	}

	tabMap.mapTree.Open(1);
	tabMap.mapTree.Open(refTree);
	tabMap.mapTree.Open(testTree);
	tabMap.mapTree.Open(linesTree);
}

/**
 * Prepares the stations list management interface
 * Sets up table columns and event handlers for station operations
 */
void MobileService::PrepareStationsLists() {
	TreeCtrl::Node node;
	node.Set("Stations");
	tabMap.mapTree.SetRoot(node);

	tabStations.RefTable.Clear();
	tabStations.RefTable.AddColumnAt(0, "№", 20);
	tabStations.RefTable.AddColumnAt(1, "Station name", 120);
	tabStations.RefTable.AddColumnAt(2, "Coordinates", 120);
	tabStations.RefTable.AddColumnAt(3, "Country", 30);
	tabStations.RefTable.AddColumnAt(4, "Tx freq [MHz]", 40);
	tabStations.RefTable.AddColumnAt(5, "Rx freq [MHz]", 40);
	tabStations.RefTable.AddColumnAt(6, "Azimuth [grad]", 40);
	tabStations.RefTable.AddColumnAt(7, "Ant. height [m]", 40);
	tabStations.RefTable.AddColumnAt(8, "Radius [km]", 40);
	tabStations.RefTable.OddRowColor(Color(255, 255, 191), Black());
	tabStations.RefTable.EvenRowColor(Color(220, 236, 249), Black());

	tabStationsTest.TestTable.OddRowColor(Color(255, 255, 191), Black());
	tabStationsTest.TestTable.EvenRowColor(Color(220, 236, 249), Black());

	tabStationsTest.TestTable.Clear();
	for (int i = 0; i < tabStations.RefTable.GetColumnCount(); i++)
		tabStationsTest.TestTable.AddColumn(tabStations.RefTable.ColumnAt(i).HeaderTab().GetText());
	tabStationsTest.TestTable.ColumnWidths(tabStations.RefTable.GetColumnWidths());

	tabStations.RefTable.WhenLeftDouble << [=] {
		int num = tabStations.RefTable.GetCursor();
		if (num >= 0) ShowStationEditor(11, num);
		RefreshStationsLists();
	};

	tabStations.BtnOpen << [=] {
		fsLoadStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsLoadStations.ExecuteOpen()) {
			String ext = ToUpper(GetFileExt(fsLoadStations.GetFile(0)));
			if (ext == ".JSON"){
				ConvertJSONToStationFile(fsLoadStations.GetFile(0), pathRef + "stations.txt");
			}else if (ext == ".XLSX"){
				ConvertExcelToStationFile(fsLoadStations.GetFile(0), pathRef + "stations.txt");
			} else {
				FileCopy(fsLoadStations.GetFile(0), pathRef + "stations.txt");
			}
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsLoadStations.GetFile(0));
			cnfg.Save();
		}
		RefreshStationsLists();
	};
	tabStations.BtnSave << [=] {
		fsSaveStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsSaveStations.ExecuteSaveAs()) {
			String ext = ToUpper(GetFileExt(fsSaveStations.GetFile(0)));
			if (ext == ".JSON"){
				ConvertStationFileToJSON(pathRef + "stations.txt", fsSaveStations.GetFile(0));
			}else if (ext == ".XLSX"){
				ConvertStationFileToExcel(pathRef + "stations.txt", fsSaveStations.GetFile(0));
			} else {
				FileCopy(pathRef + "stations.txt", fsSaveStations.GetFile(0));
			}
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsSaveStations.GetFile(0));
			cnfg.Save();
		}
		RefreshStationsLists();
	};

	tabStations.BtnNew << [=] {
		AddEmptyStationToFile(pathRef + "stations.txt");
		RefreshStationsLists();
	};

	tabStations.BtnClear << [=] {
		DeleteFileA(pathRef + "stations.txt");
		RefreshStationsLists();
	};
	tabStations.BtnAppend << [=] {
		fsSaveStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsSaveStations.ExecuteOpen()) {
			MergeFilesWithStations(pathRef + "stations.txt", fsSaveStations.GetFile(0));
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsSaveStations.GetFile(0));
			cnfg.Save();
		}
		RefreshStationsLists();
	};
	tabStations.BtnCopy << [=] {
		if (!FileExists(pathRef + "stations.txt")) return;
		int num = tabStations.RefTable.GetCursor();
		if (num < 0) return;

		DuplicateIndexStationToFile(pathRef + "stations.txt",num);
		RefreshStationsLists();
	};
	tabStations.BtnDelete1 << [=] {
		int num = tabStations.RefTable.GetCursor();
		if (num >= 0) DeleteStationFromFile(pathRef + "stations.txt", num);
		RefreshStationsLists();
	};

	tabStationsTest.TestTable.WhenLeftDouble << [=] {
		int num = tabStationsTest.TestTable.GetCursor();
		if (num >= 0) ShowStationEditor(21, num);
		RefreshStationsLists();
	};

	tabStationsTest.BtnOpen << [=] {
		fsLoadStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsLoadStations.ExecuteOpen()) {
			String ext = ToUpper(GetFileExt(fsLoadStations.GetFile(0)));
			if (ext == ".JSON"){
				ConvertJSONToStationFile(fsLoadStations.GetFile(0), pathTest + "stations.txt");
			}else if (ext == ".XLSX"){
				ConvertExcelToStationFile(fsLoadStations.GetFile(0), pathTest + "stations.txt");
			} else {
				FileCopy(fsLoadStations.GetFile(0), pathTest + "stations.txt");
			}
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsLoadStations.GetFile(0));
			cnfg.Save();
		}
		RefreshStationsLists();
	};
	tabStationsTest.BtnSave << [=] {
		fsSaveStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsSaveStations.ExecuteSaveAs()) {
			String ext = ToUpper(GetFileExt(fsSaveStations.GetFile(0)));
			if (ext == ".JSON"){
				ConvertStationFileToJSON(pathTest + "stations.txt", fsSaveStations.GetFile(0));
			}else if (ext == ".XLSX"){
				ConvertStationFileToExcel(pathTest + "stations.txt", fsSaveStations.GetFile(0));
			} else {
				FileCopy(pathTest + "stations.txt", fsSaveStations.GetFile(0));
			}
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsSaveStations.GetFile(0));
			cnfg.Save();
		}
		RefreshStationsLists();
	};
	tabStationsTest.BtnClear << [=] {
		DeleteFileA(pathTest + "stations.txt");
		RefreshStationsLists();
	};
	tabStationsTest.BtnNew << [=] {
		AddEmptyStationToFile(pathTest + "stations.txt");
		RefreshStationsLists();
	};
	tabStationsTest.BtnCopy << [=] {
		if (!FileExists(pathTest + "stations.txt")) return;
		int num = tabStationsTest.TestTable.GetCursor();
		if (num < 0) return;

		DuplicateIndexStationToFile(pathTest + "stations.txt",num);
		RefreshStationsLists();
	};
	tabStationsTest.BtnDelete1 << [=] {
		int num = tabStationsTest.TestTable.GetCursor();
		if (num >= 0) DeleteStationFromFile(pathTest + "stations.txt", num);
		RefreshStationsLists();
	};
	tabStationsTest.BtnAppend << [=] {
		fsSaveStations.ActiveDir(cnfg.LastPathForOpeningDialog);
		if (fsSaveStations.ExecuteOpen()) {
			MergeFilesWithStations(pathTest + "stations.txt", fsSaveStations.GetFile(0));
			cnfg.LastPathForOpeningDialog = GetFileFolder(fsSaveStations.GetFile(0));
			cnfg.Save();
		}
		RefreshStationsLists();
	};
}

/**
 * Refreshes the stations lists display
 * Reloads all station files and updates the UI tables
 */
void MobileService::RefreshStationsLists() {
	ListRefStationFiles.Clear();
	ListTestStationFiles.Clear();
	FindFiles(pathRef, "*.txt", ListRefStationFiles);
	FindFiles(pathTest, "*.txt", ListTestStationFiles);

	ReadAllFileStations();

	tabMap.mapTree.Clear();

	tabStations.RefTable.Clear();
	tabStationsTest.TestTable.Clear();

	int countRef = 0, countTest = 0;
	String coord = "";
	for (int i = 0; i < StationsList.GetCount(); i++) {
		coord = CoordinateToString(Pointf(StationsList[i].Longitude, StationsList[i].Latitude));
		coord.Insert(8, " ");
		if (StationsList[i].isRefList) {
			countRef++;
			tabStations.RefTable.Add(
				countRef,
				StationsList[i].Name,
				Format("%.6mf", StationsList[i].Longitude) + "   " +
				Format("%.6mf", StationsList[i].Latitude) + "\t\t" + coord,
				StationsList[i].Land,
				(StationsList[i].FreqTx > 0) ? AsString(StationsList[i].FreqTx) : "",
				(StationsList[i].FreqRx > 0) ? AsString(StationsList[i].FreqRx) : "",
				AsString(StationsList[i].Azimut),
				AsString(StationsList[i].Heigth),
				AsString(StationsList[i].Radius)
			);
		} else {
			countTest++;
			tabStationsTest.TestTable.Add(
				countTest,
				StationsList[i].Name,
				Format("%.6mf", StationsList[i].Longitude) + "   " +
				Format("%.6mf", StationsList[i].Latitude) + "\t\t" + coord,
				StationsList[i].Land,
				(StationsList[i].FreqTx > 0) ? AsString(StationsList[i].FreqTx) : "",
				(StationsList[i].FreqRx > 0) ? AsString(StationsList[i].FreqRx) : "",
				AsString(StationsList[i].Azimut),
				AsString(StationsList[i].Heigth),
				AsString(StationsList[i].Radius)
			);
		}
	}
	RefreshMapTree();
	ClearResultTablesAll();
}

/**
 * Closes the application
 * Terminates the program execution
 */
void MobileService::Close(){
	std::abort();
}

/**
 * MobileService main constructor
 * Initializes all application components, UI, and data structures
 */
MobileService::MobileService() {
	fnt.Height(22);
	textColor = Color(94, 33, 41);

	SetDarkThemeEnabled(false);

	PrepareSettings();
	cnfg.Load();
	pathRef = WinPath(GetExeFolder() + "\\Stations\\RefList\\");
	pathTest = WinPath(GetExeFolder() + "\\Stations\\TestList\\");

	RefreshSettings();

	PrepareResultLayouts();

	if (!FileExists(cnfg.FileWithCountriesCodes)) {
		ErrorOK("NO FILE WITH COUNTRIES CODES. TRY TO RE-INSTALL PROGRAM");
		Close();
	}

	fsLoadStations.Types(cnfg.ExtensionsForRecordLoad);
	fsSaveStations.Types(cnfg.ExtensionsForRecordSave);

	AddFrame(menu);
	menu.Set([=](Bar& bar) { MainMenu(bar); });

	CtrlLayout(*this, "CalcMS4A version " + APP_VERSION);
	Zoomable(true).Sizeable().SetMinSize(Size(800, 600));
	SetRect(Size(1400, 800));

	mainTab.SizePos();
	mainTab.Add(tabStationsTest.SizePos(), "Test List");
	mainTab.Add(tabStations.SizePos(), "Reference List");
	mainTab.Add(tabMap.SizePos(), "Maps");
	mainTab.Add(tabResP2p.SizePos(), "Calculations Point to Point");
	mainTab.Add(tabResLine.SizePos(), "Calculations Line");
	mainTab.Add(tabResCbr.SizePos(), "Calculations CBR");
	mainTab.Add(tabResCombine.SizePos(), "Combine results");

	s.tabheight = 30;
	s.font = StdFont().Height(18);
	int h  = s.tabheight + s.sel.top + s.sel.bottom;

	Image img = CreateImage(Size(2,2), Color(255, 255, 150));
	Image img2 = CreateImage(Size(2,2), White());

	s.normal[CTRL_PRESSED] = img;
	s.first[CTRL_PRESSED] = img;
	s.last[CTRL_PRESSED] = img;
	s.both[CTRL_PRESSED] = img;


	mainTab.SetStyle(s);
	mainTab.WhenAction = [=] {
		int current = mainTab.Get();  
		String tabLabel = mainTab.GetItem(current).GetText();
		if (tabLabel == "Maps") {
		}
		else if (tabLabel == "Calculations") {
		}
	};


	mainTab.SetDarkThemeEnabled(false);
	tabResP2p.SetDarkThemeEnabled(false);
	tabResLine.SetDarkThemeEnabled(false);
	tabResCbr.SetDarkThemeEnabled(false);
	tabMap.SetDarkThemeEnabled(false);
	tabStationsTest.SetDarkThemeEnabled(false);


	CtrlLayout(SettingsLO, t_("Settings"));
	CtrlLayout(StationEditor, t_("Station Editor"));

	PrepareMapTree();

	PrepareStationsLists();
	RefreshStationsLists();

	tabMap.map.LookAt(-21, 28, 4);

	PrepareStationEditor();
	SetStationDefault();


	SetDateFormat("%3:02d/%2:02d/%1:4d");
	SetDateScan("dmy");
}