# -*- tcl -*-
# tcl-protected \
    eval 'WISH=tcltk/bin/wish8.2; \
          if test -f $WISH; then exec $WISH $0; \
          else \
          echo Cannot find $WISH; \
          exit 1; fi'
catch {destroy .install ;unset Install}
# steps : step_list ;
# step_list : step
#           | step_list step
#           ;
# step : IDENT spec_list
#      ;
# spec_list : spec
#           | spec_list spec
#           ;
# spec : message
#      | file
#      | yesnocheck
#      | name
#      | directory
#      | path
#      | action
#      ;
# - message : display a message -
# message : MESSAGE string
#         ;
# - file : show content of a file -
# file :  FILE file_name
#      ;
# - yesnocheck : display 2 radio buttons and choices related
#                choices are enabled only when button 2 is selected
#                var contains 0 if choice 1, 1 else
# yesnocheck : YESNOCHECK var
#              label
#              label
#              spec_list
#            ;
# - name : name entry -
# name : NAME label var
#      ;
# - directory : directory selection, result in var -
# directory : DIRECTORY label default_path var
#           ;
# default_path : string
#              | CURRENT
#              ;
# - path : path selection, result in var -
# path : PATH label file_name var
#        ;
#
# - action : action to call before next step.
#            can be Tcl code or a procedure
#            procedure has no arguments and may use
#            var defined in specs. In case of error
#            must call "error msg"
# - var : defines a user defined variable. SCRIPT is predefined
#         and is the current script
# var : IDENT 
#     ;
#
# label : string
#       ;

set Install(logo) LogoCompiler.gif

