#ifndef __HCM4A_CalcFS4A_appCfg_h_
#define __HCM4A_CalcFS4A_appCfg_h_

#include "iniCfg.h"

struct CalcParamData: Moveable<CalcParamData>{
	InCalcRec inCalcRec;
	double minTD;			// tdThreshold = 1.0;
	bool isShowUnCalc;
	bool isInputDN;
	void Init(){
		inCalcRec.OnDefault();
		minTD = 0.0;
		isShowUnCalc = false;
		isInputDN = false;
	}
	void ToINI(IniCfg& ini){
		ini.SetValue("plz", IntStr(inCalcRec.plz));
		ini.SetValue("time_percentage", DblStr(inCalcRec.time_percentage));
		ini.SetValue("press", DblStr(inCalcRec.press));
		ini.SetValue("temp", DblStr(inCalcRec.temp));
		ini.SetValue("dN", DblStr(inCalcRec.dN));
		ini.SetValue("n0", DblStr(inCalcRec.n0));
		ini.SetValue("isInputDN", IntStr(isInputDN));
		ini.SetValue("minTD", DblStr(minTD));
		ini.SetValue("isShowUnCalc", IntStr(isShowUnCalc));
	}
	void FromINI(const IniCfg& ini){
		Init();
		Value v;
		v = StrInt(ini.GetValue("plz"));
		if(!v.IsNull()) inCalcRec.plz = v;
		v = StrDbl(ini.GetValue("time_percentage"));
		if(!v.IsNull()) inCalcRec.time_percentage = v;
		v = StrDbl(ini.GetValue("press"));
		if(!v.IsNull()) inCalcRec.press = v;
		v = StrDbl(ini.GetValue("temp"));
		if(!v.IsNull()) inCalcRec.temp = v;
		v = StrDbl(ini.GetValue("dN"));
		if(!v.IsNull()) inCalcRec.dN = v;
		v = StrDbl(ini.GetValue("n0"));
		if(!v.IsNull()) inCalcRec.n0 = v;
		v = StrInt(ini.GetValue("isInputDN"));
		if(!v.IsNull()) isInputDN = v;
		v = StrDbl(ini.GetValue("minTD"));
		if(!v.IsNull()) minTD = v;
		v = StrInt(ini.GetValue("isShowUnCalc"));
		if(!v.IsNull()) isShowUnCalc = v;
	}
	bool IsEmpty(){
		return inCalcRec.IsEmpty();
	}
	void Load(){
		ini.Load();
		FromINI(ini);
	}
	void Save(){
		ToINI(ini);
		ini.Save();
	}
	CalcParamData(){Init();}
protected:
	IniCfg ini;
};
//!---------------------------------------------------------------------------------------------

struct CfgCalcRec: Moveable<CfgCalcRec>{
	double maxDeltaFreqTxRx;// Frequency_TXRX = 300.0
	double maxDistTxRX;		//
	double maxDistPtxRX;	// Distance_PTXRX = 2.0
	double coMinTD;
	String fPackTest;
	String fPackRef;
	String fEditPack;
	void Init(){
		maxDeltaFreqTxRx = 300.0;
		maxDistTxRX = 1000.0;
		maxDistPtxRX = 2.0;
		coMinTD = 0.001;
		fPackTest = "";
		fPackRef = "";
		fEditPack = "";
	}
	void ToINI(IniCfg& ini){
		ini.SetValue("maxDeltaFreqTxRx", DblStr(maxDeltaFreqTxRx));
		ini.SetValue("maxDistTxRX", DblStr(maxDistTxRX));
		ini.SetValue("maxDistPtxRX", DblStr(maxDistPtxRX));
		ini.SetValue("coMinTD", DblStr(coMinTD));
		ini.SetValue("fPackTest", fPackTest);
		ini.SetValue("fPackRef", fPackRef);
		ini.SetValue("fEditPack", fEditPack);
	}
	void FromINI(const IniCfg& ini){
		Init();
		Value v1 = StrDbl(ini.GetValue("maxDeltaFreqTxRx"));
		if(!v1.IsNull()) maxDeltaFreqTxRx = v1;
		Value v2 = StrDbl(ini.GetValue("maxDistTxRX"));
		if(!v2.IsNull()) maxDistTxRX = v2;
		Value v3 = StrDbl(ini.GetValue("maxDistPtxRX"));
		if(!v3.IsNull()) maxDistPtxRX = v3;
		Value v4 = StrDbl(ini.GetValue("coMinTD"));
		if(!v4.IsNull()) coMinTD = v4;
		fPackTest = ini.GetValue("fPackTest");
		fPackRef = ini.GetValue("fPackRef");
		fEditPack = ini.GetValue("fEditPack");
	}
	CfgCalcRec(){Init();}
};
//!---------------------------------------------------------------------------------------------

