#ifndef _FormCalcHCM_FormCalcHCM_h
#define _FormCalcHCM_FormCalcHCM_h

#include <Core/Core.h>
#include <CtrlLib/CtrlLib.h>
#include <DropGrid/DropGrid.h>
#include <SqlCtrl/SqlCtrl.h>
#include <GridCtrl/GridCtrl.h>
#include <Functions4U/Functions4U.h>

using namespace Upp;


#ifdef C_UMK
	// to compile from umk with flag C_UMK
	#define APP_PATH CalcFS4A
#else
	// **** !!! to compile from IDE **** !!!
	#define APP_PATH _HCM4A/CalcFS4A
#endif
//!--------------------------------------------

#define LAYOUTFILE <APP_PATH/app.lay>
#include <CtrlCore/lay.h>
#define IMAGECLASS Images
#define IMAGEFILE <APP_PATH/app.iml>
#include <Draw/iml.h>
//!--------------------------------------------

#ifdef PLATFORM_WIN32
	#define DLLFILENAME "hcm4afs.dll"
#else
	#define DLLFILENAME "hcm4afs.so"
#endif
//!--------------------------------------------

#include "dtHcmData.h"
#include "dtHcmDll.h"

HcmErrorMap appErrorMap;

#define DLIHEADER   <APP_PATH/hcm4afs.dli>
#define DLIMODULE   Hcm4AfsDll
#include <Core/dli.h>
//!--------------------------------------------

#include "appCfg.h"
#include "ctrlHcmPack.h"
#include "common.h"
#include "ctrlCalc.h"
#include "ctrlReport.h"
#include "dtCalc.h"
#include "dtSingle.h"
#include "dtMult.h"
#include "dtTriger.h"
#include "ctrlGIS.h"


//!--------------------------------------------
 
const String APP_VERSION = "2.6.3";
const String APP_LST_DIR = "Data";
//!--------------------------------------------

enum class AppCalcMode {NONE, SINGL, MULT};
//!--------------------------------------------


