
###########################################################################
# Copyright (c) 1998, Jeffrey Glen Rennie
# All rights reserved.
###########################################################################
###########################################################################
# setupgui
# procedures for displaying gui during setup procedure:
###########################################################################
source debug.tcl
source message.tcl
source regwrap.tcl
source setupns.tcl
source setupie.tcl

if [catch { 
    set fLog [open "setup.log" a+]
    dbg::setChannel $fLog
    dbg::enableAll
} ] {
    dbg::disableAll
}

namespace eval setupgui {
    set randRange 100
    set randMin 2500
    set copyList [list \
	    buffer.tcl \
	    chat.tcl \
	    confgdlg.tcl \
	    debug.tcl \
	    defaults.tcl \
	    filter.tcl \
	    header.tcl \
	    mapchar.tcl \
	    message.tcl \
	    regwrap.tcl \
	    repo.tcl \
	    run.tcl \
	    rundebug.tcl \
	    server.tcl \
	    struct.tcl \
	    setup.tcl \
	    setupgui.tcl \
	    setupie.tcl \
	    setupns.tcl \
	    splash.tcl \
	    subscrib.tcl \
	    theFiltr.tcl \
	    urlbase.tcl \
	    maninst.htm \
	    help.htm \
	    config.htm \
	    gpl.htm \
	    ]

    set generatedList [ list \
	    confdata.tcl \
	    database.tcl \
	    ]

    set deleteList [concat $copyList $generatedList]

    set runTemplate {
	cd {%dir%}
	source run.tcl
    }

    set uninstallTemplate {
	wm withdraw .
	cd {%dir%}
	source setupgui.tcl
	setupgui::DoUninstallDialog
    }
    
    set configureTemplate {
	wm withdraw .
	if [catch { 
	    source [file join {%dir%} confdata.tcl]
	    array set defs [array get configData] 
	} ] {
	    array set defs [source [file join {%dir%} defaults.tcl]] 
	}
	if [catch { set s [socket localhost $defs(port)] } ] {
	    #we couldn't connect, so the server isn't running yet, launch it
	    cd {%dir%}
	    source run.tcl
	    config::DoConfigDialog
	} else {
	    #we connected, so just request the config dialog website
	    puts $s "GET http://configurewebsmacker HTTP/1.0\n\n"
	    close $s
	    exit
	}
    }
}

proc setupgui::IsInProxyPortRange { x } {
    variable randRange
    variable randMin
    set randMax [expr { $randRange + $randMin - 1 }]
    dbg::puts setup "expr { $x >= $randMin && $x <= $randMax }? [expr { $x >= $randMin && $x <= $randMax }]"
    expr { $x >= $randMin && $x <= $randMax }
}

proc setupgui::CatSource { } {
    set fCat [open "allsrc.txt" w]
    variable copyList
    foreach file $copyList {
	puts $fCat --------------------------------------------------
	puts $fCat "Begin File: $file"
	puts $fCat --------------------------------------------------
	set f [open $file r]
	set contents [read $f]
	close $f
	puts -nonewline $fCat $contents
    }
    close $fCat
}

proc setupgui::AddCopyrightNotice { } {
    variable copyList
    
    set copyrightNotice {###########################################################################
# Copyright (c) 1998, Jeffrey Glen Rennie
# All rights reserved.
###########################################################################
}
    set length [llength $copyList]
    set fileList [lrange $copyList 0 $length]
    foreach file $fileList {
	if [string match *.tcl $file] {
	    set f [open $file r+]
	    set contents [read $f]
	    # check to see if it already contains the copyright notice
	    if ![string match "*[set copyrightNotice]*" $contents] {
		seek $f 0
		puts -nonewline $f $copyrightNotice
		puts -nonewline $f $contents
		puts -nonewline $f $copyrightNotice
	    }
	    close $f
	}
    }
}	