struct CfgPathRec: Moveable<CfgPathRec>{
	String GetTopo()const{return topo_path;}
	String GetMorpho()const{return morpho_path;}
	String GetBorder()const{return border_path;}
	String GetEdWorkDir()const{if(DirectoryExists(edit_work_dir)) return edit_work_dir; else return GetExeFolder();}
	String GetCalcTestDir()const{if(DirectoryExists(calc_test_dir)) return calc_test_dir; else return GetExeFolder();}
	String GetCalcRefDir()const{if(DirectoryExists(calc_ref_dir)) return calc_ref_dir; else return GetExeFolder();}
	String GetTrigWorkDir()const{if(DirectoryExists(trig_work_dir)) return trig_work_dir; else return GetExeFolder();}
	void SetTopo(const String& str);
	void SetMorpho(const String& str);
	void SetBorder(const String& str);
	void SetEdWorkDir(const String& str);
	void SetCalcTestDir(const String& str);
	void SetCalcRefDir(const String& str);
	void SetTrigWorkDir(const String& str);
	void Clear(){
		topo_path = "";
		morpho_path = "";
		border_path = "";
		calc_test_dir = "";
		calc_ref_dir = "";
		edit_work_dir = "";
		trig_work_dir = "";
	}
	void Init(){
		topo_path   = NativePath(GetHomeDirectory() << "/_MAP/" << TOPO);
		morpho_path = NativePath(GetHomeDirectory() << "/_MAP/" << MORPHO);
		border_path = NativePath(GetHomeDirectory() << "/_MAP/" << BORDER);
		calc_test_dir	= GetHomeDirectory();
		calc_ref_dir	= GetHomeDirectory();
		edit_work_dir	= GetHomeDirectory();
		trig_work_dir	= GetHomeDirectory();
	}
	bool IsExistsDirsTMB(){
		if(!DirectoryExists(topo_path) || !DirectoryExists(morpho_path) || !DirectoryExists(border_path)) return false;
		if(topo_path.Find(TOPO)==-1 || morpho_path.Find(MORPHO)==-1 || border_path.Find(BORDER)==-1){
			return false;
		}
		return true;
	}
	void ToINI(IniCfg& ini){
		ini.SetValue("topo_path", topo_path);
		ini.SetValue("morpho_path", morpho_path);
		ini.SetValue("border_path", border_path);
		ini.SetValue("calc_test_dir", calc_test_dir);
		ini.SetValue("calc_ref_dir", calc_ref_dir);
		ini.SetValue("edit_work_dir", edit_work_dir);
		ini.SetValue("trig_work_dir", trig_work_dir);
	}
	void FromINI(const IniCfg& ini){
		topo_path = ini.GetValue("topo_path");
		morpho_path = ini.GetValue("morpho_path");
		border_path = ini.GetValue("border_path");
		calc_test_dir = ini.GetValue("calc_test_dir");
		calc_ref_dir = ini.GetValue("calc_ref_dir");
		edit_work_dir = ini.GetValue("edit_work_dir");
		trig_work_dir = ini.GetValue("trig_work_dir");
	}
	String ToString()const{
		return Format("\nTOPO: %s\nMORPHO: %s\n BORDER: %s\n", topo_path, morpho_path, border_path);
	}
	CfgPathRec(){Clear();}
	CfgPathRec(const CfgPathRec& сfgPath):topo_path(сfgPath.topo_path), morpho_path(сfgPath.morpho_path), border_path(сfgPath.border_path){}
protected:
	const String TOPO   = "TOPO";
	const String MORPHO = "MORPHO";
	const String BORDER = "BORDER";
	String topo_path;
	String morpho_path;
	String border_path;
	String calc_test_dir;
	String calc_ref_dir;
	String edit_work_dir;
	String trig_work_dir;
};
void CfgPathRec::SetTopo(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) topo_path = dir;
}
void CfgPathRec::SetMorpho(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) morpho_path = dir;
}
void CfgPathRec::SetBorder(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) border_path = dir;
}
void CfgPathRec::SetEdWorkDir(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) edit_work_dir = dir;
}
void CfgPathRec::SetCalcTestDir(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) calc_test_dir = dir;
}
void CfgPathRec::SetCalcRefDir(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) calc_ref_dir = dir;
}
void CfgPathRec::SetTrigWorkDir(const String& dir){
	if(!TrimBoth(dir).IsEmpty() && DirectoryExists(dir)) trig_work_dir = dir;
}
//!---------------------------------------------------------------------------------------------

