@echo off
setlocal ENABLEDELAYEDEXPANSION
set INSTFILE=V53-534U.EXE
set "INSTFILE_FILECHKINFO=+0003571648 -0089009454"
set "TDA_DRIVER_FILE=TDA204.2.2.8.sys"
set "AEIDIR=D:\AEI"
set "LOGNAME=F.LOG"
set "LOGFILE=%AEIDIR%\%LOGNAME%"


REM DIRECTORY CHECK
if not exist %AEIDIR% mkdir %AEIDIR% >nul 2>&1
if exist %AEIDIR% (
    call:logMsg "F.BAT starting."
    call:logMsg "Change directory to [%AEIDIR%]."
    pushd %AEIDIR% >> "%LOGFILE%" 2>&1
) else (
    call:echoMsg "[%AEIDIR%] cannot be created - cannot install [%INSTFILE%].">> "%LOGNAME%"
    exit /b 1
)

REM Pull latest noteLogger.exe.
if exist "%AEIDIR%\util\noteLogger.exe" (
    call:logMsg "Check for different [noteLogger.exe]."
    move /Y "%AEIDIR%\util\noteLogger.exe" "%AEIDIR%\util\noteLogger.exe-chk" > nul 2>> "%LOGFILE%"
) else (
    call:logMsg "No [noteLogger.exe], extracting it."
)
%INSTFILE% x -o util\noteLogger.exe >> "%LOGFILE%" 2>&1
if not exist "%AEIDIR%\util\noteLogger.exe" (
    call:logMsg "[noteLogger.exe] not present in [%INSTFILE%]."
    if exist "%AEIDIR%\util\noteLogger.exe-chk" (
        move /Y "%AEIDIR%\util\noteLogger.exe-chk" "%AEIDIR%\util\noteLogger.exe" > nul 2>> "%LOGFILE%"
    )
) else if not exist "%AEIDIR%\util\noteLogger.exe-chk" (
    call:logMsg "[noteLogger.exe] has been installed."
) else (
    setlocal ENABLEDELAYEDEXPANSION
    comp /M util\noteLogger.exe-chk util\noteLogger.exe >nul 2>&1
    if !ERRORLEVEL! EQU 0 (
        call:logMsg "[noteLogger.exe] has not changed."
        move /Y "!AEIDIR!\util\noteLogger.exe-chk" "!AEIDIR!\util\noteLogger.exe" > nul 2>> "%LOGFILE%"
    ) else (
        call:logMsg "An updated [noteLogger.exe] has been installed."
        del /F /Q "!AEIDIR!\util\noteLogger.exe-chk" >nul 2>&1
    )
    endlocal
)

REM Determine processor board
if exist C:\ProgramData\Comet\startcom10.bat (
    set DESTBOARD=T10

    if /I "%INSTFILE:~0,3%" NEQ "V53" (
        call:logWithMaintRptAndNotepadOnT10 "Can only install 5.3 software, not [%INSTFILE%], on the [T10] board."
        popd
        exit /b 1
    )
) else (
    set DESTBOARD=LX800

    if /I "%INSTFILE:~0,3%" NEQ "V52" (
        call:logWithMaintRptAndNotepadOnT10 "Can only install 5.2 software, not [%INSTFILE%], on the [LX800] board."
        popd
        exit /b 1
    )
)

call:logMsg "Installing from [%INSTFILE%] to [%DESTBOARD%] board."

REM ------RUNONCE FUNCTIONALITY-------------------
REM check for flag file - and don't ask any questions about the naming convention.
set "F_PSP=%AEIDIR%\F.PSP"
set "ZIP_PSP=%AEIDIR%\ZIP.PSP"
if not exist "%ZIP_PSP%" (
    REM check to see if complete flag exists
    if exist "%F_PSP%" (
        call:logWithMaintRptAndNotepadOnT10 "Reboot complete. F.BAT deployment of [%INSTFILE%] verified. Continuing normal startup sequence."
        call:delFile "%F_PSP%"
        popd
        exit /b 0
    ) else (
        call:logWithMaintRptAndNotepadOnT10 "F.BAT deployment of [%INSTFILE%] failed."
        popd
        exit /b 1
    )
)


REM delete flag file to prevent running F.BAT again on startup.
call:delFile "%ZIP_PSP%"


