$ifndef WIN32
$define WIN32
$endif

'includes
$include "windowssdk.inc"
$include "stdio.inc"
$include "Psapi.inc"
$include "TlHelp32.inc"

'function overrides
$UNDECLARE GetCommandLineA
DECLARE IMPORT,GetCommandLineA(),STRING 

$UNDECLARE CommandLineToArgvW
DECLARE IMPORT, CommandLineToArgvW(lpCmdLine as WSTRING, pNumArgs as POINTER),POINTER

$UNDECLARE GlobalFree
DECLARE IMPORT, GlobalFree(hMem as UINT),INT

'variables
UINT fromId, toId=-1, translateBtnId, clearBtnId, dicFrom, dicTo, dic, swapLangId
UINT dicFromParent, dicToParent
ISTRING dataFrom[60000], dataTo[60000]
STRING lec=""
INT SECONDS_TO_WAIT_FOR_TRANSLATOR=10
INT counter=0, index=-1

UINT fromCtrlId=0x7D1, toCtrlId=0x0, translateCtrlId=0x210, clearCtrlId=0x270
UINT dicFromCtrlId=0x6A5, dicToCtrlId=0x6A6, swapLangCtrlId=0x6A7

STRING dicFromExt="English", dicToExt="Portuguese", dicTemp=""

'console control handler - if console is visible, it detects when console closes
SetConsoleCtrlHandler(&cleanup,true)

OPENCONSOLE

'read LEC LogoTrans.exe path
lec=GetCmdArgument(GetCommandLineA())

IF RTRIM$(LTRIM$(lec))="?" OR RTRIM$(LTRIM$(lec))="\?" OR RTRIM$(LTRIM$(lec))="/?" OR RTRIM$(LTRIM$(lec))="help" OR RTRIM$(LTRIM$(lec))="h" OR RTRIM$(LTRIM$(lec))="/h" OR RTRIM$(LTRIM$(lec))="\h"
	PRINT "Usage: leccomm [full path to LEC LogoTrans.exe]"
	PRINT ""
	PRINT "If a LEC LogoTrans window is opened already, though, path is not needed."
	SETEXITCODE(1)
	END
ENDIF

'close all previous leccomm.exe opened apps
DWORD aProcesses[1024], cbNeeded, cProcesses, procId, bProcess[512] 
HANDLE hProcess, hTokenSelf, hProcSelf
closeOtherLECComm("leccomm.exe")

'check if there's already a LEC LogoTrans window opened; if not, open one
IF findwin("LEC LogoTrans")=0
	SYSTEM lec
ENDIF

'tries to open LEC LogoTrans program; path to such program should be written in command line
DO
	_sleep(1000)
	chwnd = findwin("LEC LogoTrans")
	counter++
UNTIL chwnd <>0 OR counter>=SECONDS_TO_WAIT_FOR_TRANSLATOR

'error if not found
IF counter>=SECONDS_TO_WAIT_FOR_TRANSLATOR
	SETEXITCODE(2)
ELSE
	'configure and define control handlers
	EnumChildWindows(chwnd, &DefineControlHandlers, 0)

	'set starting dictionaries FROM and TO
	setDictionary(dicFromExt, dicFrom, dicFromCtrlId, dicFromParent)
	setDictionary(dicToExt, dicTo, dicToCtrlId, dicToParent)

	BOOL check=true	
	DO	
		dataFrom=""
		dataTo=""
		counter=0

		'INPUT "",dataFrom
		'check new data
		scanf("%[^\n]",dataFrom)
	
		IF LTRIM$(RTRIM$(dataFrom))<>"" 
			'command to change origin language
			IF LEFT$(dataFrom,15)="TRANSLATE_FROM "
				dicTemp=LTRIM$(MID$(dataFrom,15))
				IF setDictionary(dicTemp, dicFrom, dicFromCtrlId, dicFromParent)=1 THEN dicFromExt=dicTemp
			'command to change destination language
			ELSEIF LEFT$(dataFrom,13)="TRANSLATE_TO "
				dicTemp=LTRIM$(MID$(dataFrom,13))
				IF setDictionary(dicTemp, dicTo, dicToCtrlId, dicToParent)=1 THEN dicToExt=dicTemp
			'command to swap languages
			ELSEIF dataFrom="SWAP_LANG"
				SENDMESSAGE(swapLangId, WM_LBUTTONDOWN, 0, 0)
				SENDMESSAGE(swapLangId, WM_LBUTTONUP, 0, 0)
			'translation
			ELSE

				'send info to proper window for translation
				SENDMESSAGE(fromId,WM_SETTEXT,0,dataFrom)
	
				'translate button press - window handle, enter order, control id, control handle
				SENDMESSAGE(chwnd, WM_COMMAND, translateCtrlId, translateBtnId)
	
				'tries to get translated text
				DO
					_sleep(500)
					SENDMESSAGE(toId, WM_GETTEXT, 60000 , dataTo)
					counter++
				UNTIL dataTo<>"" OR counter>=20
	
				'closes program, on error
				IF counter>=20
					SETEXITCODE(3)
					check=false
				ELSE
					'clear button press
					SENDMESSAGE(chwnd, WM_COMMAND, clearCtrlId, clearBtnId)
					'prints translated text to stdOut
					PRINT dataTo
				ENDIF
			ENDIF
		ENDIF

		'clean buffer
		int p
		scanf("%*[^\n]",p)
		scanf("%*c",p)
	
	UNTIL check=false
