//---------------------------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#include <time.h>
#include <conio.h>
#include <dir.h>

#pragma hdrstop

#include "quizmain.h"
#include "setupmain.h"
#include "threadsearch.h"
#include "Welcome.h"
#include "Help.h"

//---------------------------------------------------------------------------
// #pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;
SearchThread *SearchDevs;

int bits[17]  = { 0,0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
    			    0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000 };

unsigned char com_port;       	    // serial com port
int LanguageChoice;

int num,number;
int StopThread, ThreadStop;
int SetUp,SetupNeeded;

unsigned char switch_id[MAX_SWITCHES + 1][8];

char name[MAX_SWITCHES + 1][25];
int blinking;

char buffer[50],buffer1[50];

char programdir[MAXPATH];

int Open_Port(unsigned char cm_pt);
int read_init();
int write_ini_file();

extern int LearnId;

extern int SetupPort( unsigned char );
extern int TouchByte( unsigned char );
extern int TouchReset( void );
extern unsigned char TouchBit(unsigned char);
extern void CloseComport();

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    StopThread = true;
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    static int blinker    = 0;
    static int State      = 0;
    static int PortOpened = 0;
    int i,j;
    static clock_t StartTime, EndTimes[MAX_SWITCHES];

    switch(State)
    {
        case 0:
            Timer1 -> Enabled = false;
   	        if(read_init() == true)			// Read the initfile 
            {
                ThreadStop = true;          // Thread isn't running
                Timer1   -> Enabled = true;
                ListBox1 -> Clear();
	            mask     = 0;
	            number   = 0;
	            for (i = 1; i <= MAX_SWITCHES; i++)
	                for(j = 0;j < 8;j++)
		                bus_idents[i][j] = 0;

                State = 1;
                if(LanguageChoice == DUTCH)
                {
                    sprintf(buffer,"Ingestelde (RS232) Compoort: %1d",com_port);
                    WelcomeForm -> LoadLabel     -> Caption = "Compoort goed ingesteld?";
                    WelcomeForm -> ToSetupButton -> Caption = "&CompoortSetup";
                }
                else
                {
                    sprintf(buffer,"The comport (RS232) is: %1d",com_port);
                    WelcomeForm -> LoadLabel     -> Caption = "Right comport?";
                    WelcomeForm -> ToSetupButton -> Caption = "&ComportSetup";
                }
                WelcomeForm -> WelcomeComport -> Caption = buffer;
                WelcomeForm -> ProgressBar1 -> Position  = 0;
                WelcomeForm -> ShowModal();
            }
            else
            {
                exit(1);
            }
            break;
        case 1:
            WelcomeForm    -> ProgressBar1 -> StepIt();
            if(WelcomeForm -> ProgressBar1 -> Position == WelcomeForm -> ProgressBar1 -> Max)
            {
                WelcomeForm -> ModalResult = mrOk;
                if(PortOpened)
                {
                    CloseComport();
                }
                State++;
            }
            if(WelcomeForm -> ModalResult == mrYes)
            {   // Setup requested
                SetupNeeded = true;
                SetupScreen -> ListBox1 -> Enabled = false;
                State = 3;
            }
            if(WelcomeForm -> ModalResult == mrRetry)
            {   // Help needed
                Timer1   -> Enabled = false;
                HelpForm -> ShowModal();
                State    = 0;
                Timer1   -> Enabled = true;
            }
            break;

        case 2:
            if(Open_Port(com_port) == false)
            {
                Timer1 -> Enabled = false;
                if(LanguageChoice == DUTCH)
                {
                    i = Application->MessageBox("Geen communicatie mogelijk!! \n1. Stel de compoort goed in bij de setup \n2. Controleer aansluiting van het interface", "Systeem fout", MB_OK+MB_OKCANCEL+MB_ICONERROR);
                    ReactionText -> Caption = "Reactie tijd";
                }
                else
                {
                    i = Application->MessageBox("No communication possible!! \n1. Run the setup for the correct comport\n2. Check the interface connections", "System error", MB_OK+MB_OKCANCEL+MB_ICONERROR);
                    ReactionText -> Caption = "Reaction time";
                }

                Timer1 -> Enabled = true;
                if(i == IDOK)
                {
                    SetupScreen -> ListBox1 -> Enabled = false;
                    SetupNeeded = true;
                    State++;
                }
                if (i == IDCANCEL)
                {
                    State = 99;
                }
            }
            else
            {       // Comport opened successfully
                if(StopThread)
                {   // Make a thread
                    SearchThread *SearchDevs = new SearchThread(false); // create and run the thread
                }
                StopThread = false;
                ThreadStop = false;
                PortOpened = true;
                SetUp      = false;
                if(LanguageChoice == DUTCH)
                {
                    sprintf(buffer1,"Reactie tijd:");
                    ResetButton -> Hint = "Leegmaken onderstaande tabel";
                    ListBox1    -> Hint = "Wacht op indrukken van de quiztoetsen";
                }
                else
                {
                    sprintf(buffer1,"Reaction time:");
                    ResetButton -> Hint = "Clear table below";
                    ListBox1    -> Hint = "Wait till quizbuttons are pressed";
                }
                ReactionText -> Caption = buffer1;
                State++;
            }
            break;

        case 3: // RUN state
            if( SetupNeeded )
            {
                SetupNeeded = false;
                SetUp       = true;
                SetupScreen -> fill_in_config_listbox();
                SetupScreen -> ShowModal();
                State       = 0;
            }

            if(!SetUp)
	        {                               // Normal run
                if(NewFound)
                {                           // A switch found
                    if (!number)            // Attention when the first one pushes a button
                    {
                        StartTime = clock();// Starttime
                        blinking  = true;
                        if(LanguageChoice == DUTCH)
                        {
                            ListBox1 -> Hint  = "Volgorde van indrukken....";
                        }
                        else
                        {
                            ListBox1 -> Hint  = "Button-pressed sequence....";
                        }
                        ListBox1 -> Color = clWhite;
                    }
                    for(i=1;i<=max_bus_devices;i++)
                    {
		                num = 1;
                        while(num <= MAX_SWITCHES)
                        {
		                    if( (bits[num] & (nieuw & ~mask))
                                && (Sequence[i] == num) )
                            {
			                    break;
                            }
                            else
                            {
                                num++;
                            }
                        }
                        if(num <= MAX_SWITCHES)
                        {
                            if(number)
                            {
                                EndTimes[number] = (clock() - StartTime);
                                sprintf(buffer,";%2d: %d,%1d S",number + 1,EndTimes[number]/1000,(EndTimes[number]%1000)/100);
                            }
                            else
                            {
                                sprintf(buffer," 1: 0 S");
                            }
                            strcat(buffer1,buffer);
                            ReactionText -> Caption = buffer1;
                            number++;
   	                        sprintf(buffer,"%2d:%s",number,name[num]);
                            ListBox1->Items->Add(buffer);
                            mask |= bits[num];
                        }
                    }
                    NewFound = false;
                }
            }
            else
            {   // In setup
                if(SetupScreen->IdLabel -> Enabled == true)
                {
                    if(NewFound)
                    {   // Switch is pressed, display its internal number
                        for(i=7;i>=0;i--)
                        {
                            sprintf(buffer,"%02X ",bus_idents[1][i]);
                            if(i==7)
                                strcpy(buffer1,buffer);
                            else
                                strcat(buffer1,buffer);
                        }
                        SetupScreen->IdLabel ->Text = buffer1;
                        NewFound = false;
                    }
                }
            }

            if(blinking)
            {
                if(!blinker--)
                {
                    if(!SetUp)
                    {
                        blinker = 5;
                    }
                    else
                    {
                        blinker = 10;
                    }
                    if(LearnId)
                    {
                        if(SetupScreen->LearnKeyId->Color == clSilver)
                        {
                            SetupScreen->LearnKeyId->Color       = clRed;
                            SetupScreen->LearnKeyId->Font->Color = clWhite;
                        }
                        else
                        {
                            SetupScreen->LearnKeyId->Color       = clSilver;
                            SetupScreen->LearnKeyId->Font->Color = clBlack;
                        }
                    }
                    else
                    {
                        if(TitleText->Color == clSilver)
                        {
                            TitleText->Color       = clRed;
                            TitleText->Font->Color = clWhite;
                        }
                        else
                        {
                            TitleText->Color       = clSilver;
                            TitleText->Font->Color = clBlack;
                        }
                    }
                }
            }
            break;

        case 99: // Stop the program
            Timer1 -> Enabled = false;
            StopThread = true;
            while(!ThreadStop);
            delete SearchDevs;
            exit(1);
    }
}
//---------------------------------------------------------------------------
//
//  This function opens the selected com port and verifies there is not a
//  short. Returns: true:  Everything went good
//                  false: COMport not valid
//