REM make sure we can clear read-only attributes
set "ATTRIB_ERR=%AEIDIR%\ATTRIB.ERR"
set "ATTRIB_LST=%AEIDIR%\ATTRIB.LST"
set "ATTRIB_EXE=ATTRIB.EXE"
%ATTRIB_EXE% /? >nul 2>&1
if %ERRORLEVEL% NEQ 0 (
    call:logMsg "Extracting %ATTRIB_EXE%."
    %INSTFILE% x -o %ATTRIB_EXE% >> "%LOGFILE%" 2>&1
) else (
    call:logMsg "%ATTRIB_EXE% executes."
)
call:placeAttribExe


REM make sure logfile is less than 250kb
call:Trimfile 250000 "%LOGFILE%"


REM ------clear read only file attributes in D drive---------------------
call:attribClearReadOnly D:\AEI /S
call:attribClearReadOnly D:\MRSCOUNT.* /S
call:attribClearReadOnly D:\NETMRSCT.* /S


REM -------verify package file integrity------------------------
set "FILECHK_EXE=FILECHK.EXE"
if not exist %FILECHK_EXE% (
    call:logMsg "Extracting %FILECHK_EXE%."
    %INSTFILE% x -o %FILECHK_EXE% >> "%LOGFILE%" 2>&1
)
REM filechk is written by comet - checks crc of a file and sets ERRORLEVEL to 0 if pass, 1 if fail
%FILECHK_EXE% %INSTFILE% %INSTFILE_FILECHKINFO% >> "%LOGFILE%" 2>&1
if %ERRORLEVEL% NEQ 0 (
    call:logWithMaintRptAndNotepadOnT10 "[%INSTFILE%] does not match F.BAT. Install aborted. See [%LOGFILE%]."
    call:logMsg "Output of file check:"
    %FILECHK_EXE% %INSTFILE% >> "%LOGFILE%" 2>&1
    popd
    exit /b 1
) else (call:logMsg "Installation payload integrity verified.")

REM -----------------Backup copy of VIO.CFG-----------------------
if exist %AEIDIR%\VIO.CFG (
    copy /Y %AEIDIR%\VIO.CFG %AEIDIR%\BACKUP\VIO.CFG-FOR-F-BAT >> "%LOGFILE%" 2>&1
    call:logMsg "Backed up VIO.CFG."
) else (
    call:logMsg "VIO.CFG does not exist."
)

REM -------------check the payload against the board type----------------------------------
REM Extract unique file for each board type and check them.
call:logMsg "Checking self-extractor version."
%INSTFILE% x -o normaliz.dll startcom10.bat >> "%LOGFILE%" 2>&1

if /I "%DESTBOARD%" EQU "LX800" (
    if exist startcom10.bat (
        call:logWithMaintRptAndNotepadOnT10 "startcom10.bat in [%INSTFILE%] is for the [T10] not the [%DESTBOARD%]. Install aborted."
        call:delFile startcom10.bat
        popd
        exit /b 1
    )
    if not exist normaliz.dll (
        call:logWithMaintRptAndNotepadOnT10 "normaliz.dll is not in [%INSTFILE%] as required for the [%DESTBOARD%]. Install aborted."
        popd
        exit /b 1
    )
) else if /I "%DESTBOARD%" EQU "T10" (
    if exist normaliz.dll (
        call:logWithMaintRptAndNotepadOnT10 "normaliz.dll in [%INSTFILE%] is for the [LX800] not the [%DESTBOARD%]. Install aborted."
        call:delFile normaliz.dll
        popd
        exit /b 1
    )
    if not exist startcom10.bat (
        call:logWithMaintRptAndNotepadOnT10 "startcom10.bat is not in [%INSTFILE%] as required for the [%DESTBOARD%]. Install aborted."
        popd
        exit /b 1
    )
)

call:logMsg "Finished checking self-extractor version."

call:watchdogCheckpoint

REM -------------unpackage the payload----------------------------------
REM Run the self-extractor (7zip) (-o supresses overwrite confirmation)
call:logMsg "Running self-extractor."
%INSTFILE% -o >> "%LOGFILE%" 2>&1
call:logMsg "Finished self-extractor."
call:placeAttribExe
call:watchdogCheckpoint


REM --------------Restore copy of VIO.CFG--------------------------
if exist %AEIDIR%\BACKUP\VIO.CFG-FOR-F-BAT (
    move /Y %AEIDIR%\BACKUP\VIO.CFG-FOR-F-BAT %AEIDIR%\VIO.CFG > nul 2>> "%LOGFILE%"
    call:logMsg "Restored original copy of VIO.CFG."
) else (
    call:logMsg "This APU did not have a local copy of VIO.CFG."
)

call:watchdogCheckpoint



