//---------------------------------------------------------------------------
/*
Remote Train Control Program for Windows

© Copyright 2019 by Mark DiVecchio

    This file is part of Remote Train Control.

    Remote Train Control is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Remote Train Control is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

*/
// Home Page : http://www.silogic.com/trains/RTC_Running.html
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#ifndef PC_ThreadH
#define PC_ThreadH
//---------------------------------------------------------------------------
#include <Classes.hpp>
//
// Processing State Machine
//
enum STATEMACHINE {IDLE = 0, RUNNING = 1};
//
// Bump()
// These define the fields in the Program Control window that the PC_Thread and Lua Script can increment
// Copy of these constants in define.lua

#define COUNTER01 0 // User Defined Counter 01
#define COUNTER02 1 // User Defined Counter 02
#define COUNTER03 2 // User Defined Counter 03
#define COUNTER04 3 // User Defined Counter 04
#define COUNTER05 4 // User Defined Counter 05
#define COUNTER06 5 // User Defined Counter 06
#define ELAPSEDTIME 6 // Elapsed Time
// Counters in the DetectedRFIDTags window
#define TAGSUB 10 	// Number of Tags using substitution
#define UNIQTAG 11 	// Unique Tag Counter
#define TAGCNT 12 	// Total Tag Counter
#define ENGINENO 13	// value in Engine number spinner
#define NUMENG 14   // number of started engines

/* Possible future implementation
enum{
COUNTER01 = 0, // User Defined Counter 01
COUNTER02 = 1, // User Defined Counter 02
COUNTER03 = 2, // User Defined Counter 03
COUNTER04 = 3, // User Defined Counter 04
COUNTER05 = 4, // User Defined Counter 05
COUNTER06 = 5, // User Defined Counter 06
ELAPSEDTIME = 6, // Elapsed Time
// Counters in the DetectedRFIDTags window
TAGSUB = 10, 	// Number of Tags using substitution
UNIQTAG = 11, 	// Unique Tag Counter
TAGCNT = 12, 	// Total Tag Counter
ENGINENO = 13	// value in Engine number spinner
};
*/
//
// Display in Message List (if debug level > 0) or throw() a hard error (if debug level == 0)
// Always scroll to bottom of buffer for error message
// SLine must be AnsiString because the c_str() taken needs to be a char type.
#define HARDERROR(windo, msg, color)\
	{\
	String PLine = msg;\
	AnsiString SLine = PLine;\
    if (MainForm->GlobalDBLevel > 0) {\
    	ptrTIUCommThread->ShowinBuffer(windo, PLine, color, true);\
        luaL_error(L, SLine.c_str());\
        } else {\
        throw(PLine);\
        }\
    }

// Display in Message List (if debug level > 0) or throw a luaL_error (if debug level == 0)
// Always scroll to bottom of buffer for error message
// SLine must be AnsiString because the c_str() taken needs to be a char type.
#define SOFTERROR(windo, msg, color)\
	{\
	String PLine = msg;\
	AnsiString SLine = PLine;\
    if (MainForm->GlobalDBLevel > 0) {\
	    ptrTIUCommThread->ShowinBuffer(windo, PLine, color, true);\
        luaL_error(L, SLine.c_str());\
        } else {\
    	luaL_error(L, SLine.c_str());\
        }\
    }
//
// function prototypes
void SetFunctionLabel(lua_State * L, TProgram_Control * MyptrPC, TButton * But, char * Lab, char * Func, int HighLight = 0);
//
// Colors for use by SetLED and printc(). Copy of these colors in define.lua
#define luaGreen 0
#define luaYellow 1
#define luaRed 2
#define luaClear 3
#define luaBlack 4
#define luaBlue 5
#define luaFuchsia 6
//---------------------------------------------------------------------------
//
// Structure used in the Event_FIFO Thread Safe queue between different Program Control Threads
//
struct EventItem {
	int iFromPCNo;
	int iDestPCNo;
    __int64 EventType;
    __int64 iP1;
    __int64 iP2;
    __int64 iP3;
	};

//---------------------------------------------------------------------------
class TProg_Control_Thread : public TThread
{

private:
    int SyncEngineNo, SyncConsistNo, SyncCntrNo;
	int  SyncDelayTimeSeconds;
	char * LashUpEngineListOp;
    void __fastcall RFIDTagHandler();

    char * CommandSuffix;
    int __fastcall handleTag(char * tag, int len);

	HWND MyHndl;

    void __fastcall EngineStartUp(void);
    void __fastcall EngineShutDown(void);
    void __fastcall ShutDownAllEngines(void);
    void __fastcall ShutDownActiveEngines(void);
    void __fastcall StartUpActiveEngines(void);
	void __fastcall GetIsEngineActive(void);
	void __fastcall GetDoesConsistExist(void);
    void __fastcall GetCounts(void);
    void __fastcall CallInputBox(void);
    void __fastcall CallInputQuery(void);
    void __fastcall CallInputDropDown(void);
    void __fastcall GetCommandLine(void);
    void __fastcall GetInputLine(void);
    void __fastcall GotInputLine(void);
	void __fastcall SetUpLabels(void);
    void __fastcall CountActiveEngines(void);
    void __fastcall FindEngines(void);