proc setupgui::DoDirectoryDialog { } {
    global setupgui_directory
    variable root
    variable lblDirectory
    variable entDirectory
    variable frButtons
    variable btnOk
    variable btnCancel

    DoCloseBrowserMessageBox

    set root .dirDialog
    toplevel $root -width 400 -height 200
    wm resizable $root 0 0
    wm title $root "Setup Web Smacker"
    wm protocol $root WM_DELETE_WINDOW \
	    [list setupgui::OnCancel]

    set lblDirectory $root.lblDirectory
    set entDirectory $root.entDirectory
    set frButtons $root.frButtons
    set btnOk $frButtons.btnOk
    set btnCancel $frButtons.btnCancel

    label $lblDirectory -text "Install Web Smacker in which directory?"
    pack $lblDirectory -padx 7 -pady 4 -anchor nw
    entry $entDirectory -width 60 -textvariable setupgui_directory
    pack $entDirectory -padx 7
    frame $frButtons
    pack $frButtons
    button $btnOk -text "OK" -width 10 -command setupgui::OnOk
    button $btnCancel -text "Cancel" -width 10 -command setupgui::OnCancel
    pack $btnOk $btnCancel -fill x -side left -padx 7 -pady 7 -anchor center
    set setupgui_directory [GetDefaultPath]
}

proc setupgui::OnCancel { } {
    messageBox::DoMessageBox "Setup Web Smacker" \
	    "Really cancel installation of Web Smacker?" \
	    setupgui::OnCancelConfirm yesno
}

proc setupgui::OnCancelConfirm { args } {
    if { [llength $args] && [lindex $args 0] == "yes" } {
	SafeExit
    }
}

proc setupgui::CreateDirectory { dir } {
    if [file isfile $dir] {
	error "File already exists with the name $dir."
    } else {
	file mkdir $dir
    }
}	

proc setupgui::DoNothing { args } {
}

proc setupgui::OnOk { } {
    global setupgui_directory
    variable root
    variable lblDirectory
    variable entDirectory
    variable frButtons
    variable btnOk
    variable btnCancel
 
    if [catch {CreateDirectory $setupgui_directory} err] {
	ReportError "Could not create directory.\n$err"
    } else {
	# the directory was successfully created, so do copy
	# destroy $lblDirectory $entDirectory $frButtons
	if [catch { CopyFiles } err] {
	    ReportError "Could not copy files:\n$err"
	} elseif [catch { AddToStartup; AddToStartMenu } err] {
	    ReportError "Could not add new programs to Start Menu:\n$err"
	} elseif [catch { set browsers [SetupBrowsers] } err] {
	    ReportError "Could not setup browser:\n$err"
	} elseif { [llength $browsers] == 0 } {
	    tk_messageBox -title "Setup Web Smacker" -type ok \
		    -message "Web Smacker was successfully installed, but \
		    neither Netscape nor Internet Explorer were found on \
		    this computer.  Click Ok for instructions on how to \
		    manually configure your browser to use Web Smacker."
	    exec start maninst.htm &
	    setupgui::Finish
	} elseif [catch { ClearDefaultProxy } err] {
	    ReportError "Could not clear default proxy: $err."
	} else {
	    # it succeeded!
	    destroy $root
	    set browsers [join $browsers " and "]
	    messageBox::DoMessageBox "Setup Web Smacker" \
		    "Setup complete.  Installed on $browsers.  \
		    To configure Web Smacker's filtering options \
		    open the \"Configure Web Smacker\" Bookmark \
		    in your browser." \
		    setupgui::Finish
	}	    
    }
}    

proc SourceRunTcl { } {
    # uplevel #0 source run.tcl
    exec start run.tcl &
    setupgui::SafeExit
}

proc setupgui::Finish { args } {
    global setupgui_directory
    cd $setupgui_directory
    SourceRunTcl
}    

proc setupgui::ReportError { err } {
    messageBox::DoMessageBox "Setup Web Smacker" \
	    $err setupgui::DoNothing
}

proc setupgui::ClearDefaultProxy { } {
    global setupgui_directory

    if [catch {
	set defaultsFile [file join $setupgui_directory "defaults.tcl"]
	set f [open $defaultsFile r]
	set defContents [read $f]
	close $f
	regsub -all %oldProxyHost% $defContents {{}} \
		defContents
	regsub -all %oldProxyPort% $defContents {{}} \
		defContents
	set f [open $defaultsFile w]
	puts $f $defContents
	close $f
    } err ] {
	catch { close $f }
	error $err
    }
}    