REM -------Place file where they belong to perform their function---------------
(
    echo:
    echo -----------------------------------------------------------------------------------------------
    echo ------------------------------------Installing AEI files --------------------------------------
    echo:
) >> "%LOGFILE%"

if /I "%DESTBOARD%" EQU "LX800" (
    REM ------netmrs reset--------------------------------------
    call:delFile D:\MRSCOUNT.*
    call:delFile D:\NETMRSCT.*
    echo ROMSHELL count from F.BAT> D:\MRSCOUNT.0
    echo minirs count file from F.BAT> D:\NETMRSCT.0

    REM curl updates
    call:placeFile "*.nls"         "C:\Windows\SYSTEM32"
    call:placeFile normaliz.dll    "C:\Windows\SYSTEM32"
    call:placeFile curl.exe        "C:\Program Files\AEI" --copy
    call:placeFile libcurl.dll     "C:\Program Files\AEI" --copy
    call:placeFile CURL_LICENSE    "C:\Program Files\AEI"
    call:placeFile OPENSSH_LICENSE "C:\Program Files\AEI"
    call:placeFile OPENSSL_LICENSE "C:\Program Files\AEI"

    REM other pgm files
    call:placeFile INPOUT32.DLL    "C:\Program Files\AEI" --copy
    call:placeFile LXCOMCHK.BAT    "C:\Program Files\AEI"
    call:placeFile LXCOMCHK.exe    "C:\Program Files\AEI"
    call:placeFile LXSYSCHK.exe    "C:\Program Files\AEI"
    call:placeFile MRRORTXT.BAT    "C:\Program Files\AEI" --copy
    call:placeFile NetMRS.exe      "C:\Program Files\AEI" --copy
    call:placeFile Validate.exe    "C:\Program Files\AEI" --copy
    call:placeFile Y.DAT           "C:\Program Files\AEI" --copy
    call:placeFile $LOC24.DAT      "C:\Program Files\AEI"
    call:placeFile 7za-License.txt "C:\Program Files\AEI"
    call:placeFile 7za.exe         "C:\Program Files\AEI"
    call:placeFile 800BACK.BAT     "C:\Program Files\AEI"
    call:placeFile 800REST.BAT     "C:\Program Files\AEI"

    REM ftp files
    call:placeFile SlimFTPd-License.txt "C:\Program Files\AEI"
    call:placeFile slimftpd.cfg         "C:\Program Files\AEI"
    call:placeFile SlimFTPd.exe         "C:\Program Files\AEI"
) else (
    REM ------netmrs reset--------------------------------------
    call:delFile D:\netmrsct.*
    echo netmrsct file from F.BAT> D:\netmrsct.0

    REM Delete LX800 files which should not be on the T10.
    call:delFile D:\MRSCOUNT.*
    call:delFile "%AEIDIR%\*.NLS"
    call:delFile "%AEIDIR%\NORMALIZ.DLL"
    call:delFile "%AEIDIR%\LXCOMCHK.BAT"
    call:delFile "%AEIDIR%\LXCOMCHK.EXE"
    call:delFile "%AEIDIR%\LXSYSCHK.EXE"
    call:delFile "%AEIDIR%\MRRORTXT.BAT"
    call:delFile "%AEIDIR%\7za License.txt"
    call:delFile "%AEIDIR%\7za-License.txt"
    call:delFile "%AEIDIR%\7za.exe"
    call:delFile "%AEIDIR%\800BACK.BAT"
    call:delFile "%AEIDIR%\800REST.BAT"

    REM start files
    call:placeFile "startcom10.bat" "C:\ProgramData\Comet\Backup" --copy
    call:placeFile "$LOC24.DAT"     "C:\ProgramData\Comet"
    call:placeFile "devcon.exe"     "C:\ProgramData\Comet"
    call:placeFile "INPOUT32.DLL"   "C:\ProgramData\Comet"        --copy
    call:placeFile "ipsetter.ps1"   "C:\ProgramData\Comet"
    call:placeFile "tdacard.dll"    "C:\ProgramData\Comet"        --copy
    call:placeFile "tdacard.dll"    "C:\ProgramData\Comet\Backup" --copy
    call:placeFile "tdawdf.dll"     "C:\ProgramData\Comet"        --copy
    call:placeFile "tdawdf.dll"     "C:\ProgramData\Comet\Backup" --copy
    call:placeFile "VALIDADM.EXE"   "C:\ProgramData\Comet"
    call:placeFile "VALIDATE.EXE"   "C:\ProgramData\Comet"        --copy
    call:placeFile "VALIDATE.EXE"   "C:\ProgramData\Comet\Backup" --copy
    call:placeFile "ziptrain.bat"   "D:\AEI\util"                 --copy

    if exist curl (
        call:placeDir curl "C:\ProgramData\Comet"

        REM the curl files in D:\aei overwrite the files in C:\ProgramData\Comet\curl
        call:placeFile curl.exe    "C:\ProgramData\Comet\curl" --copy
        call:placeFile libcurl.dll "C:\ProgramData\Comet\curl" --copy
    )

    if exist AutoLogon  call:placeDir AutoLogon  "C:\ProgramData\Comet" --purge
    if exist frontpanel call:placeDir frontpanel "C:\ProgramData\Comet" --purge
    if exist NetMrs     call:placeDir NetMrs     "C:\ProgramData\Comet" --purge

    call:placeDir Comet "C:\ProgramData" --copy
    call:placeDir ssh   "C:\ProgramData" --copy

    call:logMsg "------------sc stop slimftpd-------"
    sc stop slimftpd 4:4:2 "F.BAT stopping slimftpd." >> "%LOGFILE%" 2>&1
    call:logMsg "-----------------------------------"
    if exist SlimFTPd call:placeDir SlimFTPd "C:\ProgramData\Comet"

    if not exist !AEIDIR!\NOFTP.DAT (
        call:logMsg "------------sc start slimftpd------"
        sc start slimftpd                                 >> "%LOGFILE%" 2>&1
        call:logMsg "-----------------------------------"
    )

    REM Delete T10 files which aren't supposed to survive the provisioning process.
    call:delFile "%AEIDIR%\AccountHandling.bat"
    call:delFile "C:\ProgramData\Comet\AccountHandling.bat"

    REM Update TDA104 driver.
    setlocal ENABLEDELAYEDEXPANSION
    set DRIVER_RESULT_COUNT=0
    set "TDA_SOURCE=!AEIDIR!\tda204.sys"
    set "DEVCON_EXE=C:\ProgramData\Comet\devcon.exe"
    if not exist "!TDA_SOURCE!" (
        call:logMsg "No driver update file found. Driver [!TDA_DRIVER_FILE!] not installed."
    ) else if not exist "!DEVCON_EXE!" (
        call:logMsg "Devcon driver tool not found. Driver [!TDA_DRIVER_FILE!] not installed."
    ) else (
        call:logMsg "STARTCOM10.BAT will install driver [!TDA_DRIVER_FILE!] on [T10] if APP.MFT passes validation."
    )
    endlocal
)