struct CfgEditRec: Moveable<CfgEditRec>{
	String GetLstCountriesName()const{return lstCountriesName.IsEmpty() ? "Countries" : lstCountriesName;}
	void SetLstCountriesName(const String& str){ lstCountriesName = str;}
	String GetLstCategoryOfUseName()const{return lstCategoryOfUseName.IsEmpty() ? "CategoryOfUse" : lstCategoryOfUseName;}
	void SetLstCategoryOfUseName(const String& str){ lstCategoryOfUseName = str;}
	String GetLstFreqCategoryName()const{return lstFreqCategoryName.IsEmpty() ? "FreqCategory" : lstFreqCategoryName;}
	void SetLstFreqCategoryName(const String& str){ lstFreqCategoryName = str;}
	String GetLstMaxCapacitLinkName()const{return lstMaxCapacitLinkName.IsEmpty() ? "MaxCapacitLink" : lstMaxCapacitLinkName;}
	void SetLstMaxCapacitLinkName(const String& str){ lstMaxCapacitLinkName = str;}
	String GetLstStatusOfCooName()const{return lstStatusOfCooName.IsEmpty() ? "StatusOfCoo" : lstStatusOfCooName;}
	void SetLstStatusOfCooName(const String& str){ lstStatusOfCooName = str;}
	bool GetIsInControl()const{return isInControl;}
	void SetIsInControl(const bool b){ isInControl = b;}

	void Init(){
		isInControl = true;
		lstCountriesName = "Countries";
		lstCategoryOfUseName = "CategoryOfUse";
		lstFreqCategoryName = "FreqCategory";
		lstMaxCapacitLinkName = "MaxCapacitLink";
		lstStatusOfCooName = "StatusOfCoo";
	}
	void ToINI(IniCfg& ini){
		ini.SetValue("isInControl", IntStr(isInControl));
		ini.SetValue("Countries", lstCountriesName);
		ini.SetValue("CategoryOfUse", lstCategoryOfUseName);
		ini.SetValue("FreqCategory", lstFreqCategoryName);
		ini.SetValue("MaxCapacitLink", lstMaxCapacitLinkName);
		ini.SetValue("StatusOfCoo", lstStatusOfCooName);
	}
	void FromINI(const IniCfg& ini){
		Init();
		Value v;
		v = StrInt(ini.GetValue("isInControl"));
		if(!v.IsNull()) isInControl = v;
		lstCountriesName = ini.GetValue("Countries");
		lstCategoryOfUseName = ini.GetValue("CategoryOfUse");
		lstFreqCategoryName = ini.GetValue("FreqCategory");
		lstMaxCapacitLinkName = ini.GetValue("MaxCapacitLink");
		lstStatusOfCooName = ini.GetValue("StatusOfCoo");
	}
	CfgEditRec(){Init();}
protected:
	bool isInControl;
	String lstCountriesName;
	String lstCategoryOfUseName;
	String lstFreqCategoryName;
	String lstMaxCapacitLinkName;
	String lstStatusOfCooName;
};
//!---------------------------------------------------------------------------------------------