set Install(steps) {
    {Welcome 
	{message "Welcome to Esterel v5_92 installer"}
    }
    {Copyright 
	{message \
"Please read the following 
Copyright information:"}
	{file COPYRIGHT.txt}
    }
    {Directories 
	{message \
"Current Esterel installation directory. 
Please change it if this is not suitable 
for network access (path starting with /0
or any other number may be local to a machine"}
	{directory "Esterel distribution" current ESTEREL_DISTRIB_DIR}
	{action check_distrib}
    }
    {Commands
	{message \
"The following commands can be linked 
in a standard directory instead of adding 
$ESTEREL_DISTRIB_DIR/bin 
to your PATH variable. You can also change
the command names."}
	{yesnocheck
            LINK_BIN_CTRL 
	    "No links"
	    "Links" {\
	        {directory "Bin dir" "/usr/local/bin" BIN_DIR}
		{name "Esterel command" esterel ESTEREL_COMMAND}
		{name "Xesterel command" xesterel XESTEREL_COMMAND}
		{name "Xes command" xes XES_COMMAND}
		{name "Xeve command" xeve XEVE_COMMAND}
	    }
	}
	{action check_bin_links}
    }
    {Libraries 
	{message 
"You can create links for libraries in 
a standard directory instead of adding 
-L$ESTEREL_DISTRIB_DIR/lib 
option to your C compiler."}
	{yesnocheck
            LINK_LIB_CTRL
	    "No links"
	    "Links" {{directory "Bin dir" "/usr/local/lib" LIB_DIR}}
	}
	{action check_lib_links}
    }
    {Includes 
	{message \
"You can create links for includes in a 
standard directory instead of possibly adding 
-I$ESTEREL_DISTRIB_DIR/include 
option to your C compiler."}
	{yesnocheck
            LINK_INC_CTRL
	    "No links"
	    "Links"
	    {{directory "Include dir" "/usr/local/include" INCLUDE_DIR}}
	}
	{action check_inc_links}
    }
    {Manuals 
	{message \
"You can create links for manpages in a
standard directory instead of adding 
$ESTEREL_DISTRIB_DIR/man
to your MANPATH variable."}
	{yesnocheck 
            LINK_MAN_CTRL
	    "No links"
	    "Links" {
		{directory "Command man dir" "/usr/local/man/man1" MAN1_DIR}
		{directory "Library man dir" "/usr/local/man/man3" MAN3_DIR}
	    }
	}
	{action check_man_links}
    }
    {Installation 
	{message \
"The Esterel v5_92 is about to be installed. 
Do you want do continue ?"}
	{action install_script}
    }
    {End 
	{message \
"The esterel v5_92 is successfully installed. 
Documentation can be found in the 
$ESTEREL_DISTRIB_DIR/doc 
directory. Please, have also a look at the 
README.txt and RELEASE_NOTES.txt files."}
    }
}

# action scripts

proc check_distrib {} {
    if {! [file isdirectory $ESTEREL_DISTRIB_DIR] ||
	! [file exists [file join $ESTEREL_DISTRIB_DIR $SCRIPT]]} {
	error "Esterel is not in $ESTEREL_DISTRIB_DIR"
    }
}

proc check_bin_links {} {
    if { ! $LINK_BIN_CTRL } {
	return
    }
    set bin  [list \
		  $ESTEREL_COMMAND \
		  $XES_COMMAND \
		  $XEVE_COMMAND \
		  $XESTEREL_COMMAND]
    foreach file $bin {
	set dir [file dirname $file]
	if {! [file isdirectory $dir] } {
	    error "$dir: no such directory"
	}
	if {[file exist $file]} {
	    error "$file: file already exists"
	}
    }
}

proc check_dirs {args} {
    foreach file $args {
	set dir [file dirname $file]
	if {! [file isdirectory $dir] } {
	    error "$dir: no such directory"
	}
    }
}
proc check_man_links {} {
    if { ! $LINK_MAN_CTRL } {
	return
    }
    check_dirs $MAN1_DIR $MAN3_DIR
}
proc check_lib_links {} {
    if { ! $LINK_LIB_CTRL } {
	return
    }
    check_dirs $LIB_DIR
}
proc check_inc_links {} {
    if { ! $LINK_INC_CTRL } {
	return
    }
    check_dirs $INCLUDE_DIR
}

proc install_script {} {
#    append cmd "echo "
    append cmd "make install ESTEREL_DISTRIB_DIR=\"$ESTEREL_DISTRIB_DIR\""
    if { $LINK_BIN_CTRL } {
	append cmd " BIN_DIR=\"$BIN_DIR\""
	append cmd " ESTEREL_COMMAND=\"$ESTEREL_COMMAND\""
	append cmd " XESTEREL_COMMAND=\"$XESTEREL_COMMAND\""
	append cmd " XES_COMMAND=\"$XES_COMMAND\""
	append cmd " XEVE_COMMAND=\"$XEVE_COMMAND\""
    }
    if { $LINK_LIB_CTRL } {
	append cmd " LIB_DIR=\"$LIB_DIR\""
    }
    if { $LINK_INC_CTRL } {
	append cmd " INCLUDE_DIR=\"$INCLUDE_DIR\""
    }
    if { $LINK_MAN_CTRL } {
	append cmd " MAN1_DIR=\"$MAN1_DIR\""
	append cmd " MAN3_DIR=\"$MAN3_DIR\""
    }
    append cmd " > /dev/tty"
    if {[catch "exec $cmd" error]} {
	global errorCode
	puts stdout $error

	if { $errorCode == "error" } {
	    error "Installation failed. Please look at the README.txt file"
	}
    }
    if {[catch {open uninstall w} fd]} {
	error "Cannot open uninstall file"
    }
    regsub install $cmd uninstall uninstall
    puts $fd "\#!/bin/sh"
    puts $fd $uninstall
    close $fd
    file attributes uninstall -permissions 0755
}
#============================================================
global Install
set Install(vars:SCRIPT) setup

proc CenterWin {w} {
    wm withdraw $w
    update idletasks
    set x [expr {[winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
	    - [winfo vrootx [winfo parent $w]]}]
    set y [expr {[winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
	    - [winfo vrooty [winfo parent $w]]}]
    wm geom $w +$x+$y
    wm deiconify $w
    update
}

# Build install window
proc InstallInit {} {
    global Install

    set Install(step:last) [expr [llength $Install(steps)] - 1]
    
    toplevel .install -width 200 -height 200
    wm title .install "Esterel Setup"

    set Install(window:top) .install
    set Install(window:buttons) [frame .install.buttons]
    set Install(window:data) [frame .install.data]
    button $Install(window:buttons).finish \
	-text Finish -command InstallFinish
    button $Install(window:buttons).cancel \
	-text Cancel -command InstallQuit
    button $Install(window:buttons).next \
	-text Next -command InstallNextStep
    button $Install(window:buttons).previous \
	-text Previous -command InstallPreviousStep
    pack  $Install(window:buttons) -anchor e -side bottom
    pack $Install(window:data) -anchor nw -side right 
    if {[info exists Install(logo)]} {
	pack [label .install.log \
		  -bd 2 -relief sunken \
		  -image [image create photo -file $Install(logo)]] \
	    -side right -padx 5 -pady 5
    }
    CenterWin .install

    set width 200
    set height 200
    
    set nb_of_specs [llength $Install(steps)]
    for {set step 0} {$step<$nb_of_specs} {incr step} {
	set w $Install(window:data).step$step
	set Install(window:step:$step) [frame $w]
	place $w -x 0 -y 0 -anchor nw
	frame $w.f
	pack $w.f -expand 1
	InstallBuildStep $w.f $step [lindex $Install(steps) $step]
	if { [winfo reqwidth $w] > $width } {
	    set width  [winfo reqwidth $w]
	}
	if { [winfo reqheight $w] > $height } {
	    set height  [winfo reqheight $w]
	}
	place $Install(window:step:$step) -relwidth 1.0 -relheight 1.0
    }

    $Install(window:data) configure -width $width -height $height

    set Install(step:current) -1
    InstallNextStep
    wm resizable $Install(window:top) false false
    CenterWin .install

    wm protocol .install WM_DELETE_WINDOW {
	InstallQuit
    }
}

# build a step
proc InstallBuildStep {f step step_spec} {
    global Install
    set Install(step:current) $step
    foreach spec [lrange $step_spec 1 end] {
	switch [lindex $spec 0] {
	    message {
		InstallShowMessage $f [lindex $spec 1]
	    }

	    file {
		InstallViewFile $f  [lindex $spec 1]
	    }
	    
	    directory {
		InstallSetDirectory $f [lrange $spec 1 end]
	    }

	    path {
		InstallSetPath $f [lrange $spec 1 end]
	    }

	    yesnocheck {
		InstallYesNoCheck $f [lrange $spec 1 end]
	    }
	    
	    action {
		InstallAction $step  [lindex $spec 1]
	    }
	    name {
		InstallName $f  [lrange $spec 1 end]
	    }
	    default {
		error "unknown spec $spec"
	    }
	}
    }
    update
}

# set install buttons according to step
proc InstallButtons {step} {
    global Install
    set w $Install(window:buttons)
    foreach button [pack slaves $w] {
	pack forget $button
    }
    if { $step == $Install(step:last) } {
	pack $w.finish -side right
    } else {
	pack $w.cancel -side right
	pack $w.next -side right
	if {$step > 0} {
	    pack $w.previous -side right
	}
    }
}

proc InstallCallActions {kind} {
    global Install

    if {[info exists Install(action:$kind:$Install(step:current))]} {
	if {[catch {
	    eval "InstallSetupVars; $Install(action:$kind:$Install(step:current))"
	} error]} {
	tk_dialog \
	    .err \
	    Error \
	    $error \
	    error \
	    0 \
	    OK
	    return -code error
	}
    }
    
}

# do next step. Possibly call associated actions
proc InstallNextStep {} {
    global Install
    if { $Install(step:current) == $Install(step:last) } {
	return
    }
    if {[catch {InstallCallActions next}]} {
	return
    }
    incr Install(step:current) 
    InstallCallActions pre
    raise $Install(window:step:$Install(step:current))
    InstallCallActions after
    InstallButtons $Install(step:current)
}

# go to previous step
proc InstallPreviousStep {} {
    global Install
    if { $Install(step:current) == 0 } {
	return
    }
    incr Install(step:current) -1
    InstallCallActions pre
    raise $Install(window:step:$Install(step:current))
    InstallCallActions after
    InstallButtons $Install(step:current)
}


# cancel
proc InstallQuit {} {
    global Install
    if {[tk_dialog .cancel Cancel "Really exit setup ?" questhead 0 Yes No] == 0} {
	wm protocol .install WM_DELETE_WINDOW {}
	exit 0
    }
}

# end of installation
proc InstallFinish {} {
    global Install
    exit 0
}


# link at the upper level user variables which are stored
# in Install(vars:<var name>)
proc InstallSetupVars {} {
    uplevel 1 {
	global Install
	foreach var [array names Install vars:*] {
	    upvar \#0 Install($var) [string range $var 5 end]
	}
    }
}

# Install an action. If action is a procedure call
# insert first InstallSetupVars
proc InstallAction {step action} {
    global Install
    if {[info procs "$action"] != ""} {
	uplevel \#0 [format {
	    proc %s {} {
		InstallSetupVars
		%s
	    }
	} $action [string trim [info body [info procs $action]]]]
    }
    append Install(action:next:$step) $action {;}
}

# Show a message
proc InstallShowMessage {w text} {
    global Install
    InstallSetupVars
    set script [format {
	set raw_text "%s"
	if {[catch {eval "set text \"$raw_text\""}]} {
	    set text $raw_text 
	}
	%s configure -text $text
    } $text $w.msg]
    label $w.msg -justify left
    eval $script
    append Install(action:pre:$Install(step:current)) $script {;}
    pack $w.msg -pady 10 -padx 10
}

# view a file
set Install(file:ctr) 0
proc InstallViewFile {w file} {
    global Install
    pack [label $w.file -text $file]
    incr Install(file:ctr)
    set proc InstallViewFile_$Install(file:ctr)
    proc $proc {} \
	[format {
	    set w [toplevel .file]
	    wm title $w %1$s
	    text $w.text -width 80 -height 20 -wrap none -relief sunken -bg white
	    scrollbar $w.vscroll \
		-orient vertical \
		-command "$w.text yview"
	    scrollbar $w.hscroll \
		-orient horizontal \
		-command "$w.text xview"
	    $w.text configure \
		-xscrollcommand "$w.hscroll set" \
		-yscrollcommand "$w.vscroll set" 
	    pack [button $w.ok -text OK -command "destroy $w"] -side bottom
	    pack $w.hscroll -side bottom -fill x
	    pack $w.vscroll -side right -fill y
	    pack $w.text -side right 
	    set fd [open %1$s]
	    while {[gets $fd line] != -1} {
		$w.text insert end "$line\n"
	    }
	    close $fd
	    $w.text configure -state disabled
	    CenterWin $w
	    grab $w
	    tkwait window $w
	} $file]
    set Install(action:after:$Install(step:current)) $proc
}

# directory browser
set Install(dir:ctr) 0
proc InstallSetDirectory {f spec} {
    global Install
    incr Install(dir:ctr)
    set f [frame $f.dir$Install(dir:ctr)]
    set var [lindex $spec 2]
    set dir [lindex $spec 1]
    if { $dir == "current" } {
	set dir [pwd]
    }
    set Install(vars:$var) $dir
    label $f.l -text "[lindex $spec 0]:"
    entry $f.e -bg white -textvariable Install(vars:$var)

    button $f.b \
	-text "Browse..." \
	-command [format {
	    set dir [DirBrowser %s %s]
	    if { $dir != ""} {
		set Install(vars:%s) $dir
	    }
	} $dir  $f.b $var]

    $f.e xview end
    pack $f.l -side left
    pack $f.e -side left
    pack $f.b -side left
    pack $f -anchor w
}

# path selection
set Install(path:ctr) 0
proc InstallSetPath {f spec} {
    global Install
    incr Install(path:ctr)
    set f [frame $f.path$Install(path:ctr)]
    set var [lindex $spec 2]
    set Install(vars:$var) [lindex $spec 1]
    label $f.l -text "[lindex $spec 0]:"
    entry $f.e -bg white -textvariable Install(vars:$var)
    button $f.b \
	-text "Browse..." \
	-command [format {
	    set file [tk_getSaveFile \
			  -initialdir [pwd] \
			  -initialfile $Install(vars:%1$s)]
	    if { $file != "" } {
		set Install(vars:%1$s) $file
		%2$s.e icursor end
		%2$s.e xview insert
	    }
	} $var $f]
    $f.e icursor end
    $f.e xview insert
    pack $f.l -side left
    pack $f.e -side left
    pack $f.b -side left
    pack $f -anchor w
}

# yes/no buttons
set Install(check:ctr) 0
proc InstallYesNoCheck {f spec_list} {
    global Install

    set ctr [incr Install(check:ctr)]
    set f [frame $f.check$ctr]
    pack $f -anchor w
    set var [lindex $spec_list 0]
    pack [radiobutton $f.ncheck$ctr \
	      -text [lindex $spec_list 1] \
	      -variable Install(vars:$var) \
	      -value 0] \
	-anchor w
    pack [radiobutton $f.ycheck$ctr \
	      -text [lindex $spec_list 2] \
	      -variable Install(vars:$var) \
	      -value 1] \
	-anchor w
    set data [frame $f.data$ctr -relief ridge -bd 2]
    pack $data -anchor w
    InstallBuildStep \
	$data $Install(step:current) \
	[concat skip [lindex $spec_list 3]]

    $f.ncheck$ctr configure \
	-command "InstallSetTreeState $f.data$ctr disabled" 
    $f.ycheck$ctr configure \
	-command "InstallSetTreeState $f.data$ctr normal" 
    $f.ncheck$ctr invoke
}

# change normal/disable state for a widget tree
proc InstallSetTreeState {f state} {
    catch {$f configure -state $state}
    if {[string match [winfo class $f] Entry]} {
	$f configure \
	    -foreground [expr [string match $state normal]?"\#000000":"\#a3a3a3" ]
    }
    foreach child [winfo children $f] {
	InstallSetTreeState $child $state
    }
}
	
# path selection
set Install(name:ctr) 0
proc InstallName {f spec} {
    global Install
    incr Install(name:ctr)
    set f [frame $f.name$Install(name:ctr)]
    set var [lindex $spec 2]
    set Install(vars:$var) [lindex $spec 1]
    label $f.l -text "[lindex $spec 0]:"
    entry $f.e -bg white -textvariable Install(vars:$var)
    $f.e icursor end
    $f.e xview insert
    pack $f.l -side left
    pack $f.e -side left
    pack $f -anchor w
}


proc DirBrowser {initial parent} {
    global DirBrowser

    if {[winfo exist .dirb]} {
	return
    }
    toplevel .dirb
    wm title .dirb "Dir Browser"
    wm geometry .dirb +[winfo rootx $parent]+[winfo rooty $parent]
    # user dir
    pack [frame .dirb.f1]  -anchor w
    pack [label .dirb.f1.l -text Dir:] -side left -expand 1 -fill x
    pack [entry .dirb.f1.e \
	      -bg white \
	      -relief sunken \
	      -bd 2 \
	      -textvariable DirBrowser(dir)] -side left
    set DirBrowser(dir:entry) .dirb.f1.e
    bind $DirBrowser(dir:entry) <Return> {
	set DirBrowser(dir) [%W get]
	DirFill $DirBrowser(dir)
    }
    # list
    pack [frame .dirb.f2] -expand 1 -fill both
    listbox .dirb.f2.l \
	-relief sunken \
	-bd 2 \
	-bg white
    scrollbar .dirb.f2.xs \
	-orient horizontal \
	-command {.dirb.f2.l xview}
    scrollbar .dirb.f2.ys \
	-orient vertical \
	-command {.dirb.f2.l yview}
    .dirb.f2.l configure \
	-xscrollcommand {.dirb.f2.xs set} \
	-yscrollcommand {.dirb.f2.ys set}

    grid .dirb.f2.l -row 0 -column 0 -sticky nswe
    grid .dirb.f2.xs -row 1 -column 0 -sticky we
    grid .dirb.f2.ys -row 0 -column 1 -sticky ns
    grid rowconfigure .dirb.f2 0 -weight 1
    grid columnconfigure .dirb.f2 0 -weight 1

    set DirBrowser(list:widget) .dirb.f2.l

    bind $DirBrowser(list:widget) <ButtonRelease-1> {+
	set idx  [%W curselection]
	if { $idx != "" } {
	    set DirBrowser(dir) [DirFullPath $idx]
	    $DirBrowser(dir:entry) xview end
	}
    }
    bind $DirBrowser(list:widget) <Double-Button-1> {
	set idx  [%W curselection]
	if { $idx != "" } {
	    DirVisit $idx
	}
    }

    # button
    pack [frame .dirb.f3] -fill x
    pack [button .dirb.f3.ok \
	      -text OK \
	      -command {set DirBrowser(choice) 1; destroy .dirb}] \
	-expand 1 -anchor e -side left
    pack [button .dirb.f3.cancel \
	      -text Cancel \
	      -command {set DirBrowser(choice) 0; destroy .dirb}] \
	-expand 1 -anchor w -side left

    set DirBrowser(choice) 0

    # doit
    update
    DirInit $initial
    grab .dirb
    tkwait window .dirb

    if { $DirBrowser(choice) } {
	return $DirBrowser(dir)
    } else {
	return ""
    }
}

proc DirFullPath {idx} {
    global DirBrowser
    return [file join $DirBrowser(path:current) [$DirBrowser(list:widget) get $idx]]
}

proc DirVisit {idx} {
    global DirBrowser
    set item [$DirBrowser(list:widget) get $idx]
    if { $item == ".." } {
	set DirBrowser(dir) [file dirname $DirBrowser(path:current)]
	DirFill $DirBrowser(dir)
    } else {
	DirFill [file join $DirBrowser(path:current) $item]
    }
}

proc DirFill {path} {
    global DirBrowser
    $DirBrowser(list:widget) delete 0 end
    $DirBrowser(list:widget) insert end {..}
    $DirBrowser(list:widget) configure -cursor watch ; update
    foreach file [glob -nocomplain -- $path/*] {
	if {[file isdirectory $file]} {
	    $DirBrowser(list:widget) insert end [file tail $file]
	}
    }
    $DirBrowser(list:widget) configure -cursor {} ; update
    set DirBrowser(path:current) $path
}

proc DirInit {initial} {
    global DirBrowser
    set DirBrowser(dir) $initial
    DirFill $DirBrowser(dir)
    
    $DirBrowser(list:widget) yview [lsearch -exact \
					[$DirBrowser(list:widget) get 0 end] \
					[file tail DirBrowser(dir)]]
    $DirBrowser(dir:entry) xview end
}


wm withdraw .
update
InstallInit