if /I "%DESTBOARD%" EQU "LX800" (
    REM RTX
    REM stop rtx server before overwriting its program file
    (
        call:echoMsg "---------------Stop RTX------------"
        net stop rtxserver /y
        call:echoMsg "-----------------------------------"
        if %ERRORLEVEL% NEQ 0 call:echoMsg "There was a problem stopping the RTX server."
    ) >> "%LOGFILE%" 2>&1

    REM Do not delete WDIDVR.RTS, we leave a copy in the directory
    call:placeFile WDIDVR.RTS "C:\Program Files\AEI" --copy
    call:placeFile WDIDVR.RTS "C:\Windows\Rtss\009"  --copy
)

(
    echo:
    echo ---------------------------------Done installing AEI files ------------------------------------
    echo -----------------------------------------------------------------------------------------------
) >> "%LOGFILE%"

call:watchdogCheckpoint

REM ---------------CLEANUP ----------------------------------------
REM remove xtrack parameter file that has xtrack enabled by default
call:delFile XTRKSYS.DAT
REM remove MPRXINIGEN.BAT which recreates the MPRX INI files
call:delFile MPRXINIGEN.BAT
REM remove SYSPARMS.CRC to prevent CRC errors
call:delFile SYSPARMS.CRC

if exist "%AEIDIR%\FinalCleanupOnT10.bat" (
    REM call this to delete what we really don't want on there then delete it
    if /I "%DESTBOARD%" EQU "T10" call "%AEIDIR%\FinalCleanupOnT10.bat"
    call:delFile "%AEIDIR%\FinalCleanupOnT10.bat"
)


REM ---------------------------------------------------------------

if exist "%ATTRIB_ERR%" ( del /F /Q "%ATTRIB_ERR%" >nul 2>&1 )
if exist "%ATTRIB_LST%" ( del /F /Q "%ATTRIB_LST%" >nul 2>&1 )