	enum PROGRAMNO ProgramRunning;		// Which Program is running

    AnsiString FileName;		// File containing the Lua Script to process

    char Title[64];		// spot for script title

    bool __fastcall DisplayMessage(String Mess, TColor Color = clBlack);

    bool StopFlag;			// PC has been requested to stop by call to StopRequest()

    void __fastcall doInterpreter(void);

    // Lua Script
    lua_State *L;
    void __fastcall Lua_Register();
    bool CompileSuccess;
    HANDLE MyTimer, MySleepTimer;		// Timers for Wait Loops

    int CntrVal;						// for fetched Counter value
    String PrintLine;
    int TenthSecondCounter;

	LARGE_INTEGER StartTime, StartFrequency;

	int TagCount_Thread;

    void __fastcall ProcessEventEvent(void);

//---------------------------------------------------------------------------
protected:
	void __fastcall Execute();
    void __fastcall RunOnTerminate(TObject * Sender);
	__fastcall TProg_Control_Thread(bool CreateSuspended);

public:
    __fastcall TProg_Control_Thread::TProg_Control_Thread(bool CreateSuspended, TForm * Callingthis, HWND Hndl,
		 int PCNo, int Engine, int Remote, int TIU, enum PROGRAMNO Prog, AnsiString FN);
    __fastcall TProg_Control_Thread::~TProg_Control_Thread(void);
   	TThreadList * RFIDFIFO;	    //  FIFO RFID Tag List - Thread Safe
    DWORD ThreadID;

    int  MyRemoteNo, MyEngineNo;

    // Train Running Variables
	byte LastSentSpeedValue[ABSOLUTEMAX];
    bool direction[ABSOLUTEMAX], predictedDirection[ABSOLUTEMAX];
    bool bell[ABSOLUTEMAX], whistle[ABSOLUTEMAX], state[ABSOLUTEMAX], paused[ABSOLUTEMAX];
    bool marker[ABSOLUTEMAX], beacon[ABSOLUTEMAX], cabchat[ABSOLUTEMAX], smoke[ABSOLUTEMAX], sound[ABSOLUTEMAX];
    byte chuffrate[ABSOLUTEMAX];
	bool MotionSoundRequest[ABSOLUTEMAX], AutoBell[ABSOLUTEMAX], AutoWhistle[ABSOLUTEMAX];
    bool AutoBellGlobal, AutoWhistleGlobal;

    struct {				// structure for Event based actions
    	int EventNo;		// Function to Run
        int EngineNo;		// Engine number - set only on press of [Run Script]
        int TIUNo;			// TIU Number - set only on press of [Run Script]
        } EventData;

    int __fastcall StopRequest();		// Request Stop
    int __fastcall CleanupRequest();	// Request to run Cleanup() then stop the thread

    bool __fastcall Setting(int iSet, float when, byte EngineNo, byte TIUNo);
	bool __fastcall SetVolume(byte Chan, byte Level, float when, byte EngineNo, byte TIUNo);
	bool __fastcall Schedule(char * Command, float when, byte EngineNo, byte TIUNo, int *Flag = NULL, int FlagValue = 0);

	bool __fastcall ShutDown(float when, byte EngineNo, byte TIUNo);

	bool __fastcall StartUp(float when, byte EngineNo, byte TIUNo);
	bool __fastcall StartUpNOTUSED(float when, byte iLashUpNo, byte iTIUNo, char * ptrLashUpEngineList);

	bool __fastcall Accessory(bool bState, int iAIUNo, int iChan, float when, byte TIUNo);
	bool __fastcall Siding(bool bState, int iAIUNo, int iChan, byte TIUNo);
	bool __fastcall Switch(bool bState, int iAIUNo, int iChan, float when, byte TIUNo);
    
	bool __fastcall Whistle(bool bState, float when, byte EngineNo, byte TIUNo);
	bool __fastcall Bell(bool bState, float when, byte EngineNo, byte TIUNo);
   	bool __fastcall Markers(bool bState, float when, byte EngineNo, byte TIUNo);
   	bool __fastcall Beacon(bool bState, float when, byte EngineNo, byte TIUNo);
   	bool __fastcall CabChat(bool bState, float when, byte EngineNo, byte TIUNo);
   	bool __fastcall Smoke(bool bState, float when, byte EngineNo, byte TIUNo);
   	bool __fastcall ChuffRate(int Rate, float when, byte EngineNo, byte TIUNo);
	bool __fastcall Rate(byte iAcc, byte iDec, float when, byte EngineNo, byte TIUNo);
    bool __fastcall GetRate(byte * iAcc, byte * iDec, int EngineNo, int TIUNo);
	bool __fastcall OpenCoupler(bool bCoupler, float when, byte EngineNo, byte TIUNo);
	bool __fastcall SetDirection(bool bDIR, float when, byte EngineNo, byte TIUNo);
	bool __fastcall Throttle(int iMPH, float when, byte EngineNo, byte TIUNo);
	bool __fastcall MyPlaySound(int iSoundNo, float when, byte EngineNo, byte TIUNo);
	bool __fastcall SetSpeed(int iMPH, float when, byte EngineNo, byte TIUNo);
   	bool __fastcall Sound(bool bState, float when, byte EngineNo, byte TIUNo);
    bool __fastcall ProtoWhistle(bool bState, float when, byte iEngineNo, byte iTIUNo);
    bool __fastcall SetQuill(int iTone, float when, byte iConsistNo, byte iTIUNo);

