//---------------------------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#include <stdlib.h>


#include <IniFiles.hpp>


#pragma hdrstop

#include "VBNGUI.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "Ipwcore"
#pragma link "ipwudpport"
#pragma link "ipwCore"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ExternalControlPortDataIn(TObject *Sender,
      char *Datagram, USHORT lenDatagram, AnsiString &SourceAddress,
      USHORT SourcePort)
{

    int  record_count;

    unsigned short  seconds,mseconds,utility_message;
    char    junk[1024],ss[6],yy[5],mm[3],dd[3],hh[3],mn[3];
    SYSTEMTIME  timestructure;
// this is the function which is called when data appears at the control UDP port


    if(!strncmp(Datagram, SHUTDOWN_MESSAGE, SHUTDOWN_LENGTH)){

        // stop logging
        MakeLogEntry("Shutdown Message Received\n");
        logging_file_stream->Free();

        // shutdown the system
        // first figure out how long to wait
        // actually, shutdown right away, I don't know why I wanted to wait

        //
        // first send a quit message to the UM software
        MasterPort->RemoteHost = SourceAddress;
      MasterPort->RemotePort = SourcePort;
      MasterPort->DataToSend = Datagram;
        VBN_output_UDP_Port->DataToSend = "VBN UM QUIT NOW";
        if(process_handle)
         TerminateProcess(process_handle,0);
        //
        // delay for a few seconds
        //
        Sleep(TICK_DELAY);
        ShutdownButtonClick(ShutdownButton);

    }
    else if(!strncmp(Datagram, NAVIGATE_MESSAGE, NAVIGATE_LENGTH)){
        // begin navigation
        // first find out how long to run the navigation software for
        record_count = sscanf(Datagram, "%*s %*s %*s %d",junk,junk,junk,&seconds);
        StatusMessage->Caption = "Status: Got Navigation Message--" + (AnsiString)Datagram;
        MakeLogEntry("Begin Navigation Execution\n");
        Launch_Process(navigation_executable_name);
        MasterPort->RemoteHost = SourceAddress;
      MasterPort->RemotePort = SourcePort;
      MasterPort->DataToSend = Datagram;

    }
    else if(!strncmp(Datagram, VIDEO_COLLECT_MESSAGE, VIDEO_COLLECT_MESSAGE_LENGTH)){
        // begin video collection
        record_count = sscanf(Datagram, "%*s %*s %*s %d",junk,junk,junk,&seconds);
        StatusMessage->Caption = "Status: Got Collection Message--" + (AnsiString)Datagram;
        MakeLogEntry("Begin Collection Execution\n");
        Launch_Process(collection_executable_name);
        MasterPort->RemoteHost = SourceAddress;
      MasterPort->RemotePort = SourcePort;
      MasterPort->DataToSend = Datagram;
    }
    else if(!strncmp(Datagram, NAVIGATE_AND_COLLECT_VIDEO_MESSAGE, NAVIGATE_AND_COLLECT_VIDEO_LENGTH)){
        // begin navigation and video collection
        record_count = sscanf(Datagram, "%*s %*s %*s %d",junk,junk,junk,&seconds);
        StatusMessage->Caption = "Status: Got Nav + Collect Message--" + (AnsiString)Datagram;
        MakeLogEntry("Begin Navigation and Collection Execution\n");
        Launch_Process(navigation_and_collection_executable_name);
        MasterPort->RemoteHost = SourceAddress;
      MasterPort->RemotePort = SourcePort;
      MasterPort->DataToSend = Datagram;
    }
    else if(!strncmp(Datagram, UTILITY_MESSAGE, UTILITY_LENGTH)){
        // execute one of several utility commands
        record_count = sscanf(Datagram, "%*s %*s %d",junk,junk,&utility_message);
        if(record_count > 0){
            StatusMessage->Caption = "Status: Got Utility Message--" + (AnsiString)Datagram;
            MakeLogEntry("Got Utility Message--" + (AnsiString)Datagram + "\n");
            Launch_Process(utility_names[utility_message]);
        }
    }
    else if(!strncmp(Datagram, TS_MESSAGE, TS_LENGTH)){
        // time synchronization
        StatusMessage->Caption = "Status: Got Time Sync Message--" + (AnsiString)Datagram;
        record_count = sscanf(Datagram,"VBN TS %s %s %s %s %s %5s",&yy,&mm,&dd,&hh,&mn,ss);
        MakeLogEntry("Time Synchronization:  Before\n" );
        if(record_count == 6){
            seconds = atoi(ss);
            mseconds = (atof(ss) - atoi(ss))*1000;
            timestructure.wYear = atoi(yy);
            timestructure.wMonth = atoi(mm);
            timestructure.wDay = atoi(dd);
            timestructure.wHour = atoi(hh);
            timestructure.wMinute = atoi(mn);
            timestructure.wSecond = seconds;
            timestructure.wMilliseconds = mseconds;
            SetSystemTime(&timestructure);
        }


        MakeLogEntry("Time Synchronization:  After\n");
    }
    else if(!strncmp(Datagram, HEARTBEAT MESSAGE, HEARTBEAT_LENGTH)){
      // got a heartbeat, send it back

      MasterPort->RemoteHost = SourceAddress;
      MasterPort->RemotePort = SourcePort;
      MasterPort->DataToSend = Datagram;
      StatusMessage->Caption = "Status: Got Heartbeat--" + (AnsiString)Datagram;
    }
}
//---------------------------------------------------------------------------