REM CommitAndReboot
(
    echo:
    call:echoMsg "Committing changes and restarting.
    if /I "%DESTBOARD%" EQU "LX800" ewfmgr -all -commit
    echo:
    call:echoMsg "Finished installing package [%INSTFILE%].
    call:echoMsg "====================================================================="

    REM startup.bat will not restart, so do it here. F.BAT will just run again. Unfortunate, but better than having to update startup.bat""
    call:echoWithMaintRptAndNotepadOnT10 "[%INSTFILE%] Install Complete." > "%F_PSP%"
    type "%F_PSP%"
) >> "%LOGFILE%" 2>&1

if /I "%DESTBOARD%" EQU "LX800" (
    call:logMsg "Rebooting [%DESTBOARD%]."
    xpepm -restart >> "%LOGFILE%" 2>&1
) else if /I "%DESTBOARD%" EQU "T10" (
    call:placeFile "startcom10.bat" "C:\ProgramData\Comet" --move
    call:logMsg "Rebooting [%DESTBOARD%]."
    shutdown /r /t 2 /c "Installing package [%INSTFILE%]" >> "%LOGFILE%" 2>&1
    timeout /t -1 /nobreak >> "%LOGFILE%" 2>&1
) else (
    call:logMsg "Unknown board [%DESTBOARD%], not rebooting."
)

popd
exit /b 0

:attribClearReadOnlyXP filespec [/S]

    setlocal ENABLEDELAYEDEXPANSION
    set "GIVEN_NAME=%~1"

    if "%GIVEN_NAME:~-1,1%" EQU "*" (
        set "NAME=%~dp1\*"
        set CLEAR=TRUE
        set FOUND=TRUE
    ) else (
        set "NAME=%~f1"
        if exist "!NAME!" (
            set FOUND=TRUE

            REM check if read-only

            %ATTRIB_EXE% "!NAME!" > "%ATTRIB_LST%"

            set /P ATTRIB_LINE=<"%ATTRIB_LST%"

            if "%ATTRIB_LINE:~5,1%" EQU "R" (
                set CLEAR=TRUE
            ) else (
                set CLEAR=FALSE
            )
        ) else (
            set CLEAR=FALSE
            set FOUND=FALSE
        )
    )

    if "!FOUND!" EQU "TRUE" (
        if "!CLEAR!" EQU "TRUE" (
            call:logMsg "Making !NAME! writeable...."

            if "%~2" NEQ "" (
                set "SUB_DIR_OPT=%~2 /D "
            ) else (
                set "SUB_DIR_OPT="
            )

            %ATTRIB_EXE% -r "!NAME!" !SUB_DIR_OPT! > "%ATTRIB_ERR%" 2>&1

            set /P ERR_LINE=<"%ATTRIB_ERR%"

            if "%ERR_LINE%" NEQ "" (
                call:logMsg "------------attrib -r !NAME! !SUB_DIR_OPT!-----"
                type "%ATTRIB_ERR%" >> "%LOGFILE%"
                call:logMsg "----------------------------------------"
            )
        ) else (
            call:logMsg "!NAME! already writeable."
        )
    ) else (
        call:logMsg "!NAME! not found, already writeable...."
    )

exit /b 0

REM on the T10, we don't change attributes on the C Drive
:attribClearReadOnlyT10ExceptCDriveOne filespec [/S]

    if /I "%~d1" NEQ "C:" (
        if exist "%~f1" (
            if exist "%~f1"\* (
                REM directory
                if /I "%~2" EQU "/S" (
                    takeown /f "%~f1" /r /d y         >> "%LOGFILE%" 2>&1
                    icacls %~f1\  /grant cmtuser:F    >> "%LOGFILE%" 2>&1
                    icacls %~f1\* /grant cmtuser:F /t >> "%LOGFILE%" 2>&1
                )
            ) else (
                takeown /f "%~f1"            >> "%LOGFILE%" 2>&1
                icacls %~f1 /grant cmtuser:F >> "%LOGFILE%" 2>&1
            )
        ) else if exist "%~dp1" (
            takeown /f "%~dp1"             >> "%LOGFILE%" 2>&1
            icacls %~dp1\ /grant cmtuser:F >> "%LOGFILE%" 2>&1
        )
    )

exit /b 0

REM on the T10, we don't change attributes on the C Drive
:attribClearReadOnlyT10ExceptCDrive filespec [/S]

    echo "%1" | findstr /L * >nul
    if %ERRORLEVEL% EQU 0 (
        for %%a in ("%~1") do (
            call:attribClearReadOnlyT10ExceptCDriveOne "%%~fa"
        )
        for /D %%a in ("%~1") do (
            call:attribClearReadOnlyT10ExceptCDriveOne "%%~fa" %2
        )
    ) else (
        call:attribClearReadOnlyT10ExceptCDriveOne "%~1" %2
    )