proc setupgui::CopyFiles { } {
    variable copyList
    variable randRange
    variable randMin
    global setupgui_directory
    
    foreach file $copyList {
	file copy -force $file [file join $setupgui_directory $file]
    }

    # now randomly choose a port
    if [catch {
	set defaultsFile [file join $setupgui_directory "defaults.tcl"]
	file attributes $defaultsFile -readonly 0
	set f [open $defaultsFile r]
	set defContents [read $f]
	close $f
	regsub -all %port% $defContents \
		[expr { int( rand() * $randRange + $randMin) } ] \
		defContents
	set f [open $defaultsFile w]
	puts $f $defContents
	close $f
    } err ] {
	catch { close $f }
	error $err
    }
}

# the windows environment is case insensitive
# but the tcl array that the environment is packed into is case
# SENSITIVE 
# to reconcile this, make all the vars in the env array uppercase
proc setupgui::NormalizeEnvironment { } {
    global env
    foreach var [array names env] {
	set newVar [string toupper $var]
	set env($newVar) $env($var)
    }
}    

proc setupgui::GetUserProfilePath { } {
    global registryDllLoaded
    global env
    global tcl_platform

    #only calculate it once
    variable _userProfilePath 
    if ![info exists _userProfilePath] {
	if { ![info exists registryDllLoaded] } {
	    load registry.dll
	    set registryDllLoaded 1
	}
	if { $tcl_platform(os) == "Windows NT" } {
	    # first try to construct the path from environment variables
	    if { [ catch { 
		set userRootPath [file join $env(WINDIR) Profiles\
			$env(USERNAME)]
	    } ] && [file exists $userRootPath] } {		
		# that didn't work so ask the user for the user name
		set userRootPath [DoUserDialog]
	    }
	} elseif [catch {
	    set k [reg_openkey key_current_user \
		    "Software/Microsoft/Windows/CurrentVersion/ProfileReconciliation" \
		    -access read]
	    set userRootPath [lindex [reg_getvalue $k ProfileDirectory] 1]
	    reg_closekey $k
	} err] {
	    # it's windows 95, or there aren't multiple profiles or something,
	    # so use win root path
	    catch { reg_closekey $k }
	    set userRootPath $env(WINDIR)
	}
	set _userProfilePath $userRootPath
    }
    return $_userProfilePath
}

proc setupgui::GetUserStartupPath { } {
    file join [GetUserProfilePath] "Start Menu" \
		"Programs" "StartUp"
}

proc setupgui::UninstallStartMenu { } {
    if [catch {
	set dirPath [file join [GetUserProfilePath] \
		"Start Menu" "Programs" "Web Smacker"]
	file delete -force $dirPath
    } err] {
	dbg::puts setup $err
    }
}   

proc setupgui::AddToStartMenu { } {
    variable runTemplate
    variable configureTemplate
    variable uninstallTemplate
    global setupgui_directory

    if [catch {
	set dirPath [file join [GetUserProfilePath] \
		"Start Menu" "Programs" "Web Smacker"]
	file mkdir $dirPath
	# install start command
	set f [open [file join $dirPath "Start Web Smacker.tcl"] w]
	regsub -all %dir% $runTemplate $setupgui_directory run_tcl
	puts $f $run_tcl
	close $f
	# install configure command
	set f [open [file join $dirPath "Configure Web Smacker.tcl"] w]
	regsub -all %dir% $configureTemplate $setupgui_directory config_tcl
	puts $f $config_tcl
	close $f
	#install the uninstall command
	set f [open [file join $dirPath "Uninstall Web Smacker.tcl"] w]
	regsub -all %dir% $uninstallTemplate $setupgui_directory config_tcl
	puts $f $config_tcl
	close $f
    } err] {
	catch { close $f }
	error $err
    }
}   