class FormEditHCM : public WithFrmEditHCM<TopWindow>{
public:
	typedef FormEditHCM CLASSNAME;
	bool isShow;
	void BeforeFrmShow(const String& nameCtrl, VectorMap<String, String>& sMap);
	void BeforeFrmClose(const String& nameCtrl, VectorMap<String, String>& sMap);
	void Serialize(Stream& s);
	void MainMenu(Bar& bar) {
		bar.Sub(t_("File"), [=](Bar& bar) { FileMenu(bar); });
		bar.Sub(t_("Tools"), [=](Bar& bar) { ToolsMenu(bar); });
	}
	void FileMenu(Bar& bar) {
		bar.Add(t_("New"), Images::NEW(), [=] { NewPack(); });
		bar.Add(t_("Open"), Images::OPEN(), [=] { OpenPack(); });
		bar.Add(t_("Save"), Images::SAVE(), [=] { SavePack(); });
		bar.Add(t_("Save As"), Images::SAVE_AS(), [=] { SavePackAs(); });
		bar.Separator();
		bar.Add(t_("Exit"), Images::EXIT(), [=] { OnClose(); });
	}
	void ToolsMenu(Bar& bar) {
		bar.Add(t_("Options"), Images::CONFIG(), [=] { ShowCfgDlg(); });
		bar.Add(t_("Validate HMC FS file"), Images::CHECKIT(), [=] { RunCheck(); });
	}
	FormEditHCM();
protected:
	MenuBar mainMenu;
	LayHcmPackEdit layEditPack;
	FormReport frmCheckReport;
	VectorMap<String, String> seriaMap;
	// --------------------
	void Setup();
	void OnClose();
	void CloseNotModalFrm();
	// --------------------
	void OpenPack();
	void NewPack();
	void SavePack();
	void SavePackAs();
	void RunCheck();
	void ShowCfgDlg();
	void AboutApp();
};
FormEditHCM::FormEditHCM(){
	CtrlLayout(*this, t_(" Create/edit HCM-FS files"));
	Sizeable().Zoomable();
	pCtrl.Add(layEditPack.SizePos());
	AddFrame(mainMenu);
	mainMenu.Set([=](Bar& bar) { MainMenu(bar); }); // or  mainMenu.Set(THISFN(MainMenu));
	Setup();
}
void FormEditHCM::Setup(){
	isShow = false;
	WhenClose = THISBACK(OnClose);
	btn_New.SetImage(Images::NEW());
	btn_New.Tip(t_("New HMC FS file"));
	btn_New <<= THISBACK(NewPack);
	btn_Open.SetImage(Images::OPEN());
	btn_Open.Tip(t_("Open HMC FS file"));
	btn_Open <<= THISBACK(OpenPack);
	btn_Save.SetImage(Images::SAVE());
	btn_Save.Tip(t_("Save HMC FS file"));
	btn_Save <<= THISBACK(SavePack);
	btn_SaveAs.SetImage(Images::SAVE_AS());
	btn_SaveAs.Tip(t_("Save HMC FS file as"));
	btn_SaveAs <<= THISBACK(SavePackAs);
	btn_Check.SetImage(Images::CHECKIT());
	btn_Check.Tip(t_("Validate HMC FS file"));
	btn_Check <<= THISBACK(RunCheck);
	btn_Config.SetImage(Images::CONFIG());
	btn_Config.Tip("Options");
	btn_Config <<= THISBACK(ShowCfgDlg);
	btn_About.SetImage(Images::ABOUT());
	btn_About.Tip("About CalcFS4A");
	btn_About <<= THISBACK(AboutApp);
	btn_Exit.SetImage(Images::EXIT());
	btn_Exit.Tip("Exit");
	btn_Exit <<= THISBACK(OnClose);
}
void FormEditHCM::Serialize(Stream& s){
	layEditPack.Serialize(s);
	SerializePlacement(s);
	seriaMap.Serialize(s);
}
void FormEditHCM::BeforeFrmShow(const String& nameCtrl, VectorMap<String, String>& sMap){
	int idx = sMap.Find(nameCtrl);
	if(idx != -1) LoadFromString(*this, sMap[idx]);
}
void FormEditHCM::BeforeFrmClose(const String& nameCtrl, VectorMap<String, String>& sMap){
	int idx = sMap.Find(nameCtrl);
	if(idx == -1)
		sMap.Add(nameCtrl, StoreAsString(*this));
	else
		sMap[idx] = StoreAsString(*this);
}
void FormEditHCM::OnClose(){
	layEditPack.CloseHcmPack();
	layEditPack.SetCaption("");
	isShow = false;
    Close();
}
void FormEditHCM::CloseNotModalFrm(){
	if(frmCheckReport.isShow) {frmCheckReport.isShow = false; frmCheckReport.Close();};
}
void FormEditHCM::ShowCfgDlg(){
	CfgDlg dlg(Single<AppCFG>());
	if(dlg.Run() == IDOK) dlg.Save();
}
void FormEditHCM::AboutApp(){
	WithAboutDlg<TopWindow> dlg;
	CtrlLayoutCancel(dlg, t_("About CalcFS4A"));
	dlg.image.SetImage(Images::ABOUT_96());
	Font fnt = Single<ItemGrid>().headFont;
	String aboutStr = String() << "HCM software is used for co-ordination of fixed service stations according to HCM4A-Agreement";
	aboutStr << "\n\nVersion: " << APP_VERSION;
	aboutStr << "\nCopyrite © \"International Telecommunication Union (ITU)\"";
	dlg.richText.SetQTF(DeQtf(aboutStr));
	dlg.Execute();
}
void FormEditHCM::OpenPack(){
	FileSel fs;
	fs.ReadOnlyOption(true);
	fs.MkDirOption(false);
	String fEditPath = Single<AppCFG>().cfgCalcRec.fEditPack;
	if(DirectoryExists(GetFileDirectory(fEditPath)))
		fs.ActiveDir(GetFileDirectory(fEditPath));
	else if(DirectoryExists(Single<AppCFG>().cfgPathRec.GetEdWorkDir()))
		fs.ActiveDir(Single<AppCFG>().cfgPathRec.GetEdWorkDir());
	else
		fs.ActiveDir(GetExeFolder());
	fs.Types("Text files\t*.txt\nExcel files\t*.xlsx\nJson files\t*.json");
	if(fs.ExecuteOpen()){
		Single<AppCFG>().cfgPathRec.SetEdWorkDir(GetFileFolder(fs.Get()));
		String hcmFile = fs;
		layEditPack.CloseHcmPack();
		layEditPack.OpenHcmPack(hcmFile);
		layEditPack.SetCaption(t_(Format(" hcm file:  %s", hcmFile)));
		CloseNotModalFrm();
	}
}
void FormEditHCM::SavePack(){
	layEditPack.SaveHcmPack();
}
void FormEditHCM::SavePackAs(){
	layEditPack.SaveHcmPackAs();
}
void FormEditHCM::NewPack(){
	layEditPack.Clear();
	layEditPack.NewHcmPack();
	layEditPack.AddEntry();
}
void FormEditHCM::RunCheck(){
	if(layEditPack.GetHcmPack().IsEmpty()){
		OpenPack();
	}
	bool isCheck = false;
	String vlog;
	if(layEditPack.GetHcmPack().IsValid()){
		isCheck = true;
		vlog << layEditPack.GetHcmPack().GetPackFile() << ":\n";
		layEditPack.CheckHcmPack(vlog);
	}
	if(isCheck){
		frmCheckReport.Title("HMC FS file validation results");
		frmCheckReport.de_Report.SetData(vlog);
		if(frmCheckReport.isShow){
			ActiveFocus(frmCheckReport);
		}
		else{
			frmCheckReport.OpenMain();	// for non-modal form calls
			frmCheckReport.isShow = true;
		}
	}
}
//!---------------------------------------------------------------------------------------------