exit /b 0

REM on the T10, we don't change attributes on the C Drive
:attribClearReadOnly filespec [/S]

    if /I "%DESTBOARD%" EQU "T10" (
        call:attribClearReadOnlyT10ExceptCDrive "%~1" %2
    ) else (
        call:attribClearReadOnlyXP "%~1" %2
    )

exit /b 0

:delFile file

    if exist "%~f1" (
        call:logMsg "Delete file [%~f1]"
        del /F /Q "%~f1" >nul 2>&1

        if exist "%~f1" (
            call:logMsg "Couldn't delete file [%~f1]"
            exit /b 1
        )
    )

exit /b 0

:echoWithMaintRptAndNotepadOnT10 message

    set "MESSAGE=[%DATE% %TIME%] %~1"

    echo %MESSAGE%

    if /I "%DESTBOARD%" EQU "T10" (
        REM Place installation complete message in site notepad and SYS$ERR.LOG.
        if not exist "D:\AEI\ERRORLOG.CSV" (
            echo Sequence Number,Error Code,Error Message>> "D:\AEI\ERRORLOG.CSV"
        )
        REM Train Sequence Number 0000 below is properly not associated with any train.
        REM Error Code 003 below is "General Info".
        echo 0000,003,%MESSAGE%>> "D:\AEI\ERRORLOG.CSV"
    )

exit /b 0

:echoMsg message

    echo [%DATE% %TIME%] %~1

exit /b 0

:logMsg message

    call:echoMsg "%~1" >> "%LOGFILE%" 2>&1

exit /b 0

:logWithMaintRptAndNotepadOnT10 message

    call:echoWithMaintRptAndNotepadOnT10 "%~1" >> "%LOGFILE%" 2>&1

exit /b 0

:makeDest destination

    if not exist "%~f1" (
        %ATTRIB_EXE% /? >nul 2>&1
        if %ERRORLEVEL% EQU 0 if /I "%DESTBOARD%" EQU "LX800" ( call:attribClearReadOnlyXP "%~dp1" )
        call:logMsg "Create directory [%~f1]"
        mkdir "%~f1"

        if not exist "%~f1" (
            call:logMsg "Couldn't create directory [%~f1]"
            exit /b 1
        )
    )

exit /b 0

:placeAttribExe

    if exist "%AEIDIR%\%ATTRIB_EXE%" (
        if not exist "C:\Windows\SYSTEM32\%ATTRIB_EXE%" (
            call:placeFile "%AEIDIR%\%ATTRIB_EXE%" "C:\Windows\SYSTEM32"
        ) else (
            call:delFile "%AEIDIR%\%ATTRIB_EXE%"
        )
    )

exit /b 0

:: --copy is the default
:: if you specify --purge the directory within the destination is completely deleted before being copied from the extraction
:placeDir directory destination [--copy|--purge]

    if not exist "%~f1" (
        REM it doesn't exist, log
        call:logMsg "F.BAT Couldn't install non-existant directory expected from extraction: [%~1] - inspect file package integrity."
    ) else if not exist "%~f1"\* (
        REM it's not a directory, log
        call:logMsg "F.BAT [%~1] is a file, not a directory as expected - inspect file package integrity."
    ) else (
        REM it does exist, put it where it goes and delete if necessary
        setlocal ENABLEDELAYEDEXPANSION
        call:makeDest "%~2"
        if ERRORLEVEL 1 endlocal & exit /b 1
        if /I "%~3" EQU "" (
            set "replaceOpt=--copy"
        ) else (
            set "replaceOpt=%~3"
        )

        if /I "%~3" EQU "--purge" (
            if exist "%~f2\%~nx1" (
                if /I "%DESTBOARD%" EQU "LX800" ( call:attribClearReadOnlyXP "%~f2\%~nx1" /S )
                rmdir /S /Q "%~f2\%~nx1" >nul 2>&1
            )
            if exist "%~f2\%~nx1" (
                call:logMsg "F.BAT Couldn't remove directory to be replaced: [%~f2\%~nx1]."
                exit /b 1
            )
        )

        call:makeDest "%~2\%~nx1"
        if ERRORLEVEL 1 endlocal & exit /b 1

        xcopy "%~f1" "%~f2\%~nx1" /E /Y>> "%LOGFILE%" 2>&1
        if ERRORLEVEL 1 (
            call:logMsg "F.BAT Couldn't copy directory: [%~f1] to [%~f2\%~nx1]."
            exit /b 1
        )

        rmdir /S /Q "%~f1" >> "%LOGFILE%" 2>&1
        if exist "%~f1" (
            call:logMsg "F.BAT Couldn't remove extraction directory: [%~f1]."
            exit /b 1
        )

        call:logMsg "F.BAT installed directory [%~f2\%~nx1]. Option: [!replaceOpt!]."
        endlocal
    )