void    TForm1::MakeLogEntry(AnsiString Entry)
{
    AnsiString  final_log_entry;
    SYSTEMTIME  time_structure;
    char        time_string[26];

    GetSystemTime(&time_structure);
    sprintf(time_string, "%4d/%02d/%02d %02d:%02d:%05.2f", time_structure.wYear,
                                                            time_structure.wMonth,
                                                            time_structure.wDay,
                                                            time_structure.wHour,
                                                            time_structure.wMinute,
                                                            time_structure.wSecond+
                                                            (double)time_structure.wMilliseconds/1000.0);

    final_log_entry =  "VBN\t" + (AnsiString)time_string + "\t" +
        Entry ;

    logging_file_stream->WriteBuffer(final_log_entry.c_str(),(long)(final_log_entry.Length()));
}


void __fastcall TForm1::ShutdownButtonClick(TObject *Sender)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;
    AnsiString  error;

    if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
        error = "OPenProcessToken";
    LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);
    if(!ExitWindowsEx( EWX_FORCE|EWX_SHUTDOWN,0))
        error = "ExitWindowsEx";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{


// called when the process begins
    ReadINI();
    ExternalControlPort->Active = true;
    VBN_output_UDP_Port->Active = true;
    VBN_output_UDP_Port->RemoteHost = "127.0.0.1";
    MasterPort->Active = true;
    //MasterPort->RemoteHost = my_master;

    // here is where the logging port should be opened

    TDateTime   Date(Now());
    logging_file_name = "C:\\"+ Date.FormatString("yyyymmdd_hhmm") + ".VBN";
    logging_file_stream = new TFileStream(logging_file_name, fmCreate|fmShareDenyWrite);

    MakeLogEntry("Start\n");


}
//---------------------------------------------------------------------------
void __fastcall TForm1::ReadINI()
{
    AnsiString  ininame;
    TIniFile *pIFEVIni = new TIniFile(INIFILE);
    navigation_executable_name =  strdup(pIFEVIni->ReadString("Executables",
                                    "Navigation","DEFAULT_NAV").c_str());
    collection_executable_name =  strdup(pIFEVIni->ReadString("Executables",
                                    "Collection","DEFAULT_COLL").c_str());
    navigation_and_collection_executable_name =  strdup(pIFEVIni->ReadString("Executables",
                                    "Navigation_and_Collection","DEFAULT_NAV_AND_COLL").c_str());
    for(int i=0; i < 9; i++){
        ininame = "utility" + (AnsiString)i;
        utility_names[i] = pIFEVIni->ReadString("Executables",
                                    ininame,"DEFAULT_UTIL");
    }
    my_master  = pIFEVIni->ReadString("Addresses",
                                    "Master","DEFAULT_MASTER");


}
void TForm1::Launch_Process(AnsiString CommandLine)
{
    PROCESS_INFORMATION ProcessInfo;
    STARTUPINFO         StartupInfo;

    ZeroMemory(&StartupInfo,sizeof(STARTUPINFO));
    StartupInfo.cb = sizeof(STARTUPINFO);

    if(CreateProcess(NULL,CommandLine.c_str(),
                        NULL,
                        NULL,
                        NULL,
                        NORMAL_PRIORITY_CLASS,
                        NULL,
                        NULL,
                        &StartupInfo,
                        &ProcessInfo)){
       // CloseHandle(ProcessInfo.hProcess);
       // CloseHandle(ProcessInfo.hThread);
        process_handle = ProcessInfo.hProcess;
    }
}