ENDIF

CLOSECONSOLE

'kill LEC LogoTrans app - if console is not visible, handle won't work and so at least at this point will kill the app
killProcess(chwnd)

END


SUB cleanup(t:UINT), INT
	'closes LEC LogoTrans app
	IF t<>5
		SENDMESSAGE(chwnd, WM_CLOSE, 0, 0)
		killProcess(chwnd)
	ENDIF
/*
0 	A CTRL+C signal was received, either from keyboard input or 
	from a signal generated by the GenerateConsoleCtrlEvent function. 

1 	A CTRL+BREAK signal was received, either from keyboard input 
	or from a signal generated by GenerateConsoleCtrlEvent. 

2 	A signal that the system sends to all processes attached to 
	a console when the user closes the console (either by clicking 
	Close on the console window's window menu, or by clicking 
	the End Task button command from Task Manager). 

5 	A signal that the system sends to all console processes 
	when a user is logging off. This signal does not indicate 
	which user is logging off, so no assumptions can be made.
	 Note that this signal is received only by services. Interactive 
	applications are terminated at logoff, so they are not 
	present when the system sends this signal. 

6 	A signal that the system sends to all console processes when 
	the system is shutting down.
*/
	RETURN 0
ENDSUB

SUB setDictionary(STRING text, UINT ctrlWindowHandler, UINT ctrlId, UINT ctrlParentWindowHandler), INT
	INT result=0
	INT index=SENDMESSAGE(ctrlWindowHandler,CB_FINDSTRING ,-1,text)
	IF index<>-1
		SENDMESSAGE(ctrlWindowHandler,CB_SETCURSEL,index,"")
		SENDMESSAGE(ctrlParentWindowHandler, WM_COMMAND,MAKEWPARAM(ctrlId,CBN_SELCHANGE),ctrlWindowHandler)
		result=1
	ENDIF
	RETURN result
ENDSUB

SUB findwin(window AS STRING),INT
	 hwnd = FindWindowA(NULL,window)
	 RETURN hwnd
ENDSUB

SUB DefineControlHandlers(HWND hwnd, LPARAM lParam)
	IF GetDlgItem(hwnd, fromCtrlId)<>0 THEN fromId = GetDlgItem(hwnd, fromCtrlId)
	IF GetDlgItem(hwnd, toCtrlId)<>0 AND toId=-1 THEN toId = GetDlgItem(hwnd, toCtrlId)
	IF GetDlgItem(hwnd, translateCtrlId)<>0 THEN translateBtnId = GetDlgItem(hwnd, translateCtrlId)
	IF GetDlgItem(hwnd, clearCtrlId)<>0 THEN clearBtnId = GetDlgItem(hwnd, clearCtrlId)
	IF GetDlgItem(hwnd, swapLangCtrlId)<>0 THEN swapLangId = GetDlgItem(hwnd, swapLangCtrlId)
	IF GetDlgItem(hwnd, dicFromCtrlId)<>0 
		dicFrom = GetDlgItem(hwnd, dicFromCtrlId)
		dicFromParent = hwnd
	ENDIF
	IF GetDlgItem(hwnd, dicToCtrlId)<>0
		dicTo = GetDlgItem(hwnd, dicToCtrlId)
		dicToParent = hwnd
	ENDIF
	return 1
ENDSUB

SUB GetCmdArgument(STRING _command), STRING
	POINTER _pszArglist
	WORD _nArgs
	INT _i
	STRING _exe,_params:_params = ""

	_pszArglist = CommandLineToArgvW(S2W(_command), &_nArgs)
	IF(_nArgs<>0)
		_exe = W2S(*<WSTRING>*<POINTER>_pszArglist)
		FOR _i=1 TO _nArgs-1
			_params += W2S(*<WSTRING>*<POINTER>(_pszArglist+(_i*4))) + " "
		NEXT _i
	ENDIF
	IF (_pszArglist) THEN GlobalFree(_pszArglist)
	RETURN _params
ENDSUB