exit /b 0

REM --move is the default
:placeFile file destination [--move or --copy]

    if not exist "%~f1" (
        REM it doesn't exist, log
        call:logMsg "F.BAT Couldn't install non-existant file expected from extraction: [%~1] - inspect file package integrity."
    ) else if exist "%~f1"\* (
        REM it's not a file, log
        call:logMsg "F.BAT [%~1] is a directory, not a file as expected - inspect file package integrity."
    ) else (
        REM it does exist, put it where it goes and delete if necessary

        setlocal ENABLEDELAYEDEXPANSION
        call:makeDest "%~f2"
        if !ERRORLEVEL! NEQ 0 ( exit /b 1 )
        set "destFile=%~f2\%~nx1"

        REM --move is the default
        if "%3"=="" (
            set "opt=--move"
        ) else (
            set "opt=%3"
        )

        if exist "!destFile!"\* (
            REM if dest is a directory remove it
            call:logMsg "F.BAT is replacing the directory [!destFile!] with a file of the same name."
            if /I "!DESTBOARD!" EQU "LX800" ( call:attribClearReadOnlyXP "%~f2" /S )
            rmdir /S /Q "!destFile!" >> "!LOGFILE!" 2>&1
            if exist "!destFile!" (
                call:logMsg "F.BAT Couldn't remove destination: [!destFile!]."
                exit /b 1
            )
        )
        REM if source matches dest, don't mess with dest
        comp /M "%~f1" "!destFile!" >nul 2>&1
        if !ERRORLEVEL! EQU 0 (
            call:logMsg "F.BAT file [!destFile!] already matches the installation file. No change. Option: [!opt!]"
        ) else (
            if /I "!DESTBOARD!" EQU "LX800" ( call:attribClearReadOnlyXP "%~2\%~nx1" )
            REM check copy failure
            copy /y "%~f1" "!destFile!" > NUL 2>> "!LOGFILE!"
            if !ERRORLEVEL! NEQ 0 (
                call:logMsg "F.BAT Problem [err=!ERRORLEVEL!] installing file [!destFile!]. Option: [!opt!]"
            ) else (
                REM SUCCESS
                call:logMsg "F.BAT installed file [!destFile!]. Option: [!opt!]"
            )
        )

        if "!opt!" EQU "--move" (
            del /F /Q "%~f1" >nul 2>&1
        )

    )

exit /b 0


:replaceIfNewer directory sourceFile destFile

    setlocal ENABLEDELAYEDEXPANSION
    set "DIRECTORY=%~f1"
    set "SRC_FILE=%~2"
    set "DEST_FILE=%~3"

    if not exist "!DIRECTORY!"\* (
        REM it's not a directory, log
        call:logMsg "Replace directory [!DIRECTORY!] is a file, not a directory as expected."
    ) else (
        pushd "!DIRECTORY!"
        if exist "!SRC_FILE!" (
            if exist "!SRC_FILE!"\* (
                REM it's not a file, log
                call:logMsg "Replace source [!SRC_FILE!] is a directory, not a file as expected."
            ) else if exist "!DEST_FILE!"\* (
                REM it's not a file, log
                call:logMsg "Replace destination [!DEST_FILE!] is a directory, not a file as expected."
            ) else (
                comp /M "!SRC_FILE!" "!DEST_FILE!" >nul 2>&1
                if !ERRORLEVEL! EQU 0 (
                    call:logMsg "Replace source [!SRC_FILE!] already matches destination [!DEST_FILE!]. Deleting [!SRC_FILE!]."
                ) else (
                    for %%i in (!SRC_FILE!)  do set SRC_DATE=%%~ti
                    for %%i in (!DEST_FILE!) do set DEST_DATE=%%~ti

                    if /I "!SRC_DATE!" EQU "!DEST_DATE!" (
                        call:logMsg "Replace source [!SRC_FILE!] has the same date as destination [!DEST_FILE!]. Deleting [!SRC_FILE!]."
                    ) else (
                        for /F %%i in ('dir /B /O:D !SRC_FILE! !DEST_FILE!') do set NEWEST=%%i

                        if /I "!SRC_FILE!" EQU "!NEWEST!" (
                            call:logMsg "Replace source [!SRC_FILE!] is newer than destination [!DEST_FILE!]. Replacing [!DEST_FILE!] with [!SRC_FILE!]."
                            copy /y "!SRC_FILE!" "!DEST_FILE!" > NUL 2>> "!LOGFILE!"
                        ) else (
                            call:logMsg "Replace source [!SRC_FILE!] is older than destination [!DEST_FILE!]. Deleting [!SRC_FILE!]."
                        )
                    )
                )

                del /F /Q "!SRC_FILE!" >nul 2>&1
            )
        )

        popd
    )