struct AppCFG{
	CfgPathRec cfgPathRec;
	CfgCalcRec cfgCalcRec;
	CfgEditRec cfgEditRec;
	void Load();
	void Save();
	AppCFG();
protected:
	IniCfg ini;
};
AppCFG::AppCFG(){
	cfgPathRec.Init();
	cfgCalcRec.Init();
	cfgEditRec.Init();
}
void AppCFG::Load(){
	ini.Load();
	cfgPathRec.FromINI(ini);
	cfgCalcRec.FromINI(ini);
	cfgEditRec.FromINI(ini);
}
void AppCFG::Save(){
	cfgPathRec.ToINI(ini);
	cfgCalcRec.ToINI(ini);
	cfgEditRec.ToINI(ini);
	ini.Save();
}
//!---------------------------------------------------------------------------------------------

struct CfgPathCtrl{
	typedef CfgPathCtrl CLASSNAME;
	WithLayCfgPath<ParentCtrl> layCfgPath;	// layout to place the control
	void ToCtrl(const CfgPathRec& cfgPathRec);
	void FromCtrl(CfgPathRec& cfgPathRec);
	void SetTopo();
	void SetMorpho();
	void SetBorder();
	CfgPathCtrl();
protected:
	String dirLast;
	String dirTopo;
	String dirMorpho;
	String dirBorder;
	String GetValidDir(const String& aDir, const String& title);

};
CfgPathCtrl::CfgPathCtrl(){
	CtrlLayout(layCfgPath);
	dirLast = "";
	dirTopo = "";
	dirMorpho = "";
	dirBorder = "";
	layCfgPath.btn_Topo <<= THISBACK(SetTopo);
	layCfgPath.btn_Morpho <<= THISBACK(SetMorpho);
	layCfgPath.btn_Border <<= THISBACK(SetBorder);
}
void CfgPathCtrl::ToCtrl(const CfgPathRec& cfgPathRec){
	dirTopo = (cfgPathRec.GetTopo());
	dirMorpho = (cfgPathRec.GetMorpho());
	dirBorder = (cfgPathRec.GetBorder());
	layCfgPath.ed_Topo.SetData(dirTopo);
	layCfgPath.ed_Morpho.SetData(dirMorpho);
	layCfgPath.ed_Border.SetData(dirBorder);
}
void CfgPathCtrl::FromCtrl(CfgPathRec& cfgPathRec){
	dirTopo = (layCfgPath.ed_Topo.GetData());
	dirMorpho = (layCfgPath.ed_Morpho.GetData());
	dirBorder = (layCfgPath.ed_Border.GetData());
	cfgPathRec.SetTopo(dirTopo);
	cfgPathRec.SetMorpho(dirMorpho);
	cfgPathRec.SetBorder(dirBorder);
}
void CfgPathCtrl::SetTopo(){
	layCfgPath.ed_Topo.SetData(GetValidDir(dirTopo, "TOPO"));
}
void CfgPathCtrl::SetMorpho(){
	layCfgPath.ed_Morpho.SetData(GetValidDir(dirMorpho, "MORPHO"));
}
void CfgPathCtrl::SetBorder(){
	layCfgPath.ed_Border.SetData(GetValidDir(dirBorder, "BORDER"));
}
String CfgPathCtrl::GetValidDir(const String& aDir, const String& title){
	String rDir = aDir;
	if(aDir.IsEmpty() || !DirectoryExists(aDir)) rDir = GetExeFolder();
	if(!dirLast.IsEmpty() && DirectoryExists(dirLast)) rDir = dirLast;
	FileSel fs;
	fs.ReadOnlyOption(true);
	fs.MkDirOption(false);
	fs.ActiveDir(rDir);
	if(fs.ExecuteSelectDir(Format("Select %s directory", title))){
		dirLast = fs;
		return fs;
	}
	dirLast = rDir;
	return rDir;
}

//!---------------------------------------------------------------------------------------------