//!=============================================================================================


class FormCalcHCM : public WithFrmCalcHCM<TopWindow>{
public:
	typedef FormCalcHCM CLASSNAME;
	bool isShow;
	void BeforeFrmShow(const String& nameCtrl, VectorMap<String, String>& sMap);
	void BeforeFrmClose(const String& nameCtrl, VectorMap<String, String>& sMap);
	void Serialize(Stream& s);
	void MainMenu(Bar& bar) {
		bar.Sub(t_("File"), [=](Bar& bar) { FileMenu(bar); });
		bar.Sub(t_("Calculation"), [=](Bar& bar) { CalcMenu(bar); });
		bar.Sub(t_("Tools"), [=](Bar& bar) { ToolsMenu(bar); });
	}
	void FileMenu(Bar& bar) {
		bar.Add(t_("Exit"), Images::EXIT(), [=] { OnClose(); });
	}
	void CalcMenu(Bar& bar) {
		bar.Add(t_("List-to-List Entry Calculation"), Images::CALC_LIST(), [=] { RunCalcList(); });
		bar.Add(t_("Single Entry Calculation"), Images::CALC_SINGLE(), [=] { RunCalcSingle(); });
	}
	void ToolsMenu(Bar& bar) {
		bar.Add(t_("Options"), Images::CONFIG(), [=] { ShowCfgDlg(); });
		bar.Add(t_("Validate HMC FS file"), Images::CHECKIT(), [=] { RunCheck(); });
	}
	void ClearGisMap();
	FormCalcHCM();
protected:
	MenuBar mainMenu;
	Splitter splDataCalc;
	Splitter splTesRef;
	LayHcmPackView layTest;
	LayHcmPackView layRef;
	ParentCtrl ctrlData;

	HSinglCalcCtrl ctrlSingl;
	HMultCalcCtrl ctrlMult;

	AppCalcMode appCalcMode;
	VectorMap<String, String> seriaMap;
	// --------------------
	// for non-modal form calls, declare as a class member
	FormReport formReport;
	FormMap formMap;
	FormCalcRes formCalcRes;
	// --------------------

	CalcParamData inCalcParam;
	// --------------------
	void Setup();
	void OnClose();
	void ShowCfgDlg();
	void CloseNotModalFrm();
	void AboutApp();
	// --------------------
	void ShowMap();
	void ShowFormCalcRes(const String& title);
	void RunCheck();
	void RunCalcSingle();
	void RunCalcList();
	void SaveSingleCalcToXLS();
	void SaveMultCalcToXLS();
	TblSingleRec calcSingleResult;
	TblMultData multHcmData;
};

