#!/usr/bin/env tclsh

set binpath [file dirname [file normalize [info script]]]

package require Tk
package require dicttool

ttk::notebook .n
set p1 [ttk::frame .n.p1]
set p2 [ttk::frame .n.p2]

.n add $p1 -text "Step 1: Define Structure"
.n add $p2 -text "Step 2: Specify Recipes"

#
# first panel captures basic parameters
#

# solution consistency and coverage

set f1 [ttk::frame $p1.f1]
set lcon [ttk::label $f1.lcon -text "Solution consistency: "]
set lcov [ttk::label $f1.lcov -text "Solution coverage: "]
set econ [ttk::entry $f1.econ -width 5 -textvariable solcon]
set ecov [ttk::entry $f1.ecov -width 5 -textvariable solcov]

grid $f1 -sticky w

grid $lcon -row 0 -column 0 -sticky w
grid $econ -row 0 -column 1 -sticky w
grid $lcov -row 1 -column 0 -sticky w
grid $ecov -row 1 -column 1 -sticky w

# condition names
set lconds [ttk::label $p1.lconds -text "Condition names:"]
set tconds [text $p1.tconds -width 60 -height 8]

grid $lconds -sticky w
grid $tconds -columnspan 2 -sticky w

# recipe names
set lrecipes [ttk::label $p1.lrecipes -text "Recipe names:"]
set trecipes [text $p1.trecipes -width 60 -height 8]
grid $lrecipes -sticky w
grid $trecipes -columnspan 2 -sticky w

# # panel 1 button
# set bnext [ttk::button $p1.bnext -text "Next" -default active -command {
#     panel2 [getConditionNames] [getRecipeNames]
#     .n select $p2
# }]
# grid $bnext -column 1 -sticky e

grid .n -row 0

proc getConditionNames {} {
    set raw [string trim [$::tconds get 1.0 end]]
    return [split $raw \n]
}

proc getRecipeNames {} {
    set raw [string trim [$::trecipes get 1.0 end]]
    return [split $raw \n]
}

##
## second panel captures glyph matrix
##

proc solStanza {} {
    global solcon
    global solcov
    if {![info exists solcon]} {
	set solcon -1
    }
    if {![info exists solcov]} {
	set solcov -1
    }
    set s "solcon $solcon\nsolcov $solcov"
    return $s
}

proc boxheadStanza {} {
    set recipeNames [getRecipeNames]
    set s "boxhead {\n\t$recipeNames\n}"
    return $s
}

proc stubStanza {} {
    set s "stub {"
    foreach condName [getConditionNames] {
	append s "\n\t[list $condName]"
    }
    append s "\n}"
    return $s
}

# the recipesStanza approach below is pretty messy and has a problem
# in that it doesn't handle missing or empty elements.  Here, I
# provide default values for these elements by looping through all
# recipes/conds (following the same pattern that generated the glyph
# matrix).  I may want to combine this validation process with the
# recipesStanza at some point in the future.
proc validateGM {} {
    upvar gm gm
    global DELIM
    set condNames [getConditionNames]
    set recipeNames [getRecipeNames]

    foreach rec $recipeNames {
	foreach cond $condNames {
	    # set condition to irrelevant if left empty
	    if {[llength "$gm($rec $DELIM $cond)"] == 0} {
		set "gm($rec $DELIM $cond)" Irr
	    }
	}
	
	# set concov scores to -1 if left empty
	if {[llength "$gm($rec $DELIM con)"] == 0} {
	    set "gm($rec $DELIM con)" -1
	}
	if {[llength "$gm($rec $DELIM cov)"] == 0} {
	    set "gm($rec $DELIM cov)" -1
	}
	if {[llength "$gm($rec $DELIM ucov)"] == 0} {
	    set "gm($rec $DELIM ucov)" -1
	}
    }
}

proc recipesStanza {} {
    global DELIM
    upvar gm gm

    # this is pretty messy at first.  the basic form of [array get gm]
    # is: \{recipe cond|metric\} glyph|score.  That is, a recipe name,
    # followed either a condition name or a metric (con, cov, ucov),
    # followed by either a glyph value or a metric score.
    #
    # I hack this structure apart and then flatten it into a list that I can reconstruct into a a dictionary.

    set l {}
    foreach {fst snd} [array get gm] {
	lassign [split $fst $DELIM] recipe cond
	set recipe [string trim $recipe]
	set cond [string trim $cond]
	set snd [string trim $snd]

	set m [switch $cond {
	    con { list $recipe metrics con $snd }
	    cov { list $recipe metrics cov $snd }
	    ucov { list $recipe metrics ucov $snd }
	    default { list $recipe conds $cond $snd }
	}]

	set l [concat $l $m]
    }

    foreach {recipeName key fst snd} $l {
	dict set d $recipeName $key $fst $snd
    }

    return "recipes {[dict print $d]}"
}


bind .n <Button-1> {NotebookCheckTabChange %W %x %y}

proc NotebookCheckTabChange {nb x y} {
    # Identify which tab was clicked
    set clickedTab [$nb identify tab $x $y]
    if {$clickedTab eq ""} {
        return    ;# click wasn't on a tab
    }

    # Determine current tab and target tab
    set current [$nb index current]
    set target  $clickedTab

    # If moving FROM step 1 TO step 2, validate
    if {$current == 0 && $target == 1} {

	# test that condition names were entered
	set condNames [getConditionNames]
        if {[llength $condNames] == 0} {
            tk_messageBox -icon warning -title "Error" -message "Conditions are missing. Add them to continue."
            return -code break   ;# *** Prevent the tab switch ***
        }

	# test for duplicate condition names
	if {[lsort $condNames] ne [lsort -unique $condNames]} {
            tk_messageBox -icon warning -title "Error" -message "Duplicate condition names are prohibited."
            return -code break   ;# *** Prevent the tab switch ***
        }

	set recipeNames [getRecipeNames]
	# test that recipe names were entered
        if {[llength $recipeNames] == 0} {
            tk_messageBox -icon warning -title "Error" -message "Recipes are missing. Add them to continue."
            return -code break   ;# *** Prevent the tab switch ***
        }

	# test for duplicate recipe names
	if {[lsort $recipeNames] ne [lsort -unique $recipeNames]} {
            tk_messageBox -icon warning -title "Error" -message "Duplicate condition names are prohibited."
            return -code break   ;# *** Prevent the tab switch ***
        }
    }
}


set sig \x10
bind .n <<NotebookTabChanged>> {
    set nb %W

    # the user can toggle back and forth between tabs as long as they
    # don't change any of the condition or recipe names.  When they
    # do, destroy the second tab's frame and reconstruct.
    if {[$nb select] eq $p2} {

	set conds [getConditionNames]
	
	set recipes [getRecipeNames]
	if {[llength $conds] == 0} {
	    tk_messageBox -message "Recipes are missing.  Add them to proceed."
	}
	
	if {[string equal $sig [concat $conds $recipes]] == 0} {
	    set sig [concat $conds $recipes]
	    if {[info exists f2]} {
		destroy $f2
		destroy $bcreate
	    }
	    source [file join $binpath wizard-glyph-matrix.tcl]
	}
    }
}

# force window to top; I'm not sure that 'focus -force' is the best
# approach here, but at least on macOS, the Wizard is otherwise
# popping up underneath the editor and it appears that the software
# has hung
wm attributes . -topmost
focus -force .

wm title . "Fiss Chart Wizard"
