'
' Create language translation DLLs
'
' cscript Create_DLLs.vbs [LL | /h | /help | /?] [x86 | x64]
'   LL - optional single language
'   /h | /help | /? - show help
'   x86 | x64 - architecture choice. If LL is given and architecture 
'     is omitted, defaults to x86.
' If no arguments are supplied, help is shown.
'
' The list of available translations is defined by the Tranlsations.txt file.
'
' See Readme.txt for more information.
'

If Instr(1, WScript.FullName, "cscript.exe", vbTextCompare) = 0 then
    MsgBox "This script must be executed by cscript.exe" & vbCRLF & _
           "e.g. cscript Create_DLLs.vbs", _
           vbCritical, _
           "Error: " & Wscript.ScriptFullName
    ' return error code to caller
    Wscript.Quit(99)
End If

' Default conditions
DO_ALL = True
ARCH = "x86"
DO_COUNTRY = Empty

' Command argument validation
' Valid argument combinations
'   None | /h | /help | /?
'   LL
'   x86
'   x64
'   LL x86
'   LL x64
Select Case Wscript.Arguments.Count
  Case 1
    ' The single argument can be a country or an architecture spec
    DIM Arg1
    Arg1 = UCase(Wscript.Arguments(0))
    Select Case Arg1
      Case "X86"
        ARCH = "x86"
      Case "X64"
        ARCH = "x64"
      Case "/HELP", "/H", "/?" 
        Usage
        Wscript.Quit(0)
      Case Else
        if Len(Arg1) = 2 Then
          DO_ALL = False
          DO_COUNTRY = Arg1
        Else
          ' Currently languages must be 2 characters long
          Usage
          Wscript.Quit(0)
        End If
    End Select
  Case 2
    ' The first arg is a language and the second is the architecture
    DO_ALL = False
    DO_COUNTRY = UCase(Wscript.Arguments(0))
    If Len(DO_COUNTRY) <> 2 Then
      ' Currently languages must be 2 characters long
      Usage
      Wscript.Quit(0)
    End If
    Select Case Wscript.Arguments(1)
      Case "x86"
        ARCH = "x86"
      Case "x64"
        ARCH = "x64"
      Case Else
        Usage
        Wscript.Quit(0)
    End Select
  Case Else
    Usage
    Wscript.Quit(0)
End Select

Dim CURPATH, TOOLS, RESTEXT, RESPWSL, BASE_DLL, DEST_DIR, DO_ALL, DO_COUNTRY, ARCH

' Configure tool and output location

If ARCH = "x86" Then
  ' 32-bit tools
  TOOLS = "..\..\..\..\build\bin"
  RESTEXT = TOOLS & "\restext\release\ResText.exe"
  RESPWSL = TOOLS & "\respwsl\release\ResPWSL.exe"
  BASE_DLL = "..\..\..\..\build\bin\pwsafe\release\pwsafe_base.dll"
  DEST_DIR = "..\..\..\..\build\bin\pwsafe\I18N\"
  WScript.Echo "Creating 32-bit language DLLs"
Else
  ' 64-bit tools
  TOOLS = "..\..\..\..\build\bin"
  RESTEXT = TOOLS & "\restext\release64\ResText.exe"
  RESPWSL = TOOLS & "\respwsl\release64\ResPWSL.exe"
  BASE_DLL = "..\..\..\..\build\bin\pwsafe\release64\pwsafe_base.dll"
  DEST_DIR = "..\..\..\..\build\bin\pwsafe\I18N64\"
  WScript.Echo "Creating 64-bit language DLLs"
End If

' Used through out the script
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")

' File system definitions for reading/writing files
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

' Make absolute addresses
DEST_DIR = objFSO.GetAbsolutePathName(DEST_DIR)
DEST_DIR = DEST_DIR & "\"

CURPATH = objFSO.GetAbsolutePathName(".")
CURPATH = CURPATH & "\"

' Sometimes the delete files do not work for permission failures. So...
' It is not clear what permissions are a problem. Could be that
' the script needs to be run as Administrator, but there appears
' to be nothing special about the permissions of the DLLs.
WScript.Echo " "
WScript.Echo "*** Please ensure that you have deleted ALL DLLs from this script directory:"
WScript.Echo  "    " & CURPATH
WScript.Echo  " "
WScript.Echo "*** Please delete any DLLs you are (re)making from the target directory:"
WScript.Echo  "    " & DEST_DIR
WScript.Echo  " "
Pause("Press any key to continue.")