FormCalcHCM::FormCalcHCM(){
	CtrlLayout(*this, t_(" Calculate interference between fixed service"));
	Sizeable().Zoomable();
	ctrlData.Add(splTesRef.Vert(layTest.SizePos(), layRef.SizePos()));
	mainCtrl.Add(ctrlData.SizePos());
	AddFrame(mainMenu);
	mainMenu.Set([=](Bar& bar) { MainMenu(bar); }); // or  mainMenu.Set(THISFN(MainMenu));
	Setup();
}
void FormCalcHCM::Setup(){
	isShow = false;
	appCalcMode = AppCalcMode::NONE;
	layTest.SetTabCaption("HCM Testing ");
	layRef.SetTabCaption("HCM Reference ");
	WhenClose = THISBACK(OnClose);
	btn_CalcSingle.SetImage(Images::CALC_SINGLE());
	btn_CalcSingle.Tip(t_("Single Entry Calculation"));
	btn_CalcSingle <<= THISBACK(RunCalcSingle);
	btn_CalcList.SetImage(Images::CALC_LIST());
	btn_CalcList.Tip(t_("List-to-List Entry Calculation"));
	btn_CalcList <<= THISBACK(RunCalcList);
	btn_Check.SetImage(Images::CHECKIT());
	btn_Check.Tip(t_("Validate HMC FS file"));
	btn_Check <<= THISBACK(RunCheck);
	btn_Map.SetImage(Images::MAP());
	btn_Map.Tip(t_("Show Map"));
	btn_Map <<= THISBACK(ShowMap);
	btn_Config.SetImage(Images::CONFIG());
	btn_Config.Tip(t_("Options"));
	btn_Config <<= THISBACK(ShowCfgDlg);
	btn_About.SetImage(Images::ABOUT());
	btn_About.Tip(t_("About CalcFS4A"));
	btn_About <<= THISBACK(AboutApp);
	btn_Exit.SetImage(Images::EXIT());
	btn_Exit.Tip(t_("Exit"));
	btn_Exit <<= THISBACK(OnClose);
}
void FormCalcHCM::AboutApp(){
	WithAboutDlg<TopWindow> dlg;
	CtrlLayoutCancel(dlg, t_("About CalcFS4A"));
	dlg.image.SetImage(Images::ABOUT_96());
	Font fnt = Single<ItemGrid>().headFont;
	String aboutStr = String() << "HCM software is used for co-ordination of fixed service stations according to HCM4A-Agreement";
	aboutStr << "\n\nVersion: " << APP_VERSION;
	aboutStr << "\nCopyrite © \"International Telecommunication Union (ITU)\"";
	dlg.richText.SetQTF(DeQtf(aboutStr));
	dlg.Execute();
}
void FormCalcHCM::Serialize(Stream& s){
	layTest.Serialize(s);
	layRef.Serialize(s);
	ctrlSingl.Serialize(s);
	ctrlMult.Serialize(s);
	formReport.Serialize(s);
	formMap.Serialize(s);
	formCalcRes.Serialize(s);
	SerializePlacement(s);
	seriaMap.Serialize(s);
}
void FormCalcHCM::BeforeFrmShow(const String& nameCtrl, VectorMap<String, String>& sMap){
	int idx = sMap.Find(nameCtrl);
	if(idx != -1) LoadFromString(*this, sMap[idx]);
	inCalcParam.Load();
}
void FormCalcHCM::BeforeFrmClose(const String& nameCtrl, VectorMap<String, String>& sMap){
	inCalcParam.Save();
	int idx = sMap.Find(nameCtrl);
	if(idx == -1)
		sMap.Add(nameCtrl, StoreAsString(*this));
	else
		sMap[idx] = StoreAsString(*this);
}
void FormCalcHCM::OnClose(){
	isShow = false;
	layTest.CloseHcmPack();
	layRef.CloseHcmPack();
	CloseNotModalFrm();
	ctrlSingl.Clear();
	ctrlMult.Clear();
    Close();
}
void FormCalcHCM::CloseNotModalFrm(){
	if(formReport.isShow)	{formReport.isShow = false; formReport.Close();};
	if(formMap.isShow)		{formMap.isShow = false; formMap.Close();};
	if(formCalcRes.isShow)	{formCalcRes.isShow = false; formCalcRes.Close();};
}
void FormCalcHCM::ShowCfgDlg(){
	CfgDlg dlg(Single<AppCFG>());
	if(dlg.Run() == IDOK) dlg.Save();
}
void FormCalcHCM::SaveSingleCalcToXLS(){
	FileSel fs;
	fs.ReadOnlyOption(true);
	fs.MkDirOption(false);
	fs.ActiveDir(GetExeFolder());
	fs.EditFileName(true);
	fs.Types("Excel files\t*.xlsx");
	if(fs.ExecuteSaveAs()){
		const String file = fs;
		xlnt::workbook wbOut;
	    xlnt::worksheet wsOut = wbOut.active_sheet();
	    wsOut.title("single calc");
	    Vector<String> title;
		calcSingleResult.FillTitle(title);
	    for(int i=0; i<title.GetCount(); i++){
			wsOut.cell(xlnt::cell_reference(i+1, 1)).value(title[i].ToStd());
		}
	    Vector<String> data;
		calcSingleResult.FillData(data);
	    for(int i=0; i<data.GetCount(); i++){
	        wsOut.cell(xlnt::cell_reference(i+1, 2)).value(data[i].ToStd());
	    }
		wbOut.save(file.ToStd());
	}
}
void FormCalcHCM::SaveMultCalcToXLS(){
	FileSel fs;
	fs.ReadOnlyOption(true);
	fs.MkDirOption(false);
	fs.ActiveDir(GetExeFolder());
	fs.EditFileName(true);
	fs.Types("Excel files\t*.xlsx");
	if(fs.ExecuteSaveAs()){
		const String file = fs;
		xlnt::workbook wbOut;
	    xlnt::worksheet wsOut = wbOut.active_sheet();
	    wsOut.title("list to list calc");
	    Vector<String> title;
		Vector<Vector<String>> data;
		if(multHcmData.multCalcLst.GetCount()){
			multHcmData.multCalcLst[0].FillTitle(title);
			for(auto v: multHcmData.multCalcLst){
				v.FillData(data.Add());
			}
		}
	    for(int i=0; i<title.GetCount(); i++){
			wsOut.cell(xlnt::cell_reference(i+1, 1)).value(title[i].ToStd());
		}
		for(int i=0; i<data.GetCount(); i++){
			for(int j=0; j<data[i].GetCount(); j++)
				wsOut.cell(xlnt::cell_reference(j+1, i+2)).value(data[i][j].ToStd());
		}
		wbOut.save(file.ToStd());
	}
}

