# Copyright: 2016-2025 Paul Obermeier (obermeier@tcl3d.org)
# Distributed under BSD license.
#
# BuildType Windows: InnoSetup
# BuildType Linux  : tar or deb
# BuildType Darwin : tar or dmg
#
# Possible user configuration options (--copt):
#   Additional tag, ex. "Tag=-BI".
#   Version string, ex. "Version=8.7.0.4".
#   Setup type,     ex. "Linux=deb", Darwin="dmg".
#   On Linux and Darwin, type "tar" is the default.

proc Init_SetupTcl { libName libVersion } {
    SetScriptAuthor    $libName "Paul Obermeier" "obermeier@tcl3d.org"
    SetLibHomepage     $libName "https://www.tcl3d.org/bawt/"
    SetLibDependencies $libName "All"
    SetPlatforms       $libName "Windows" "Linux" "Darwin"
}

proc _GetPackagesAsString { { fmtStr "%-18s %s\n" } } {
    set libStr ""
    foreach libName [lsort -dictionary [GetLibs]] {
        if { [lsearch -exact -nocase [GetLibDependencies $libName] "Tcl"] >= 0 || \
             [lsearch -exact -nocase [GetLibDependencies $libName] "TclStubs"] >= 0 || \
             [lsearch -exact -nocase [GetLibDependencies $libName] "Tclkit"] >= 0 || \
             [lsearch -exact -nocase [GetLibDependencies $libName] "Tk"] >= 0 || \
             [lsearch -exact -nocase [GetLibDependencies $libName] "TkStubs"] >= 0 } {
            if { [IsSupportedPlatform $libName] } {
                if { $libName ne "SWIG" && \
                     $libName ne "Redistributables" && \
                     $libName ne "Tk" && \
                     $libName ne "TkStubs" && \
                     $libName ne "BawtLogViewer" } {
                    set libVersion [GetLibVersion $libName]
                    if { $libVersion eq "" } {
                        set libVersion [GetLibVersion "Tcl"]
                    }
                    append libStr [format $fmtStr $libName $libVersion]
                }
            }
        }
    }
    return $libStr
}