' Make absolute addresses
DEST_DIR = objFSO.GetAbsolutePathName(DEST_DIR)
DEST_DIR = DEST_DIR & "\"

CURPATH = objFSO.GetAbsolutePathName(".")
CURPATH = CURPATH & "\"

' Check output directory exists and, if not, create it
CreateFolder(DEST_DIR)

If (Not objFSO.FileExists(BASE_DLL)) Then
  ' Check Base DLL exists
  WScript.Echo "Can't find the Base DLL - pwsafe_base.dll"
  WScript.Quit(99)
End If

If (Not objFSO.FileExists(RESTEXT)) Then
  ' Check required program exists
  WScript.Echo "Can't find Tool - ResText.exe"
  WScript.Quit(99)
End If

If (Not objFSO.FileExists(RESPWSL)) Then
  ' Check required program exists
  WScript.Echo "Can't find Tool - ResPWSL.exe"
  WScript.Quit(99)
End If

' Read in the list of all available translations
Dim TransList
TransList = BuildTranslationList()

' Create DLLs based on command line arguments

If DO_ALL = True Then
  ' Do all countries in Translations.txt
  Wscript.Echo "Creating translation DLLs for all countries in Translations.txt", vbCRLF
  Dim t
  For Each t in TransList
    Wscript.Echo "Creating translation DLL for country", UCase(t.LL)
    DoI18N LCase(t.FileName), t.LCID, t.LL_CC, UCase(t.LL)
  Next
Else
  ' Do one country
  Wscript.Echo "Creating translation DLL for country", DO_COUNTRY
  Dim OneTranslation
  Set OneTranslation = FindCountry(TransList, DO_COUNTRY)
  If Not OneTranslation Is Nothing Then
    DoI18N OneTranslation.FileName, OneTranslation.LCID, OneTranslation.LL_CC, OneTranslation.LL
  Else
    WScript.Echo "Error:", DO_COUNTRY, "is not a valid language"
    WScript.Quit(99)
  End If
End If

Wscript.Echo "Finished"
Wscript.Quit(0)

' End of main
'----------------------------------------------------
' Start of subroutines and functions