void FormCalcHCM::RunCheck(){
	if(layTest.GetHcmPack().IsEmpty()){
		String testFile;
		testFile = SelHcmFile("Open file", Single<AppCFG>().cfgPathRec.GetCalcTestDir());
		if(FileExists(testFile)) layTest.OpenHcmPack(testFile);
	}
	bool isCheck = false;
	String vlog;
	if(layTest.GetHcmPack().IsValid()){
		isCheck = true;
		vlog << layTest.GetHcmPack().GetPackFile() << ":\n";
		layTest.CheckHcmPack(vlog);
	}
	if(layRef.GetHcmPack().IsValid()){
		isCheck = true;
		vlog << "\n\n" << layRef.GetHcmPack().GetPackFile() << ":\n";
		layRef.CheckHcmPack(vlog);
	}
	if(isCheck){
		formReport.Title("HMC FS file validation results");
		formReport.de_Report.SetData(vlog);
		if(formReport.isShow){
			ActiveFocus(formReport);
		}
		else{
			formReport.OpenMain();	// for non-modal form calls
			formReport.isShow = true;
		}
	}
}
void FormCalcHCM::RunCalcSingle(){
	String testFile = SelHcmFile("Open Testing file", Single<AppCFG>().cfgPathRec.GetCalcTestDir());
	if(testFile.IsEmpty()) return;
	if(!FileExists(testFile)){
		Exclamation("Error opening the file [* " + DeQtf(testFile) + "]!");
		return;
	}
	Single<AppCFG>().cfgPathRec.SetCalcTestDir(GetFileFolder(testFile));
	layTest.CloseHcmPack();
	layRef.CloseHcmPack();
	layTest.OpenHcmPack(testFile);

	formMap.layGisMap.stationsList.Clear();
	layTest.GetHcmPack().FillStationList(false, formMap.layGisMap.stationsList);
	formMap.layGisMap.RefreshMapTree();
	formMap.layGisMap.Refresh();

	ctrlSingl.Clear();
	ctrlMult.Clear();
	layTest.tab.Set(1);
	layRef.tab.Set(1);
	formCalcRes.Clear();

	if(!layTest.GetHcmPack().IsValid()) return;
	CalcParamDlg dlg(inCalcParam);
	if(dlg.Run() == IDOK){
		dlg.Save();
		dlg.FromCtrl();
		calcSingleResult.Clear();
		if(!layTest.GetHcmPack().IsValid()){
			calcSingleResult.ts_i_error = appErrorMap.Get(997).Code();
			calcSingleResult.ts_msgerror = appErrorMap.Get(997).Message();
		}
		else{
			SingleCalc(calcSingleResult, layTest.GetHcmPack(), inCalcParam, Single<AppCFG>());
		}
		ctrlSingl.Clear();
		ctrlSingl.Load(calcSingleResult);
		formCalcRes.ctrlCalc.ClearFrames();
		formCalcRes.ctrlCalc.Add(ctrlSingl.grCalcRes);
		ctrlSingl.fcbExport << [=]{SaveSingleCalcToXLS();};
		// Show Calc Report ------------------------------
		ctrlSingl.fcbReport << [=] {
			formReport.Title("Detailed calculation report");
			formReport.fileName = GetFileName(layTest.GetHcmPack().GetPackFile());
			formReport.de_Report.SetData(calcSingleResult.ts_report);
			if(formReport.isShow){
				ActiveFocus(formReport);
			}
			else{
				formReport.OpenMain();	// for non-modal form calls
				formReport.isShow = true;
			}
		};
		ShowFormCalcRes(String()<<"Сalculation result: "<<GetFileTitle(testFile));
	}
}