proc Build_SetupTcl { libName libVersion buildDir instDir devDir distDir } {
    set tclVersion $libVersion
    if { $libVersion eq "" } {
        set tclVersion [GetTclVersion]
    }
    set tkVersion [GetTkVersion]
    if { $tclVersion ne $tkVersion } {
        set tcltkVersion "$tclVersion-$tkVersion"
    } else {
        set tcltkVersion "$tclVersion"
    }

    if { [UseStage "Extract" $libName] } {
        ExtractLibrary $libName $buildDir
    }

    set libListFile [file join $instDir $libName-$tcltkVersion.txt]

    if { [UseStage "Compile" $libName] } {
        # Store list of included libraries in separate file.
        WriteToFile $libListFile [_GetPackagesAsString]
    }

    if { [UseStage "Distribute" $libName] } {
        SingleFileCopy $libListFile "$distDir"
    }

    set setupStr [GetUserConfigValue $libName "Tag"]
    set userTag  [GetUserConfigValue $libName "Version"]

    if { [IsWindows] } {
        set fileTemplate "${libName}${setupStr}-$tcltkVersion-[GetArchitecture]_Bawt-[GetVersion]"
        set comprMode "lzma"
        set innoSetupFile [file join $instDir $fileTemplate]

        if { [UseStage "Compile" $libName] } {
            MultiFileCopy $buildDir $instDir "*" true
            MultiFileCopy [file join $distDir "opt" "Tcl"] "$instDir/Tcl" "*" true
            set vcRedistName "None"
            if { [UseVisualStudio] } {
                set vcVersion [GetVisualStudioVersion]
                set vcRedistName [format "vcredist%s_%s.exe" $vcVersion [GetArchitecture]]
                set vcRedistFile [file join [GetOutputBuildDir] "Redistributables" $vcRedistName]
                if { [file exists $vcRedistFile] } {
                    SingleFileCopy $vcRedistFile "$instDir"
                }
            }

            set sendToConst "usersendto"
            if { [GetLibVersion "InnoSetup"] eq "5.5.9" } {
                set sendToConst "sendto"
            }

            set issInFile  [file join $instDir "Setup.in"]
            set issOutFile [file join $instDir "Setup.iss"]

            # Replace keywords in the InnoSetup template file.
            file copy $issInFile $issOutFile
            set versionStr $tcltkVersion
            if { $userTag ne "" } {
                set versionStr $userTag
            }
            if { [regexp {[:alpha:]} $versionStr] } {
                # This is an alpha or beta release containing letters.
                # InnoSetup does not allow letters in Setup key "VersionInfoVersion".
                set versionStr "0.0.0.0"
            }
            set replaceList [list]
            lappend replaceList "@CURRENT_YEAR@"     [clock format [clock seconds] -format "%Y"]
            lappend replaceList "@TCL_VERSION@"      $versionStr
            lappend replaceList "@TCL_BITS@"         [GetBits]
            lappend replaceList "@INNO_COMPRESSION@" $comprMode
            lappend replaceList "@VC_REDIST_EXE@"    $vcRedistName
            lappend replaceList "@SENDTO@"           $sendToConst
            if { [info exists vcRedistFile] && [file exists $vcRedistFile] } {
                lappend replaceList "@VC_REDIST_ENABLE@" ""
            } else {
                lappend replaceList "@VC_REDIST_ENABLE@" "; "
            }
            ReplaceKeywords $issOutFile $replaceList

            set appInFile  [file join $instDir "Readme-App.in"]
            set appOutFile [file join $instDir "Readme-App.txt"]

            # Replace keywords in the InnoSetup ReadmeApp file.
            file copy $appInFile $appOutFile
            set pkgsString "Tcl-$tclVersion\nTk-$tkVersion\n"
            append pkgsString [_GetPackagesAsString "%s-%s\n"]
            set numPkgs [expr [llength [split $pkgsString "\n"]] -1]
            set replaceList [list]
            lappend replaceList "@LIBRARY_LIST@" $pkgsString
            lappend replaceList "@NUM_LIBS@"     $numPkgs
            ReplaceKeywords $appOutFile $replaceList

            # Call the InnoSetup program.
            set innoCmd [GetInnoProg]
            if { $innoCmd ne "" } {
                set curDir [pwd]
                cd $instDir
                set logFile [file join $instDir "InnoCompileLog.txt"]
                Log "InnoSetup" 2
                Log "Input file : $issOutFile" 4 false
                Log "Log file   : $logFile"    4 false
                Log "Output file: $innoSetupFile[GetExeSuffix]" 4 false
                exec $innoCmd /o$instDir /f[file tail $innoSetupFile] $issOutFile >& $logFile
                cd $curDir
            }
        }

        if { [UseStage "Distribute" $libName] } {
            SignExecutables "$instDir" "${libName}*[GetExeSuffix]"

            SingleFileCopy $innoSetupFile[GetExeSuffix]  "$distDir"
        }
    } elseif { [IsUnix] } {
        set fileTemplate "${libName}${setupStr}-$tcltkVersion-[GetDpkgArchitecture]_Bawt-[GetVersion]"
        set setupTypeLinux  [string tolower [GetUserConfigValue $libName "Linux"]]
        set setupTypeDarwin [string tolower [GetUserConfigValue $libName "Darwin"]]
        if { $setupTypeLinux eq "" } {
            set setupTypeLinux "tar"
        }
        if { $setupTypeDarwin eq "" } {
            set setupTypeDarwin "tar"
        }

        if { ([IsLinux]  && $setupTypeLinux eq "tar") || \
             ([IsDarwin] && $setupTypeDarwin eq "tar") } {
            set tarFile   [file join $instDir ${fileTemplate}.tar.gz]
            set setupFile [file join $distDir ${fileTemplate}.sh]

            if { [UseStage "Compile" $libName] } {
                MultiFileCopy [file join $distDir "opt" "Tcl"] "$instDir/Tcl" "*" true
                TarGzip $tarFile $instDir/Tcl
            }

            if { [UseStage "Distribute" $libName] } {
                set cmd "$buildDir/SetupAddPayload.sh $buildDir/SetupTemplate.sh $setupFile $tarFile"
                MSysRun $libName "SetupAddPayload" "" "$cmd"
            }
            return true
        }
        if { [IsLinux] } {
            if { $setupTypeLinux eq "deb" } {
                set instSetupDir [file join $instDir ${fileTemplate}]
                set debSetupFile [file join $instDir ${fileTemplate}.deb]
                if { [UseStage "Compile" $libName] } {
                    MultiFileCopy "$buildDir/DEBIAN" "$instSetupDir/DEBIAN" "*" true
                    SetFilePermissions "$instSetupDir/DEBIAN/postinst" "755"

                    set pkgsString " Tcl-$tclVersion\n Tk-$tkVersion\n"
                    append pkgsString [_GetPackagesAsString "  %s-%s\n"]
                    set numPkgs [expr [llength [split $pkgsString "\n"]] -1]
                    set replaceList [list]
                    lappend replaceList "@TCL_VERSION@"  $tcltkVersion
                    lappend replaceList "@LIBRARY_LIST@" $pkgsString
                    lappend replaceList "@NUM_LIBS@"     $numPkgs
                    lappend replaceList "@ARCHITECTURE@" [GetDpkgArchitecture]
                    ReplaceKeywords "$instSetupDir/DEBIAN/control" $replaceList

                    MultiFileCopy [file join $distDir "opt" "Tcl"] "$instSetupDir/opt/Tcl" "*" true

                    set debCmd [GetDpkgDebProg]
                    if { $debCmd ne "" } {
                        Log "Create Debian package" 2
                        Log "Input dir  : $instSetupDir" 4 false
                        Log "Output file: $debSetupFile" 4 false
                        set curDir [pwd]
                        cd "$instDir"
                        exec $debCmd --build {*}[GetDpkgDebOpts] $fileTemplate
                        cd "$curDir"
                    }
                }
                if { [UseStage "Distribute" $libName] } {
                    SingleFileCopy $debSetupFile  "$distDir"
                }
                return true
            } else {
                ErrorAppend "$libName: Invalid Linux setup type \"$setupTypeLinux\"." "FATAL"
                return false
            }
        }
        if { [IsDarwin] } {
            if { $setupTypeDarwin eq "dmg" } {
                set instSetupDir [file join $instDir ${fileTemplate}]
                set dmgSetupFile [file join $instDir ${fileTemplate}.dmg]
                if { [UseStage "Compile" $libName] } {
                    MultiFileCopy [file join $distDir "opt" "Tcl"] "$instSetupDir/Tcl" "*" true
                    SingleFileCopy "$buildDir/License.txt"      "$instSetupDir"
                    SingleFileCopy "$buildDir/ReadmeDarwin.txt" "$instSetupDir" -rename "Readme.txt"

                    set pkgsString "Tcl-$tclVersion\nTk-$tkVersion\n"
                    append pkgsString [_GetPackagesAsString "%s-%s\n"]
                    set numPkgs [expr [llength [split $pkgsString "\n"]] -1]
                    set replaceList [list]
                    lappend replaceList "@TCL_VERSION@"  $tcltkVersion
                    lappend replaceList "@LIBRARY_LIST@" $pkgsString
                    lappend replaceList "@NUM_LIBS@"     $numPkgs
                    ReplaceKeywords "$instSetupDir/Readme.txt" $replaceList

                    set dmgCmd [GetHdiUtilProg]
                    if { $dmgCmd ne "" } {
                        Log "Create MacOS DMG package" 2
                        Log "Input dir  : $instSetupDir" 4 false
                        Log "Output file: $dmgSetupFile" 4 false
                        set curDir [pwd]
                        cd "$instDir"
                        exec $dmgCmd create -ov -quiet -fs HFS+ -srcfolder $fileTemplate -volname "Bawt-Tcl Distribution" $dmgSetupFile
                        cd "$curDir"
                    }
                }
                if { [UseStage "Distribute" $libName] } {
                    SingleFileCopy $dmgSetupFile  "$distDir"
                }
                return true
            } else {
                ErrorAppend "$libName: Invalid Darwin setup type \"$setupTypeDarwin\"." "FATAL"
                return false
            }
        }
    }
    return true
}