proc setupgui::AddToStartup { } {
    variable runTemplate
    global setupgui_directory
    
    if [ catch {
	regsub %dir% $runTemplate $setupgui_directory run_tcl
	set filename [file join [GetUserStartupPath] "RunSmacker.tcl"]
	set f [open $filename w]
	puts $f $run_tcl
	close $f
    } err] {
	catch { close $f }
	error $err
    }
}

proc setupgui::UninstallStartup { } {
    if [catch {
	file delete -force [file join [GetUserStartupPath] "RunSmacker.tcl"]
    } err] {
	dbg::puts setup $err
    }
}

proc setupgui::SetupBrowsers { } {
    set result [list ]
    if [setupns::SetupNetscape]  {
	lappend result "Netscape"
    }
    if [setupie::SetupInternetExplorer] {
	lappend result "Internet Explorer"
    }
    set result
}

proc setupgui::GetDefaultPath { } {
    global env
    if { [catch {set root $env(HOME) }] || $root == "" } {
	set root "C:/"
    }
    file nativename [file join $root "Program Files" "WebSmacker"]
}

proc setupgui::DoCloseBrowserMessageBox { } {
    messageBox::DoMessageBox "Web Smacker" \
	    "Please close all Netscape and Internet Explorer windows. \
	    If Netscape or Internet Explorer is running, the install \
	    procedure will fail." \
	    setupgui::DoNothing
}


proc setupgui::DoUninstallDialog { } {
    variable root

    messageBox::DoMessageBox "Uninstall Web Smacker" \
	    "Please close any Internet Explorer or Netscape windows.  \
	    Also, please select \"Programs | Web Smacker | \
	    Configure Web Smacker\" from the Start Menu, and shut down \
	    Web Smacker.  Web Smacker will not uninstall correctly if \
	    unless you have done this." setupgui::DoNothing

    set root .uninstallDialog
    toplevel $root
    wm title $root "Uninstall Web Smacker"
    set lblQuestion $root.lblQuestion
    set btnRemoveUser $root.btnRemoveUser
    set btnRemoveAll $root.btnRemoveAll
    set btnCancel $root.btnCancel

    label $lblQuestion -text "What would you like to do?"
    button $btnRemoveUser -text "Uninstall Web Smacker for the Current User" \
	    -command setupgui::OnRemoveUser
    button $btnRemoveAll -text "Uninstall Web Smacker and Remove All Files" \
	    -command setupgui::OnRemoveAll
    button $btnCancel -text "Cancel" \
	    -command setupgui::OnCancelUninstall
    
    pack $lblQuestion $btnRemoveUser $btnRemoveAll $btnCancel \
	    -expand 1 -pady 4 -padx 7 -fill x
}

proc setupgui::DoDoneMessageBox { } {
    messageBox::DoMessageBox "Uninstall Web Smacker" \
	    "Done" setupgui::SafeExit
}

proc setupgui::RemoveUser { } {
    setupns::Uninstall
    setupie::Uninstall
    UninstallStartMenu
    UninstallStartup
}

proc setupgui::OnRemoveUser { } {
    RemoveUser
    DoDoneMessageBox
}

proc setupgui::OnRemoveAll { } {
    variable deleteList

    RemoveUser
    foreach file $deleteList {
	catch { file delete $file }
    }
    DoDoneMessageBox
}

proc setupgui::OnCancelUninstall { } {
    SafeExit
}

proc setupgui::GetDefaults { } {
    global setupgui_directory
    set f [open [file join $setupgui_directory "defaults.tcl"] r]
    set defaults [read $f]
    close $f    
    set defaults
}