void FormCalcHCM::RunCalcList(){
	String testFile;
	String refFile;
	OpenHcmDlg openDlg(Single<AppCFG>());
	if(openDlg.Run() == IDOK){
		testFile = openDlg.ed_FileTest.GetData().ToString();
		refFile  = openDlg.ed_FileRef.GetData().ToString();
		if(!FileExists(testFile)) testFile = SelHcmFile("Open Testing file", Single<AppCFG>().cfgPathRec.GetCalcTestDir());
		if(!FileExists(refFile)) refFile = SelHcmFile("Open Reference file", Single<AppCFG>().cfgPathRec.GetCalcRefDir());
		if(!FileExists(testFile)){
			Exclamation("Error opening the file [* " + DeQtf(testFile) + "]!");
			return;
		}
		if(!FileExists(refFile)){
			Exclamation("Error opening the file [* " + DeQtf(refFile) + "]!");
			return;
		}
		appCalcMode = AppCalcMode::MULT;
		Single<AppCFG>().cfgCalcRec.fPackTest = testFile;
		Single<AppCFG>().cfgCalcRec.fPackRef = refFile;
		layTest.CloseHcmPack();
		layRef.CloseHcmPack();
		formMap.layGisMap.stationsList.Clear();
		formMap.layGisMap.RefreshMapTree();
		formMap.layGisMap.Refresh();
	}
	else{
		return;
	}
	openDlg.Close();
	Sleep(100);
	Refresh();
	layTest.OpenHcmPack(testFile);
	layRef.OpenHcmPack(refFile);
	layTest.GetHcmPack().FillStationList(false, formMap.layGisMap.stationsList);
	layRef.GetHcmPack().FillStationList(true, formMap.layGisMap.stationsList);
	formMap.layGisMap.RefreshMapTree();
	formMap.layGisMap.Refresh();

	ctrlSingl.Clear();
	ctrlMult.Clear();
	layTest.tab.Set(1);
	layRef.tab.Set(1);
	formCalcRes.Clear();

	CalcParamDlg dlg(inCalcParam);
	if(dlg.Run() != IDOK) return;
	dlg.Save();
	dlg.FromCtrl();
	if(Hcm4AfsDll()){
		multHcmData.multCalcLst.Clear();
		MultHcmPack mTestPack; mTestPack.FromPack(layTest.GetHcmPack());
		MultHcmPack mRefPack; mRefPack.FromPack(layRef.GetHcmPack());
		if(!mTestPack.IsValid() || !mRefPack.IsValid()){
			if(!mTestPack.IsValid()){
				Exclamation(DeQtf(Format("There is no way to perform calculation, file:\n\"%s\"\n is not an hcm data file", mTestPack.GetHcmFile())));
				return;
			}
			if(!mRefPack.IsValid()){
				Exclamation(DeQtf(Format("There is no way to perform calculation, file:\n\"%s\"\n is not an hcm data file", mRefPack.GetHcmFile())));
				return;
			}
		}
		else{
			CalcPTR(multHcmData.multCalcLst, mTestPack, mRefPack, inCalcParam, Single<AppCFG>());
			CalcTx(multHcmData.multCalcLst, mTestPack, mRefPack, inCalcParam, Single<AppCFG>());
			CalcRx(multHcmData.multCalcLst, mTestPack, mRefPack, inCalcParam, Single<AppCFG>());
		}
	}
	Hcm4AfsDll().Free();
	ctrlMult.Load(multHcmData.multCalcLst);


	formCalcRes.layResCo.CloseHcmPack();
	formCalcRes.layResCo.OpenHcmPack(testFile);
	formCalcRes.ctrlCalc.ClearFrames();
	formCalcRes.ctrlCalc.Add(ctrlMult.grCalcRes);
	formCalcRes.CoEditPack(multHcmData, inCalcParam); // , const CalcParamData& calcParam
	formCalcRes.layResCo.ToCtrl();

	ctrlMult.fcbExport << [=]{SaveMultCalcToXLS();};
	// Show Calc Report ----------------------------
	ctrlMult.fcbReport << [=] {
		int recNo = ctrlMult.GetCurSelID();
		if(recNo>=0 && recNo < multHcmData.multCalcLst.GetCount()){
			formReport.Title("Detailed calculation report");
			formReport.fileName = String() << Format("%s_%s.txt", GetFileTitle(Single<AppCFG>().cfgCalcRec.fPackTest), recNo);
			formReport.de_Report.SetData(multHcmData.multCalcLst[recNo].tl_report);
			if(formReport.isShow){
				ActiveFocus(formReport);
			}
			else{
				formReport.OpenMain();	// for non-modal form calls
				formReport.isShow = true;
			}
		}
	};
	ShowFormCalcRes(String()<<"Сalculation result: "<<GetFileTitle(testFile)<<" <<=>> "<<GetFileTitle(refFile));
}
void FormCalcHCM::ShowMap(){
	formMap.Title("");
	if(formMap.isShow){
		ActiveFocus(formMap);
	}
	else{
		//formMap.layGisMap.ChangeOptions();
		formMap.layGisMap.RefreshMapSettings();
		formMap.OpenMain();	// for non-modal form calls
		formMap.isShow = true;
	}
}
void FormCalcHCM::ClearGisMap(){
	formMap.layGisMap.stationsList.Clear();
	formMap.layGisMap.RefreshMapTree();
	formMap.layGisMap.Refresh();
}

void FormCalcHCM::ShowFormCalcRes(const String& title){
	formCalcRes.Title(title);
	if(formCalcRes.isShow){
		ActiveFocus(formCalcRes);
	}
	else{
		formCalcRes.OpenMain();	// for non-modal form calls
		formCalcRes.isShow = true;
	}
}
//!---------------------------------------------------------------------------------------------

//!=============================================================================================