    bool __fastcall SmokeWhistle(bool bState, float when, byte iEngineNo, byte iTIUNo);
    bool __fastcall SwingingBell(bool bState, float when, byte iEngineNo, byte iTIUNo);

    void __fastcall MyEngineStartUp(byte iEngineNo, int iTIUNo, int iDelayTimeSeconds = 0);
	void __fastcall MyEngineShutDown(byte Consist, int iTIUNo, int iDelayTimeSeconds = 0);
    void __fastcall MyShutDownAllEngines(int iDelayTimeSeconds = 0);
    void __fastcall MyShutDownActiveEngines(int iDelayTimeSeconds = 0);
    void __fastcall MyStartUpActiveEngines(int iDelayTimeSeconds = 0);
    void __fastcall MyIsEngineActive(int iEngineNo);
	void __fastcall MyDoesConsistExist(int iConsistNo);
	void __fastcall MyGetCounts(void);
    void __fastcall MyCallInputBox(void);
    void __fastcall MyCallInputQuery(void);
    void __fastcall MyCallInputDropDown(void);
    void __fastcall MyGetCommandLine(void);
    void __fastcall MyGetInputLine(void);
    void __fastcall MyGotInputLine(void);

    bool __fastcall luaH_CallFunction(char * FuncName, __int64 i0 = 0, __int64 i1 = 0, __int64 i2 = 0, __int64 i3 = 0, __int64 i4 = 0);
    bool __fastcall FetchByte(unsigned int addr, byte *value, int EngineNo, int TIUNo);
    bool __fastcall FetchWord(unsigned int addr, unsigned short * value, int EngineNo, int TIUNo);
    bool __fastcall FetchInt(unsigned int addr, unsigned int * value, int EngineNo, int TIUNo);
    bool __fastcall FetchDTO(double *value, int EngineNo, int TIUNo);
    bool __fastcall FetchDOD(double *value, int EngineNo, int TIUNo);
    bool __fastcall FetchDCH(double *value, int EngineNo, int TIUNo);
    bool __fastcall FetchSpeed(unsigned int *value, int EngineNo, int TIUNo);
    bool __fastcall FetchInstSpeed(unsigned int *value, int EngineNo, int TIUNo);
    bool __fastcall FetchDirection(bool *value, int EngineNo, int TIUNo);
    bool __fastcall FetchVolume(int Chan, int *value, int EngineNo, int TIUNo);

    bool __fastcall FactoryReset(int EngineNo, int TIUNo);
    bool __fastcall FeatureReset(int EngineNo, int TIUNo);
    bool __fastcall Command(char sCommand[], int EngineNo, int TIUNo, int Expected, int * iCmdCount, byte * CmdbyteResp);

    bool __fastcall Ping(int * p4loss, int EngineNo, int TIUNo);

    char ToString[64];	// location for transfer of script string
    int MyActiveCount, MyInactiveCount;	// for fetched engine counts
    bool __fastcall PCSleepinSeconds(lua_State *L, float DelayTime);
    bool __fastcall MyWaitForInputLine(lua_State *L, float DelayTime);
    bool __fastcall MyYield(lua_State *L);
    bool MybResponse;
    // InputBox & InputQuery parameters
    String ACaption, APrompt, ADefault, InputString;
    int AIndex;
    bool InputResponse;	// InputQuery response
    TStringList * DropDownList;
    int MyPCNo;
    TProgram_Control * ptrPC;				// pointer to calling Program Control window
    bool Finished;
    HANDLE RFIDReqEvent;		// for event communications with PC_Thread
    
    bool CallTickFunction;		// OK to run tick()
    bool CallLoopFunction;		// OK to run loop()
    bool CallTagFunction;		// OK to run handletag() which runs lua functions tag(), rawtag() and uidtag() if present
    bool CallUIDTagFunction;	// OK for handletag() to run uidtag()
    bool CallResponseFunction;	// OK for handletag() to run response()
    bool CallNameTagFunction;	// OK for handletag() to run nametag()
    bool CallCleanupFunction;	// OK to run cleanup()
    bool CallEventFunction; 	// OK to run event()

    bool CabCreated;			// indicate that the Cab Display is created

    void __fastcall SetUpLabelsSync(void);

};
//---------------------------------------------------------------------------
// Create a custom exception that will be called if the user presses the [STOP] button
class EMySTOP : public Exception
{
public:
	__fastcall EMySTOP(const String Msg) :
    	Exception(Msg){}
};
//---------------------------------------------------------------------------
#endif
