#include "lfsaappl.h"
extern LArc TBL_DiscreteTime[];
class FDiscreteTime :											
	public LFsaAppl											
{													
public:													
    enum {cvarINE, cvarExlusiveOR, cvarOrNot};
    void MooreAction();
	bool	FCreationOfLinksForVariables();								
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF) return new FDiscreteTime(nameFsa); }
	bool FInit();											
    FDiscreteTime(string strNam, LArc* pTBL = TBL_DiscreteTime);
	~FDiscreteTime(void);										
	CVar *pVarType;		
	CVar *pVarX1;		
	CVar *pVarStrNameX1;	
    	CVar *pVarIfNotX1;	
    	CVar *pVarY1;		
	CVar *pVarStrNameY1;	
	CVar *pVarValue01;	
	CVar *pVarValue10;	
    	CVar *pVarNegationY;
    	virtual int x3();	
	virtual int x12();	
    	virtual bool f();
    	int nTypeElement;
protected:
    int x1();
	void y1(); void y4(); void y5(); void y6(); void y7(); void y12(); void y13(); 
    bool bType{false};	
    bool bX1{false};
    int nCurrent{0};
    int nDelay{0};		
    LFsaAppl	*pFCall{nullptr};
    friend class FCallTransport;
    friend class FCallInertial;
};		
class FCallTransport :
	public LFsaAppl
{
public:
	void MooreAction();
	FCallTransport(FDiscreteTime	*pFDiscreteTime);
	FDiscreteTime	*pFDiscreteTime;
protected:
	int x1();
};
class FCallInertial :
	public LFsaAppl
{
public:
	void MooreAction();
	FCallInertial(FDiscreteTime	*pFDiscreteTime);
	FDiscreteTime	*pFDiscreteTime;
protected:
    int x1(); int x3();
};
#include "stdafx.h"
#include "FDiscreteTime.h"											
#include "VARFSA/SetVarFsaLibrary.h"
LArc TBL_DiscreteTime[] = {
    LArc("st",	"st","^x12","y12"),	
    LArc("st",	"ss","x12", "--"),	
    LArc("ss",	"s1","x3",  "y7y6y13"),
    LArc("ss",	"s0","^x3", "y4y5y13"),
    LArc("s0",	"s1","x3",  "y13"),    
    LArc("s1",	"s0","^x3", "y13"),    
    LArc()
};
FDiscreteTime::FDiscreteTime(string strNam, LArc* pTBL):
    LFsaAppl(pTBL, strNam, nullptr, nullptr)
{ }
													
FDiscreteTime::~FDiscreteTime(void) { if (pFCall) delete pFCall; }
bool FDiscreteTime::FInit() {										
    FCreationOfLinksForVariables();
    return true;
}
bool FDiscreteTime::FCreationOfLinksForVariables()
{
    pVarNegationY = CreateLocVar("negation", CLocVar::vtBool, "output inversion: 0-without inversion / 1-inversion");
    pVarType = CreateLocVar("type", CLocVar::vtBool, "delay type: 0-transp / 1-inertia");
    pVarY1 = CreateLocVar("y", CLocVar::vtBool, "local output");
    pVarX1 = CreateLocVar("x1", CLocVar::vtBool, "local input");
    pVarValue01 = CreateLocVar("value to 1", CLocVar::vtInteger, "delay value from 0 to 1");
    pVarValue10 = CreateLocVar("value to 0", CLocVar::vtInteger, "delay value from 1 to 0");
    pVarStrNameX1 = CreateLocVar("strNameX1", CLocVar::vtString, "name of external input variable (x)");
    pVarStrNameY1 = CreateLocVar("strNameY", CLocVar::vtString, "name of external output variable (y)");
    pVarIfNotX1 = CreateLocVar("not(x1)", CLocVar::vtBool, "1st input inversion: 0-without inversion / 1-inversion");
    string str;
    str = pVarStrNameX1->strGetDataSrc();
    if (str != "") { pVarX1 = pTAppCore->GetAddressVar(pVarStrNameX1->strGetDataSrc().c_str(), this);	}
    str = pVarStrNameY1->strGetDataSrc();
    if (str != "") { pVarY1 = pTAppCore->GetAddressVar(pVarStrNameY1->strGetDataSrc().c_str(), this);	}
    return true;
}
int FDiscreteTime::x1() { return nCurrent == nDelay; }
int FDiscreteTime::x3() {
    if (bool(pVarNegationY->GetDataSrc())) return !f();
    return f();
}
int FDiscreteTime::x12() { return pVarX1 != nullptr; }
bool FDiscreteTime::f() {
    bX1 = bool(pVarX1->GetDataSrc());
    if (bool(pVarIfNotX1->GetDataSrc())) bX1 = !bX1;
    return bX1;
}
void FDiscreteTime::y1() { nCurrent++; }
void FDiscreteTime::y4() { nDelay = int(pVarValue01->GetDataSrc()); }
void FDiscreteTime::y5() { pVarY1->SetDataSrc(nullptr, 0.0); }
void FDiscreteTime::y6() { pVarY1->SetDataSrc(nullptr, 1); }
void FDiscreteTime::y7() { nDelay = int(pVarValue10->GetDataSrc()); }
void FDiscreteTime::y12() { FInit(); }
void FDiscreteTime::y13() {
	nCurrent = 0;
	if (pFCall) { delete pFCall; pFCall = nullptr; }
	if (x1()) return;
	bType = pVarType->GetDataSrc();		
	if (bType) pFCall = new FCallInertial(this);
	else pFCall = new FCallTransport(this);
	if (pFCall) pFCall->FCall(this);
}
void FDiscreteTime::MooreAction()
{
	string strState = FGetState();
	if (strState=="s0")	{ 
        y4(); y5();		
    }
	else if (strState=="s1") { 
        y7(); y6();		
    }
}
static LArc TBL_CallTransport[] = {
	LArc("s5","s5","^x1",	"--"),		
	LArc("s5","00","x1",	"--"),		
	LArc()
};
FCallTransport::FCallTransport(FDiscreteTime	*pFI):
    LFsaAppl(TBL_CallTransport, "FCallTransport", nullptr, nullptr)
{
	pFDiscreteTime = pFI;
}
int FCallTransport::x1() { return pFDiscreteTime->x1(); }
void FCallTransport::MooreAction()
{
	string strState = FGetState();
	if (strState=="s5")	{ pFDiscreteTime->y1(); }
}
static LArc TBL_CallInertial[] = {
	LArc("s5",	"s5","^x1x3",	"--"),		
	LArc("s5",	"00","x1x3",	"--"),		
	LArc("s5",	"XX","^x3",	"--"),		
	LArc()
};
FCallInertial::FCallInertial(FDiscreteTime	*pFI):
    LFsaAppl(TBL_CallInertial, "FCallInertial", nullptr, nullptr)
{
	pFDiscreteTime = pFI;
}
int FCallInertial::x1() { return pFDiscreteTime->x1(); }
int FCallInertial::x3() {
	string strState = FGetStateUp();
	bool bX = pFDiscreteTime->x3();
    if (strState == "s0") return bX;
    if (strState == "s1") return !bX;
	if (strState == "st") {
		string str = pFDiscreteTime->FGetNextState();
		bX = pFDiscreteTime->x3();
		if (!bX) {
			if (x1()) {
                if (str == "s0") return !bX;
                if (str == "s1") return bX;
			}
            else return true;
		}
		return true;
	}
	else return bX; 
}
void FCallInertial::MooreAction()
{
	string strState = FGetState();
	if (strState=="s5")	{ pFDiscreteTime->y1(); }
}