struct CfgCalcCtrl{
	typedef CfgCalcCtrl CLASSNAME;
	WithLayCfgCalc<ParentCtrl> layCfgCalc;	// layout to place the control
	void ToCtrl(const CfgCalcRec& cfgCalcRec);
	void FromCtrl(CfgCalcRec& cfgCalcRec);
	CfgCalcCtrl();
};
CfgCalcCtrl::CfgCalcCtrl(){
	CtrlLayout(layCfgCalc);
}
void CfgCalcCtrl::ToCtrl(const CfgCalcRec& cfgCalcRec){
	layCfgCalc.ed_FreqDif.SetData(cfgCalcRec.maxDeltaFreqTxRx);
	layCfgCalc.ed_DistTxRx.SetData(cfgCalcRec.maxDistTxRX);
	layCfgCalc.ed_DistPTxRx.SetData(cfgCalcRec.maxDistPtxRX);
	layCfgCalc.ed_CoMinTD.SetData(cfgCalcRec.coMinTD);
}
void CfgCalcCtrl::FromCtrl(CfgCalcRec& cfgCalcRec){
	cfgCalcRec.maxDeltaFreqTxRx = layCfgCalc.ed_FreqDif.GetData();
	cfgCalcRec.maxDistTxRX = layCfgCalc.ed_DistTxRx.GetData();
	cfgCalcRec.maxDistPtxRX = layCfgCalc.ed_DistPTxRx.GetData();
	cfgCalcRec.coMinTD = layCfgCalc.ed_CoMinTD.GetData();
}
//!---------------------------------------------------------------------------------------------

struct CfgEditCtrl{
	typedef CfgEditCtrl CLASSNAME;
	WithLayCfgEdit<ParentCtrl> layCfgEdit;	// layout to place the control
	void ToCtrl(const CfgEditRec& cfgEditRec);
	void FromCtrl(CfgEditRec& cfgEditRec);
	CfgEditCtrl();
};
CfgEditCtrl::CfgEditCtrl(){
	CtrlLayout(layCfgEdit);
}
void CfgEditCtrl::ToCtrl(const CfgEditRec& cfgEditRec){
	layCfgEdit.op_InControl.Set(cfgEditRec.GetIsInControl());				// static_cast<int>()
}
void CfgEditCtrl::FromCtrl(CfgEditRec& cfgEditRec){
	cfgEditRec.SetIsInControl(layCfgEdit.op_InControl);
}
//!---------------------------------------------------------------------------------------------


class CfgDlg : public WithFrmCfg<TopWindow> {
public:
	typedef CfgDlg CLASSNAME;
	void Serialize(Stream& s);
	void ToCtrl();
	void FromCtrl();
	void Save();
	void Load();
	CfgDlg(AppCFG& appCFG);
protected:
	CfgPathCtrl ctrlCfgPath;
	CfgCalcCtrl ctrlCfgCalc;
	CfgEditCtrl ctrlCfgEdit;
	AppCFG& appCFG;
};
CfgDlg::CfgDlg(AppCFG& appCFG):appCFG(appCFG){
	CtrlLayoutOKCancel(*this, "Setup");
	Sizeable().Zoomable();
	tab.Add(ctrlCfgPath.layCfgPath.SizePos(), t_("\1[ [ [3*!Arial! Paths]]]"));
	tab.Add(ctrlCfgCalc.layCfgCalc.SizePos(), t_("\1[ [ [3*!Arial! Calculation]]]"));
	tab.Add(ctrlCfgEdit.layCfgEdit.SizePos(), t_("\1[ [ [3*!Arial! Edit]]]"));
	Load();
}
void CfgDlg::Serialize(Stream& s){
	int version = 1;
	s / version;
	SerializePlacement(s);
}
void CfgDlg::ToCtrl(){
	ctrlCfgPath.ToCtrl(appCFG.cfgPathRec);
	ctrlCfgCalc.ToCtrl(appCFG.cfgCalcRec);
	ctrlCfgEdit.ToCtrl(appCFG.cfgEditRec);
}
void CfgDlg::FromCtrl(){
	ctrlCfgPath.FromCtrl(appCFG.cfgPathRec);
	ctrlCfgCalc.FromCtrl(appCFG.cfgCalcRec);
	ctrlCfgEdit.FromCtrl(appCFG.cfgEditRec);
}
void CfgDlg::Load(){
	appCFG.Load();
	ToCtrl();
}
void CfgDlg::Save(){
	FromCtrl();
	appCFG.Save();
}

#endif