proc setupgui::UpdateDefaultsWithOldProxy { oldProxy } {
    global setupgui_directory
    set defaults [GetDefaults]
    array set defs [eval $defaults]

    if { [string trim [lindex $oldProxy 0]] != "" && \
	    [string trim [lindex $oldProxy 1]] != "" } {
	#install succeeded, check for old proxy
	set oldProxyHost \
		[string tolower [string trim [lindex $oldProxy 0]]]
	set oldProxyPort [string trim [lindex $oldProxy 1]]
	if { $oldProxyHost != "localhost" || \
		![IsInProxyPortRange $oldProxyPort] } {
	    dbg::puts setup "old proxy host is different"
	    if { [regsub %oldProxyHost% $defaults \
		    [lindex $oldProxy 0] defaults] && \
		    [regsub %oldProxyPort% $defaults \
		    [lindex $oldProxy 1] defaults] } {
		set w " \r\n\t"
		regsub "(\[$w]*useProxy\[$w]*)0" $defaults \\11 defaults
		set f [open [file join $setupgui_directory "defaults.tcl"] w]
		puts -nonewline $f "set defaults {"
		puts -nonewline $f $defaults
		puts -nonewline $f "}"
		close $f
	    }
	}
    }
}

proc setupgui::SafeExit { } {
    global fLog
    catch { close $fLog }
    exit
}

# returns the path to the users profile dialog
# called only on Windows NT
proc setupgui::DoUserDialog { } {
    global env
    variable userResult
    variable listboxUsers
    variable pathProfiles
    variable winUserDialog

    catch { wm withdraw .dirDialog }
    set pathProfiles [file join [set env(WINDIR)] Profiles]
    set listUsersPath [glob [file join $pathProfiles *]]
    foreach userPath $listUsersPath { 
	lappend listUsers [file tail $userPath]
    }
    set winUserDialog ".userdlg"
    toplevel $winUserDialog
    wm title $winUserDialog "Select a User"
    wm protocol $winUserDialog  WM_DELETE_WINDOW \
	    setupgui::OnCancel
    set labelQuestion $winUserDialog.labelQuestion
    label $labelQuestion -text "For which user would you like to\
	    install Web Smacker?"
    set frameListBox $winUserDialog.frameListBox
    set listboxUsers [Scrolled_Listbox $frameListBox -width 30 \
	    -height 5]
    eval [list $listboxUsers insert end ] $listUsers
    set frameButtons $winUserDialog.frameButtons
    frame $frameButtons
    set buttonOk $frameButtons.buttonOk
    button $buttonOk -width 10 -text Ok \
	    -command setupgui::OnUserDialogOk
    set buttonCancel $frameButtons.buttonCancel
    button $buttonCancel -width 10 -text Cancel \
	    -command setupgui::OnCancel
    pack $labelQuestion $frameListBox $frameButtons -padx 7 -pady 3
    pack $buttonOk $buttonCancel -padx 5 -pady 3 -side left

    $listboxUsers selection set 0
    focus $winUserDialog
    grab $winUserDialog
    tkwait window $winUserDialog
    return $userResult
}    

proc setupgui::OnUserDialogOk { } {
    variable userResult
    variable listboxUsers
    variable pathProfiles
    variable winUserDialog

    set indecesSelection [$listboxUsers curselection]
    set user [$listboxUsers get [lindex $indecesSelection 0]]
    set userResult [file join $pathProfiles $user]
    destroy $winUserDialog
}
    

#these two functions are copied directly from Brent B. Welch's book.
proc Scrolled_Listbox { f args } {
    frame $f
    listbox $f.list \
	    -xscrollcommand [list Scroll_Set $f.xscroll \
	    [list grid $f.xscroll -row 1 -column 0 -sticky we]] \
	    -yscrollcommand [list Scroll_Set $f.yscroll \
	    [list grid $f.yscroll -row 0 -column 1 -sticky ns]]
    eval {$f.list configure} $args
    scrollbar $f.xscroll -orient horizontal \
	    -command [list $f.list xview]
    scrollbar $f.yscroll -orient vertical \
	    -command [list $f.list yview]
    grid $f.list -sticky news
    grid rowconfigure $f 0 -weight 1
    grid columnconfigure $f 0 -weight 1
    return $f.list
}

proc Scroll_Set {scrollbar geoCmd offset size} {
    if {$offset != 0.0 || $size != 1.0} {
	eval $geoCmd			;# Make sure it is visible
    }
    $scrollbar set $offset $size
}

# on startup
# always normalize the envrionment when loaded
setupgui::NormalizeEnvironment

###########################################################################
# Copyright (c) 1998, Jeffrey Glen Rennie
# All rights reserved.
###########################################################################