int Open_Port(unsigned char cm_pt)
{
    int return_val = true;

	if (!SetupPort(cm_pt))      // make sure we can use this port
    {
        return_val = false;
    }
    else
    {                           // We can use this port
	    if (TouchReset() == 5)  // either no brick is connected, or com_port is to slow or no VCC
        {                       // First time gives no charcter back and thus a 5
            if (TouchReset() == 5)
            {                   // No interface connected
                return_val = false;
            }
        }
    }
    return return_val;
}

#define COMMAND     0
#define ID          1
#define NAME        2
#define COM         3
#define LANGUAGE    4

// Read switch-names/id's, comport and language from file config.txt
int read_init( void )
{
	FILE *read;
	char dat[1000];
	int i,j,point = 0,file_state = COMMAND;

	i = -1; // Char pointer
	j = -1; // Name pointer

    strcpy(programdir, "X:\\");         // fill string with form of response: X:\
    programdir[0] = 'A' + getdisk();    // replace X with current drive letter
    getcurdir(0, programdir+3);         // fill rest of string with current directory

	for (i=0; i<=MAX_SWITCHES; i++)
    {
		sprintf(name[i],"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); /* Fill in default names */
    }

	if( ( read = fopen("config.txt", "r" ) ) == NULL )
	{
        Application->MessageBox("File config.txt is missing!", "System error", MB_OK+MB_ICONERROR);
        return false;
	}
	else
	{
		dat[point] = (char)fgetc( read );
		while((dat[point] != EOF))
		{
			point++;
			dat[point] = (char)fgetc( read );   // Get file into an array to make life
		}                                       // easier further in the program
		fclose( read );

		point = 0;
		while((dat[point] != EOF))
		{
			switch(file_state)
			{
				case COMMAND:                 // Which item in the configfile
						if(dat[point] == '-') // Command
						{
							point++;
							if((dat[point] > '0') && (dat[point] <= '9'))     /* Names */
							{
								if(dat[point+1] == ' ')
									j = dat[point] - '0';                         /* Which team (1,2..8) */
								else
								{
									j = (dat[point] - '0') * 10;                  /* Which team (1,2..8) */
									j += dat[point+1] - '0';
								}
								i = -1;
								file_state = ID;
							}
							else
							{
								if((dat[point] == 'C') || (dat[point] == 'c')) 	/* Serialport */
								{
									file_state = COM;
								}
								if((dat[point] == 'L') || (dat[point] == 'l')) 	/* Language */
								{
									file_state = LANGUAGE;
								}
							}
						}
						point++;
						break;

				case ID:            // Read 64 bits id-number
						if((dat[point] == '"') && (i == -1))
						{
							point++;
							i = 7;
						}
						if(i != -1)
						{
							if(dat[point] != '"')
							{
								if(dat[point] <= '9')
									switch_id[j][i]  = (unsigned char)((dat[point++] - '0') * 16); /* Filter name from the data */
								else
									switch_id[j][i]  = (unsigned char)((dat[point++] - '7') * 16); /* Filter name from the data */

								if(dat[point] <= '9')
									switch_id[j][i] += (unsigned char)(dat[point] - '0'); /* Filter name from the data */
								else
									switch_id[j][i] += (unsigned char)(dat[point] - '7'); /* Filter name from the data */

								if(i)
								{
									point++; // Skip the point in the identstring
									i--;
								}
							}
							else
							{
								i = -1;
								file_state = NAME;
							}
						}
						point++;
						break;

				case NAME:              // Read team-name
						if((dat[point] == '"') && (i == -1))
						{
							point++;
							i = 0;
						}
						if(i != -1)
						{
							if(dat[point] != '"')
							{
								name[j][i] = dat[point]; // Filter name from the data
								i++;
							}
							else
							{
								i = -1;
								file_state = COMMAND;
							}
						}
						point++;
						break;

				case COM:                   // Read com-port
						if(dat[point] != ' ')
						{
							com_port = (unsigned char)(dat[point] - '0');
                            if(com_port > 4)
                            {
                                com_port = 1;
                            }
							file_state = COMMAND;
						}
						point++;
						break;

				case LANGUAGE:              // Read language setting
						if(dat[point] != ' ')
						{
							LanguageChoice = (unsigned char)(dat[point] - '0');
                            if(LanguageChoice > ENGLISH)
                            {
                                LanguageChoice = ENGLISH;
                            }
							file_state = COMMAND;
						}
						point++;
						break;

			}
		}
        return true;
	}
}

int write_ini_file()
{
	FILE *write;
	int  i,j;

    chdir(programdir);

	if( ( write = fopen("config.txt", "w" ) ) == NULL )
	{
        Application->MessageBox("Cannot write file: config.txt!", "System error", MB_OK+MB_ICONERROR);
        return false;
	}
	else
	{
		fprintf(write,"Config file \n\n");
		fprintf(write,"-c %1d /* Com port */ \n\n",com_port);
		fprintf(write,"-l %1d /* Language: 0 = dutch, 1 = english */ \n\n",LanguageChoice);
        fprintf(write,"Nr      Switch id                   Name\n\n");
		for(i = 1;i <= MAX_SWITCHES;i++)
		{
			fputc('-',write);               // begin of switchdata
			if(i<10)
				fprintf(write,"%d  ",i);    // Number 1..20
			else
				fprintf(write,"%d ",i);
			fputc('"',write);
            for(j=7;j>=0;j--)
            {                               // Write 8 byte id number
                if(j == 0)
                    fprintf(write,"%02X",switch_id[i][j]);
                else
                    fprintf(write,"%02X ",switch_id[i][j]);
            }
			fputc('"',write);
			fputc(' ',write);
			fputc('"',write);
			fprintf(write,"%s",name[i]);    // Ande the name of it
			fputc('"',write);
			fputc('\n',write);
		}
		fclose(write);
	}
	return true;
}



void __fastcall TForm1::ResetButtonClick(TObject *Sender)
{
    int i,j;
    if(LanguageChoice == DUTCH)
    {
        sprintf(buffer1,"Reactie tijd:");
        ListBox1 -> Hint = "Wacht op indrukken van de quiztoetsen";
    }
    else
    {
        sprintf(buffer1,"Reaction time:");
        ListBox1 -> Hint = "Wait till quizbuttons are pressed";
    }
    ReactionText -> Caption = buffer1;
    TitleText->Color        = clSilver;
    TitleText->Font->Color  = clBlack;
    ListBox1->Clear();
    ListBox1->Color = clSilver;
    blinking = false;
	mask     = 0;
	number   = 0;
	for (i = 1; i <= MAX_SWITCHES; i++)
	    for(j=0;j<8;j++)
			bus_idents[i][j] = 0;
}
//---------------------------------------------------------------------------




void __fastcall TForm1::StopMenuClick(TObject *Sender)
{
    StopThread = true;   // Try to stop the running searchthread
    while(!ThreadStop);
    delete SearchDevs;   // It stops

    exit(1);             // Kill application
}
//---------------------------------------------------------------------------

void __fastcall TForm1::SetupMenuClick(TObject *Sender)
{
    int i,j;

    TitleText -> Color = clSilver;
    TitleText -> Font -> Color = clBlack;
    ListBox1  -> Clear();
    ListBox1  -> Color = clSilver;
    blinking = false;
	mask     = 0;
	number   = 0;
	for (i = 1; i <= MAX_SWITCHES; i++)
	    for(j = 0;j < 8;j++)
			bus_idents[i][j] = 0;

    SetupNeeded = true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::HelpMenuClick(TObject *Sender)
{
    HelpForm -> ShowModal();
}
//---------------------------------------------------------------------------