Sub DoI18N(POFileName, LCID, LL_CC, LL)
  ' Create a language DLL
  ' Parameters:
  ' 1. Name of file in sub-directory "pos" e.g. "pwsafe_zh.po"
  ' 2. LCID e.g. 0x0804 for Chinese (Simplified)
  ' 3. Generated DLL in form LL_CC e.g. "ZH_CN" for "pwsafeZH_CN.dll"
  '    NOTE: This is determined by the LCID and is not a free choice! See Windows XP version of
  '    http://www.microsoft.com/resources/msdn/goglobal/default.mspx
  '    as this generates the 2-character LL and CC values (later OSes can generate other values).
  ' 4. Final DLL name in form LL e.g. "ZH" for "pwsafeZH.dll"

  If (Not objFSO.FileExists("pos\" & POFileName)) Then
    ' Check required PO file exists
    WScript.Echo "   Can't find requested PO file - pos\" & POFileName
    WScript.StdOut.WriteLine "   Skipped"
    Exit Sub
  End If

  Dim WshShell, oExec
  Set WshShell = CreateObject("WScript.Shell")

  ' Create new intermediate DLL using PO file to replace strings
  Set oExec = WshShell.Exec(RESTEXT & " apply " & BASE_DLL & " foo.dll " & "pos\" & POFileName)

  Do While oExec.Status = 0
    WScript.StdOut.Write ".."
    WScript.Sleep 100
  Loop

  ' Create new DLL with correct name and update version information
  Set oExec = WshShell.Exec(RESPWSL & " apply foo.dll " & LCID)

  Do While oExec.Status = 0
    WScript.StdOut.Write ".."
    WScript.Sleep 100
  Loop

  If (objFSO.FileExists("foo.dll")) Then
    'Delete intermediate DLL if still there
    On Error Resume Next
    objFSO.DeleteFile "foo.dll"
  End If

  If (objFSO.FileExists(DEST_DIR & "pwsafe" & LL & ".dll")) Then
    ' Delete any old version of this language resource-only DLL
    On Error Resume Next
    objFSO.DeleteFile DEST_DIR & "pwsafe" & LL & ".dll"
  End If

  ' Move and rename the new DLL
  objFSO.MoveFile "pwsafe" & LL_CC & ".dll", DEST_DIR & "pwsafe" & LL & ".dll"

  Wscript.StdOut.WriteLine "Done"

  Set oExec = Nothing
  Set WshShell = Nothing

  End Sub

' Recursive folder create, will create directories and Sub
Sub CreateFolder(strPath)
  On Error Resume Next
  If strPath <> "" Then 'Fixes endless recursion in some instances when at lowest directory
    If Not objFSO.FolderExists(objFSO.GetParentFolderName(strPath)) then 
      Call CreateFolder(objFSO.GetParentFolderName(strPath))
    End If
    objFSO.CreateFolder(strPath)
  End If 
End Sub

Sub Pause(strPause)
  Dim z
  WScript.Echo (strPause)
  z = WScript.StdIn.Read(1)
End Sub

Sub Usage
  MsgBox "This script must be executed by cscript.exe in a Command window" & vbCRLF & _
    vbCRLF & _
    "cscript Create_DLLs.vbs [LL | /h | /help | /?] [x86 | x64]" & vbCRLF & _
    "    LL - a two letter language code for a specific language DLL" & vbCRLF & _
    "         e.g cscript Create_DLLs.vbs DE ==> for German/Germany" & vbCRLF & _
    "    /h | /help | /? - show help" & vbCRLF & _
    "    x86 -  produce 32-bit DLLs (default)" & vbCRLF & _ 
    "    x64 -  produce 64-bit DLLs" & vbCRLF & _
    vbCRLF & _
    "Examples" & vbCRLF & _
    "    cscript Create_DLLs.vbs x86 ==> create 32-bit DLLs for all languages" & vbCRLF & _
    "    cscript Create_DLLs.vbs x64 ==> create 64-bit DLLs for all languages" & vbCRLF & _
    "    cscript Create_DLLs.vbs ZH x64 ==> create 64-bit DLL for Chinese" & vbCRLF & _
    "", _
    vbInformation, _
    "Help: Create_DLLs.vbs"

End Sub

' Represents a record from the Translations.txt file
Class Translation
  Public FileName
  Public LCID
  Public LL_CC
  Public LL
End Class

' Reads Translations.txt and builds a list of PO files
' to be processed as language translations
Function BuildTranslationList()
  Dim TranList(), TranListSize
  ReDim TranList(1000)
  TranListSize = 0

  ' Set up regex for parsing out file and locale info from a line
  Dim re
  Set re = New RegExp
  re.Global = True
  re.IgnoreCase = True
  ' A translation record should look something like:
  ' #POFile       lcid   LL_CC LL  
  ' pwsafe_cz.po  0x0405 CS_CZ CS
  re.Pattern = "(^#)|(\w+\.\w+)|(\w+)"

  ' Read through the Translations.txt file
  Dim POFile
  Set POFile = objFSO.OpenTextFile("Translations.txt", ForReading, False, TristateFalse)
  Dim line, lineCounter
  Dim tokens
  lineCounter = 1
  Do While POFile.AtEndOfStream <> True
      line = POFile.ReadLine
      if line <> "" and mid(line, 1, 1) <> "#" Then
        Set tokens = re.Execute(line)
        ' A valid record must have at least 4 tokens and cannot start with a #
        If tokens.Count >= 4 Then
          Dim tran
          Set tran = New Translation
          tran.FileName = tokens(0)
          tran.LCID = tokens(1)
          tran.LL_CC = tokens(2)
          tran.LL = tokens(3)
          ' The first array element is 0
          Set TranList(TranListSize) = tran
          TranListSize = TranListSize + 1
        Else
          Wscript.Echo "Invalid translation mapping file record at line", lineCounter, "<", line, ">"
        End If
      End If
      lineCounter = lineCounter + 1
  Loop  
  POFile.Close
  
  ' Clean up
  Set re = Nothing
  Set POFile = Nothing
  Set tokens = Nothing
  
  ' Re-dimension the array to the exact number of elements used (sets the UBound value)
  ' Elements are indexed as 0 to UBound
  ReDim Preserve TranList(TranListSize - 1)

  ' Note that the first valid array element is TranList(0)
  BuildTranslationList = TranList
  
End Function

' Search a translations array for a matching country.
' This is a brute force search because the list is not very long.
Function FindCountry(trans, cc)
  Dim country
  Set country = Nothing

  Dim t
  For Each t in trans
    If UCase(t.LL) = UCase(cc) Then
      Set country = t
      Exit For
    End If
  Next
  
  Set FindCountry = country
  
End Function