class FormStart : public WithFrmStart<TopWindow>{
public:
	typedef FormStart CLASSNAME;
	void Serialize(Stream& s);
	void BeforeFrmShow();
	void BeforeFrmClose();
	void FillAppLst();
	void MainMenu(Bar& bar) {
		bar.Add(t_("Create/Edit"), [=] { Edit(); });
		bar.Sub(t_("Calculation"), [=](Bar& bar) { CalcMenu(bar); });
		bar.Add(t_("Config"), [=] { ShowCfgDlg(); });
		bar.Add(t_("About"), [=] { AboutApp(); });
		bar.Add(t_("Exit"), [=] { OnClose(); });
	}
	void CalcMenu(Bar& bar) {
		bar.Add(t_("(Single | List-to-List) Entry Calculation"), Images::CALC(), [=] { Calc(); });
		bar.Add(t_("Trigger for Co-ordination "), Images::TRIG(), [=] { RunCalcTriger(); });
	}

	FormStart();
protected:
	MenuBar mainMenu;
	FormEditHCM frmEdit;
	FormCalcHCM frmCalc;
	FormHTrigCalc frmHTrigCalc;
	VectorMap<String, String> seriaMap;
	Vector<TrigerRec> trigCalcLst;
	void OnClose();
	void Edit();
	void Calc();
	void RunCalcTriger();