exit /b 0


:watchdogCheckpoint

    if /I "%DESTBOARD%" EQU "LX800" (
        call:logMsg "Stroke watchdog on %DESTBOARD%."
        strokewd >> "%LOGFILE%" 2>&1
    )

exit /b 0

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::Trimfile - use to trim a file, duh. :::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Trimfile maxLogSizeBytes logFile
    setlocal
    call:echoMsg "Starting trim."
    call:echoMsg "Starting trim.">> "%~2"
    ::make sure logsize is numeric, if not, its an input error
    for /f "delims=1243567890" %%a in ("%~1") do (call:usage & exit /b 1)
    set maxLogSize=%~1

    ::trim it to 3/4 below the threshold to cause hysteresis
    set /a targetLogSize=maxLogSize*3/4

    ::force logFile to exist
    call:makeDest "%~dp2"
    set currentLogFile="%~f2"
    if not exist %currentLogFile% (echo: > NUL 2> %currentLogFile%)
    set tempLogFile="%~f2.temp"

    ::get the current log size
    for %%a in (%currentLogFile%) do (set currentFileSize=%%~za)

    ::check to see if the log is still small enough to skip
    if %currentFileSize% LSS %maxLogSize% (
        call:echoMsg "Logsize [%currentFileSize%] is within max size limit [%maxLogSize%]!"
        call:echoMsg "Logsize [%currentFileSize%] is within max size limit [%maxLogSize%]!">> %currentLogFile%
        exit /b 0
    )

    ::determine how many lines to delete
    call:getNumberofLinesToDelete %currentLogFile% %targetLogSize% startingLine totalLines

    ::remove that many lines     numlines          source       destination
    call:copyFileStartingFrom %startingLine% %currentLogFile% %tempLogFile%

    ::copy temp into final file and remove temp file
    if exist %tempLogFile% move /Y %tempLogFile% %currentLogFile% > nul 2> nul

    ::gets the new size
    for %%a in (%currentLogFile%) do (set newFileSize=%%~za)
    call:echoMsg "LOG FILE TRIMMED -- [%numLinesToDelete%] oldest lines removed of total [%totalLines%]. new size:[%newFileSize% bytes]"
    call:echoMsg "LOG FILE TRIMMED -- [%numLinesToDelete%] oldest lines removed of total [%totalLines%]. new size:[%newFileSize% bytes]">> %currentLogFile%
exit /b 0


:getNumberofLinesToDelete filepath targetSize [numberofLines] [totalLines]
    if not exist "%~f1" (
        set numLinesToDelete=0
        set linecount=0
    ) else (
        ::get file size
        for %%a in ("%~f1") do (set fileSize=%%~za)

        ::get number of lines
        set linecount=0
        for /f %%a in ("%~f1") do (set /a "linecount+=1")

        ::compute number of lines to delete based on average bytes per line
        set /a "averageBytesPerLine=fileSize/linecount"
        set /a "bytesToDelete=fileSize-%~2"
        set /a "numLinesToDelete=bytesToDelete/averageBytesPerLine"
    )

    set %~3=%numLinesToDelete%
    set %~4=%linecount%
exit /b 0



:copyFileStartingFrom line sourceFile destFile
    set dest="%~3"

    ::beginning of new log
    call:echoMsg "LOG FILE TRIM"
    > %dest% call:echoMsg "LOG FILE TRIM"

    ::extra parentheses are so that CMD.exe completely expands the for-loop before writing to file
    ::not doing this is VERY slow
    (
        for /f "skip=%~1 delims=" %%a in (%~2) do (
            echo %%a
        )
    )>> %dest%

exit /b 0


:usage
    echo Trimlog - trims off the oldest lines in a time-ascending log
    echo Syntax: trimfile maxLogSizeBytes file

exit /b 0
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::End of Trimfile :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