SUB closeOtherLECComm(STRING fileNameToFindPID),INT
	'// required by fined PIDByName
	CONST TH32CS_SNAPHEAPLIST	 =0x00000001
	CONST TH32CS_SNAPPROCESS	 =0x00000002
	CONST TH32CS_SNAPTHREAD		 =0x00000004
	CONST TH32CS_SNAPMODULE		 =0x00000008
	CONST TH32CS_SNAPMODULE32	 =0x00000010
	CONST TH32CS_SNAPALL		 =(TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
	CONST TH32CS_INHERIT		 =0x80000000
	CONST PROCESS_ALL_ACCESS	 =0x1F0FFF

	TYPE PROCESSENTRY32
		 UINT dwSize
		 UINT cntUsage
		 UINT th32ProcessID
		 UINT th32DefaultHeapID
		 UINT th32ModuleID
		 UINT cntThreads
		 UINT th32ParentProcessID
		 UINT pcPriClassBase
		 UINT dwFlags
		 ISTRING szExeFile[259]
	ENDTYPE
	
	DEF pe:PROCESSENTRY32
	STRING item,PID
	INT retval, x = 0

	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)
	pe.dwSize=LEN(pe)
	retval=Process32First(hSnapshot,pe)

	DO
		IF LCASE$(pe.szExeFile) = LCASE$(fileNameToFindPID)
			IF pe.th32ProcessID<>GetCurrentProcessId()
				killProcess(pe.th32ProcessID)
				'CloseHandle(hSnapshot)
				'RETURN pe.th32ProcessID
			ENDIF
		ENDIF
		item = pe.szExeFile
		PID = STR$(pe.th32ProcessID)
		'PRINT "["+pid+"] "+item
		x++
		dwPriorityClass = 0
		hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pe.th32ProcessID)
		IF hProcess = NULL
			'PRINT error("Open Process Fail findpidbyname ")
		ELSE
			dwPriorityClass = GetPriorityClass(hProcess)
			IF dwPriorityClass <>0
				'print dwPriorityClass 
			ELSE
				'PRINT error("dwPriorityClass")
			ENDIF
			CloseHandle(hProcess)
		ENDIF
		pe.dwSize=len(PROCESSENTRY32)
		retval=Process32Next(hSnapshot,pe)
	UNTIL retval = false

	CloseHandle(hSnapshot)
	RETURN 0
ENDSUB

SUB findProcessIdByName(INT processID),INT
	INT ret 
	STRING szProcessName

	szProcessName = SPACE$(255)
	hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE,processID )
	IF hProcess <>0
		ret = EnumProcessModules( hProcess, bProcess[0], LEN(bProcess), &cbNeeded)
		IF ret <>0
			ret = GetModuleBaseName(hProcess, bProcess[0], szProcessName,LEN(szProcessName))
			IF ret <>0
				'PRINT szProcessName
			ELSE
				'PRINT error("GetModule")
			ENDIF
		ELSE
			'error("EnumProcessModules")
		ENDIF
		CloseHandle( hProcess )
	ELSE
		'PRINT error( "Openprocess Failed"+STR$(processID))
	ENDIF
	RETURN 0
ENDSUB

SUB killProcess(INT PID)
	HANDLE hProc

	hProc = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_TERMINATE, FALSE, PID)
	IF hProc <>0
		IF TerminateProcess(hProc, 0) <>0
			'MessageBox (NULL, "CLOSED", "CLOSED", @MB_ICONSTOP) 
		ELSE
			'MessageBox (NULL, error("SUB KillProcess "), "NOT CLOSED PID"+STR$(procId), @MB_ICONSTOP) 
			CloseHandle(hProc)
		ENDIF
	ELSE
		'MessageBox (NULL, error("SUB KillProcess "),"I CANT CLOSE "+STR$(procId),@MB_ICONSTOP) 
	ENDIF
ENDSUB


SUB SetPrivilege(HANDLE hToken, STRING lpszPrivilege,INT bEnablePrivilege) 

	TYPE TOKEN_PRIVILEGES
		DEF PrivilegeCount:INT
		DEF LowPart:INT
		DEF HighPart:INT
		DEF Attributes:INT
	ENDTYPE

	DEF tp:TOKEN_PRIVILEGES
	DEF luid:LUID

	IF LookupPrivilegeValue(NULL,lpszPrivilege,&luid ) = 0
		'error("LookupPrivilegeValue error: ")
		RETURN FALSE
	ENDIF
	tp.PrivilegeCount = 1
	tp.Privileges[0].Luid = luid
	
	IF bEnablePrivilege = true
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
	ELSE
		tp.Privileges[0].Attributes = 0
	ENDIF

	'// Enable the privilege or disable all privileges.
	IF AdjustTokenPrivileges(hToken,FALSE, &tp, LEN(TOKEN_PRIVILEGES), 0, 0) =0
		'error("AdjustTokenPrivileges error:") 
		RETURN FALSE 
	ENDIF 

	IF GetLastError() = ERROR_NOT_ALL_ASSIGNED
		'PRINT "The token does not have the specified privilege."
		RETURN FALSE
	ENDIF
	RETURN TRUE
ENDSUB

SUB error(STRING errorCall),STRING  
	INT CodeErrorId, nBufferSize, flag 
	STRING sBuffer,retError  
	nBufferSize = 1024 
	sBuffer = STRING$(nBufferSize, CHR$(0)) 
	flag=FORMAT_MESSAGE_FROM_SYSTEM 
	CodeErrorId=GetLastError() 
	FormatMessage(flag, NULL,CodeErrorId,LANG_NEUTRAL, sBuffer, nBufferSize ,NULL ) 
	retError = errorCall+" / "+sBuffer+" / ErrorID = "+STR$(CodeErrorID)
	RETURN retError
ENDSUB