	void ShowCfgDlg();
	void AboutApp();
	String GetVersion()const{return APP_VERSION;}
};
FormStart::FormStart(){
	Sizeable().Zoomable();
	CtrlLayout(*this, Format(t_(" %s: HCM4A-FS ver. %s"), GetExeTitle(), GetVersion()));
	// lb_Name.SetText(Format(t_(" %s: HCM4A-FS ver. %s"), GetExeTitle(), GetVersion()));
	AddFrame(mainMenu);
	mainMenu.Set([=](Bar& bar) { MainMenu(bar); }); // or  mainMenu.Set(THISFN(MainMenu));

	WhenClose = THISBACK(OnClose);
	btn_Edit.SetImage(Images::EDIT());
	btn_Edit.Tip(t_("Create or edit HCM-FS files."));
	btn_Edit <<= THISBACK(Edit);
	btn_Calc.SetImage(Images::CALC());
	btn_Calc.Tip(t_("Calculate interference between fixed service stations."));
	btn_Calc <<= THISBACK(Calc);
	btn_Trigger.SetImage(Images::TRIG());
	btn_Trigger.Tip("Trigger for Co-ordination");
	btn_Trigger <<= THISBACK(RunCalcTriger);
	btn_Config.SetImage(Images::CONFIG());
	btn_Config.Tip("Options");
	btn_Config <<= THISBACK(ShowCfgDlg);
	btn_About.SetImage(Images::ABOUT());
	btn_About.Tip("About CalcFS4A");
	btn_About <<= THISBACK(AboutApp);
	btn_Exit.SetImage(Images::EXIT());
	btn_Exit.Tip("Close the program.");
	btn_Exit <<= THISBACK(OnClose);
	frmEdit.Icon(Images::ICON_64());
	frmCalc.Icon(Images::ICON_64());
}
void FormStart::OnClose(){
    Close();
}
void FormStart::Serialize(Stream& s){
	int version = 1;
	s / version;
	if(s.IsLoading()){
		frmEdit.BeforeFrmShow("frmEdit_", seriaMap);
		frmCalc.BeforeFrmShow("frmCalc_", seriaMap);
	}
	if(s.IsStoring()){
		frmEdit.BeforeFrmClose("frmEdit_", seriaMap);
		frmCalc.BeforeFrmClose("frmCalc_", seriaMap);
	}
	frmHTrigCalc.Serialize(s);
	frmEdit.Serialize(s);
	frmCalc.Serialize(s);
	SerializePlacement(s);
	seriaMap.Serialize(s);
}
void FormStart::BeforeFrmShow(){
	LoadFromFile(*this);
	Single<AppCFG>().Load();
	FillAppLst();
	if(!Single<AppCFG>().cfgPathRec.IsExistsDirsTMB()){
		ShowCfgDlg();
	}
}
void FormStart::BeforeFrmClose(){
	StoreToFile(*this);
	Single<AppCFG>().Save();
}
void FormStart::FillAppLst(){
	String warStr = "";
	String path_1Z = String() << APP_LST_DIR << "/" << Single<AppCFG>().cfgEditRec.GetLstFreqCategoryName();
	if(!FileExists(GetExeFolder() << "/" << path_1Z)) warStr << path_1Z << "\n";
	String path_6Z = String() << APP_LST_DIR << "/" << Single<AppCFG>().cfgEditRec.GetLstCategoryOfUseName();
	if(!FileExists(GetExeFolder() << "/" << path_6Z)) warStr << path_6Z << "\n";
	String path_4B = String() << APP_LST_DIR << "/" << Single<AppCFG>().cfgEditRec.GetLstCountriesName();
	if(!FileExists(GetExeFolder() << "/" << path_4B)) warStr << path_4B << "\n";
	String path_7K = String() << APP_LST_DIR << "/" << Single<AppCFG>().cfgEditRec.GetLstMaxCapacitLinkName();
	if(!FileExists(GetExeFolder() << "/" << path_7K)) warStr << path_7K << "\n";
	String path_13Y = String() << APP_LST_DIR << "/" << Single<AppCFG>().cfgEditRec.GetLstStatusOfCooName();
	if(!FileExists(GetExeFolder() << "/" << path_13Y)) warStr << path_13Y << "\n";
	if(!warStr.IsEmpty()){
		Exclamation("Мissing data files:" + DeQtf("\n" + warStr));
	}
	Single<HcmLstData>().AddLst(HcmLstRec("0A", Vector<String>{"Tx", "Rx", "Ptx", "Prx"}));
	Single<HcmLstData>().AddLst(HcmLstRec("1A1", Vector<String>{"k", "M", "G"}));
	Single<HcmLstData>().AddLst(HcmLstRec("1Z", path_1Z));
	Single<HcmLstData>().AddLst(HcmLstRec("6A", Vector<String>{"FX"}));
	Single<HcmLstData>().AddLst(HcmLstRec("6B", Vector<String>{"CO", "CP", "CR", "CV", "OT"}));
	Single<HcmLstData>().AddLst(HcmLstRec("6Z", path_6Z));
	Single<HcmLstData>().AddLst(HcmLstRec("4B", path_4B));
	Single<HcmLstData>().AddLst(HcmLstRec("9D", Vector<String>{"H", "V"}));
	Single<HcmLstData>().AddLst(HcmLstRec("9Xptcp", Vector<String>{"", "CP", "VV", "HH"}));
	Single<HcmLstData>().AddLst(HcmLstRec("9Xptxp", Vector<String>{"", "XP", "VH", "HV"}));
	Single<HcmLstData>().AddLst(HcmLstRec("7K", path_7K));
	//Single<HcmLstData>().AddLst(HcmLstRec("13Y", String() << APP_LST_DIR << "/" << Single<AppCFG>().cfgEditRec.GetLstStatusOfCooName()));
	HcmLstRec lst13Y = HcmLstRec("13Y"); lst13Y.LoadFirstValueCSV(path_13Y);
	Single<HcmLstData>().AddLst(lst13Y);
}
void FormStart::Edit(){
	frmEdit.Execute();
}
void FormStart::Calc(){
	frmCalc.ClearGisMap();
	frmCalc.Execute();
}
void FormStart::RunCalcTriger(){
	trigCalcLst.Clear();
	String fileName = OpenFileTXT(Single<AppCFG>().cfgPathRec.GetTrigWorkDir());
	if(fileName.IsEmpty()) return;
	MultHcmPack mPack;
	if(mPack.FromCSV(fileName)){
		Single<AppCFG>().cfgPathRec.SetTrigWorkDir(GetFileFolder(fileName));
		TrigerCalc(trigCalcLst, mPack, Single<AppCFG>());
		frmHTrigCalc.frmCtrl.Load(trigCalcLst, fileName);
		frmHTrigCalc.Title(GetFileName(fileName));
		frmHTrigCalc.Execute();
	}
	else{
		Exclamation(DeQtf(Format("Error opening file: \"%s\"\nThe selected file is not an hcm data file", fileName)));
	}
}
void FormStart::ShowCfgDlg(){
	CfgDlg dlg(Single<AppCFG>());
	if(dlg.Run() == IDOK) dlg.Save();
}
void FormStart::AboutApp(){
	WithAboutDlg<TopWindow> dlg;
	CtrlLayoutCancel(dlg, t_("About CalcFS4A"));
	dlg.image.SetImage(Images::ABOUT_96());
	Font fnt = Single<ItemGrid>().headFont;
	String aboutStr = String() << "HCM software is used for co-ordination of fixed service stations according to HCM4A-Agreement";
	aboutStr << "\n\nVersion: " << APP_VERSION;
	aboutStr << "\nCopyrite © \"International Telecommunication Union (ITU)\"";
	dlg.richText.SetQTF(DeQtf(aboutStr));
	dlg.Execute();
}
//!---------------------------------------------------------------------------------------------



/*
CalcFS 4A
Create or edit HCM-FS files
Calculate interference between fixed service	
Exit

This program calculates interference between fixed service
stations according to HCM calculation procedure defined
in http://www.hcm-agreement.eu

For calculations of interference it uses HCMFS_DLL.dll.

This program also can create and edit HCM-FS files.
Format of the files is defined in Annex 2 of the HCM-Agreement.

General remark: An administration with which co-ordination is sought is not allowed to change the content of any field
 except of field 13Y which must be changed and field 13Z which can be changed e.g. to notify the reason(s) for disagree¬ment 
 (indication of a co-ordination reference etc.). If comments need more characters than provided in 13Z, paper or another medium has to be used.
*/


#endif
