#!/bin/sh  
# \
exec oagwish "$0" "$@"

if {![info exists env(OAG_TOP_DIR)]} { set env(OAG_TOP_DIR) /usr/local }
set auto_path [linsert $auto_path 0  $env(OAG_TOP_DIR)/oag/apps/lib/$env(HOST_ARCH)]

APSStandardSetup
option clear
APSApplication . -name "Experiment Configuration Editor" -overview "Applicaton to create and submit experiment configuration files to /net/oxygen/apsu/mbadm/data"

set data(topLevelDir) /net/oxygen/apsu/mbadm
if {![file exists $data(topLevelDir)]} {
    set data(topLevelDir) C:/apsu/mbadm
    if {![file exists $data(topLevelDir)]} {
        set data(topLevelDir) Z:/apsu/mbadm
        if {![file exists $data(topLevelDir)]} {
            set data(topLevelDir) X:/apsu/mbadm
            if {![file exists $data(topLevelDir)]} {
                set data(topLevelDir) D:/apsu/mbadm
                if {![file exists $data(topLevelDir)]} {
                    set data(topLevelDir) /Users/soliday/apsu/mbadm
                }
            }
        }
    }
}

proc AddParameter {} {
    set w .userFrame.lf1.misc
    global data
    incr data(miscParameter.count)
    set i $data(miscParameter.count)

    set data(miscParameter$i.label) ""
    set data(miscParameter$i.value) ""
    ttk::entry ${w}Label.label$i -textvariable data(miscParameter$i.label)
    ttk::entry ${w}Value.value$i -textvariable data(miscParameter$i.value)
    pack ${w}Label.label$i -fill x
    pack ${w}Value.value$i -fill x
}

proc RemoveParameter {} {
    set w .userFrame.lf1.misc
    global data
    set i $data(miscParameter.count)
    destroy ${w}Label.label$i ${w}Value.value$i
    if {[info exists data(miscParameter$i.label)]} {
        unset data(miscParameter$i.label)
    }
    if {[info exists data(miscParameter$i.value)]} {
        unset data(miscParameter$i.value)
    }
    incr data(miscParameter.count) -1
}

proc AddLine {args} {
    set widget ""
    set name ""
    set file 0
    set userSpecifiedKey 0
    set hasDescription 0
    APSStrictParseArguments {widget name file userSpecifiedKey hasDescription}
    global data
    incr data(${name}.count)
    set i [set data(${name}.count)]
    set data(${name}$i) ""
    if {![info exists data(Desc${name}$i)]} {
        set data(Desc${name}$i) ""
    }
    if {$file} {
        if {$hasDescription} {
            ttk::frame $widget.data.values.v$i
            ttk::entry $widget.data.values.v$i.entry -textvariable data(${name}$i)
            ttk::button $widget.data.values.v$i.file -text F -style Toolbutton -command "GetFileName -index ${name}$i"
            pack $widget.data.values.v$i -fill x
            pack $widget.data.values.v$i.entry -side left -fill x -expand true
            pack $widget.data.values.v$i.file -side right -pady 0
            if {$file == 2} {
                ttk::button $widget.data.values.v$i.dir -text D -style Toolbutton -command "GetDirName -index ${name}$i"
                pack $widget.data.values.v$i.dir -side right -pady 0
            }
            ttk::entry $widget.data.descriptions.v$i -textvariable data(Desc${name}$i)
            pack $widget.data.descriptions.v$i -fill x -pady 1
        } else {
            ttk::frame $widget.v$i
            ttk::entry $widget.v$i.entry -textvariable data(${name}$i)
            ttk::button $widget.v$i.file -text F -style Toolbutton -command "GetFileName -index ${name}$i"
            pack $widget.v$i -fill x
            pack $widget.v$i.entry -side left -fill x -expand true
            pack $widget.v$i.file -side right -pady 0
        }
    } elseif {$userSpecifiedKey} {
        set data(${name}$i.key) ""
        set data(Desc${name}$i.key) ""
        ttk::entry $widget.data.keys.key$i -textvariable data(${name}$i.key)
        ttk::entry $widget.data.values.entry$i -textvariable data(${name}$i)
        ttk::entry $widget.data.descriptions.entry$i -textvariable data(Desc${name}$i)
        pack $widget.data.keys.key$i
        pack $widget.data.values.entry$i -fill x -expand true
        pack $widget.data.descriptions.entry$i -fill x -expand true
    } else {
        if {$hasDescription} {
            ttk::entry $widget.data.values.v$i -textvariable data(${name}$i)
            pack $widget.data.values.v$i -fill x
            ttk::entry $widget.data.descriptions.v$i -textvariable data(Desc${name}$i)
            pack $widget.data.descriptions.v$i -fill x
        } else {
            ttk::entry $widget.v$i -textvariable data(${name}$i)
            pack $widget.v$i -fill x
        }
    }
}

proc GetFileName {args} {
    APSStrictParseArguments {index}
    global data
    set selection [tk_getOpenFile -parent .]
    if {$selection != ""} {
        set data($index) $selection
    }
}

proc GetDirName {args} {
    APSStrictParseArguments {index}
    global data
    set selection [tk_chooseDirectory -parent .]
    if {$selection != ""} {
        set data($index) $selection
    }
}

proc RemoveLine {args} {
    set widget ""
    set name ""
    APSStrictParseArguments {widget name}
    global data
    set i [set data(${name}.count)]
    if {$i == 0} { return }
    if {[winfo exists $widget.v$i]} {
        destroy $widget.v$i
    } elseif {[winfo exists $widget.data.values.v$i]} {
        destroy $widget.data.values.v$i $widget.data.descriptions.v$i
    } elseif {[winfo exists $widget.data.keys.key$i]} {
        destroy $widget.data.keys.key$i $widget.data.values.entry$i $widget.data.descriptions.entry$i
    }
    if {[info exists data(${name}$i)]} {
        unset data(${name}$i)
    }
    incr data(${name}.count) -1
}

proc QuickEdit {args} {
    set widget ""
    set name ""
    set file 0
    set hasDescription 0
    APSStrictParseArguments {widget name file hasDescription}
    global data
    if {[winfo exists .quickEdit]} {
        destroy .quickEdit
    }
    toplevel .quickEdit
    text .quickEdit.text -width 80 -height 15 -yscrollcommand ".quickEdit.yscroll set" -xscrollcommand ".quickEdit.xscroll set" -bg white
    ttk::scrollbar .quickEdit.yscroll -command ".quickEdit.text yview"
    ttk::scrollbar .quickEdit.xscroll -command ".quickEdit.text xview" -orient horizontal
    grid .quickEdit.text -row 1 -column 1 -sticky nwes
    grid .quickEdit.yscroll -row 1 -column 2 -sticky ns
    grid .quickEdit.xscroll -row 2 -column 1 -sticky ew
    ttk::frame .quickEdit.buttons
    grid .quickEdit.buttons -row 3 -column 1
    grid rowconfigure .quickEdit .quickEdit.text -weight 1
    grid columnconfigure .quickEdit .quickEdit.text -weight 1
    ttk::button .quickEdit.buttons.apply -text "Apply" -command "ApplyQuickEdit -widget $widget -name $name -file $file -hasDescription $hasDescription"
    ttk::button .quickEdit.buttons.dismiss -text "Dismiss" -command "destroy .quickEdit"
    pack .quickEdit.buttons.apply .quickEdit.buttons.dismiss -side left

    set valueList ""
    for {set i 1} {$i <= $data($name.count)} {incr i} {
        set value [string trim $data(${name}$i)]
        if {[string length $value] == 0} {
            continue
        }
        lappend valueList $value
    }
    .quickEdit.text insert 1.0 [join $valueList \n]

    wm title .quickEdit "Experiment Description Quick Edit"
    update     
    set x [expr [winfo rootx .] + [winfo reqwidth .] / 2 - [winfo reqwidth .quickEdit] / 2]
    set y [expr [winfo rooty .] + [winfo reqheight .] / 2 - [winfo reqheight .quickEdit] / 2]
    wm geometry .quickEdit [winfo reqwidth .quickEdit]x[winfo reqheight .quickEdit]+${x}+${y}
}

proc ApplyQuickEdit {args} {
    set widget ""
    set name ""
    set file 0
    set hasDescription 0
    APSStrictParseArguments {widget name file hasDescription}
    global data
    while {[set data(${name}.count)] > 0} {
        RemoveLine -widget $widget -name $name
    }
    foreach line [split [string trim [.quickEdit.text get 1.0 end]] \n] {
        set line [string trim $line]
        if {[string length $line] == 0} {
            continue
        }
        AddLine -widget $widget -name $name -file $file -hasDescription $hasDescription
        set i [set data(${name}.count)]
        set data(${name}$i) $line
    }
    destroy .quickEdit
}


proc InitTheme {} {
 
    # Modify the current style definition for a Ttk button.
    set layout [ttk::style layout TButton]
    set tail [lindex $layout end]
    set tail [list Plain.Button.fill -sticky news -children $tail]
    ttk::style layout Plain.Button [lreplace $layout end end $tail]
    
    # Copy the standard configuration and override the background
    ttk::style configure Plain.Button {*}[ttk::style configure TButton] \
      -background yellow
    ttk::style map Plain.Button {*}[ttk::style map TButton] \
      -background {active LightYellow}
    
    if {[lsearch -exact [bind . <<ThemeChanged>>] InitTheme] == -1} {
        bind . <<ThemeChanged>> +InitTheme
    }
}
 
InitTheme 
proc SetupGUI {args} {
    global data

    set w .userFrame
    set i 1

    ttk::label .lflabel1 -text Parameters
    ttk::labelframe $w.lf$i -labelwidget .lflabel1
    pack $w.lf$i -fill x

    set data(miscParameter.count) 0
    ttk::frame $w.lf$i.buttons 
    ttk::button $w.lf$i.buttons.add -text "+" -style Toolbutton \
      -command "AddParameter"
    ttk::button $w.lf$i.buttons.remove -text "-" -style Toolbutton \
      -command "RemoveParameter"
    grid $w.lf$i.buttons -row 1 -column 1 -sticky w
    pack $w.lf$i.buttons.add $w.lf$i.buttons.remove -side left

    set files [glob -nocomplain -directory $data(topLevelDir)/experimentTemplates *template*.ecf]
    if {[catch {eval exec sddscombine -collapse $files -pipe=out | sddssort -pipe -unique -col=typeOfExperiment | sdds2stream -pipe=in -col=typeOfExperiment} templateTypes]} {
        bell
        #tk_messageBox -type ok -icon warning -message "No valid templates found. $templateTypes"
        set templateTypes {"M1 Dipole Measurement" "PS Stability" "Timestamp Measurements"}
    }

    set data(typeOfExperiment) ""
    ttk::label $w.lf$i.f1label -text "Type of Experiment:"
    ttk::combobox $w.lf$i.f1value -textvariable data(typeOfExperiment) \
      -values $templateTypes
    grid $w.lf$i.f1label -row 2 -column 1 -sticky e
    grid $w.lf$i.f1value -row 2 -column 2 -sticky ew
    grid columnconfigure $w.lf$i 2 -weight 1
    bind $w.lf$i.f1value <<ComboboxSelected>> "LoadTemplate %W"

    set data(testProcedureLink) ""
    ttk::label $w.lf$i.f2label -text "Test Procedure Link:"
    ttk::entry $w.lf$i.f2value -textvariable data(testProcedureLink)
    grid $w.lf$i.f2label -row 3 -column 1 -sticky e
    grid $w.lf$i.f2value -row 3 -column 2 -sticky ew

    set data(testLocation) ""
    ttk::label $w.lf$i.f3label -text "Test Location:"
    ttk::entry $w.lf$i.f3value -textvariable data(testLocation)
    grid $w.lf$i.f3label -row 4 -column 1 -sticky e
    grid $w.lf$i.f3value -row 4 -column 2 -sticky ew

    set data(operatorName) ""
    ttk::label $w.lf$i.f4label -text "Operator Name:"
    ttk::entry $w.lf$i.f4value -textvariable data(operatorName)
    grid $w.lf$i.f4label -row 5 -column 1 -sticky e
    grid $w.lf$i.f4value -row 5 -column 2 -sticky ew
 
    set data(operatorComment) ""
    ttk::label $w.lf$i.f5label -text "Operator Comment:"
    ttk::entry $w.lf$i.f5value -textvariable data(operatorComment)
    grid $w.lf$i.f5label -row 6 -column 1 -sticky e
    grid $w.lf$i.f5value -row 6 -column 2 -sticky ew

    set data(logBook) ""
    ttk::label $w.lf$i.f6label -text "Log Book URL:" -foreground blue -cursor hand1
    ttk::entry $w.lf$i.f6value -textvariable data(logBook)
    grid $w.lf$i.f6label -row 7 -column 1 -sticky e
    grid $w.lf$i.f6value -row 7 -column 2 -sticky ew
    bind $w.lf$i.f6label <ButtonRelease-1> "OpenlogBook"

    global ecfHardware
    if {[catch {sdds load $data(topLevelDir)/experimentTemplates/ecf_hardwareTypes.sdds ecfHardware} results]} {
        set ecfHardware(Parameter.componentTag) ""
	set ecfHardware(Column.qrCode) ""
	set ecfHardware(Column.hardwareType) ""
    }
    set data(componentTag) [lindex $ecfHardware(Parameter.componentTag) 0]
    ttk::label $w.lf$i.f7label -text "Component Tag:"
    ttk::combobox $w.lf$i.f7value -textvariable data(componentTag) -values $ecfHardware(Parameter.componentTag)
    grid $w.lf$i.f7label -row 8 -column 1 -sticky e
    grid $w.lf$i.f7value -row 8 -column 2 -sticky ew

    set data(qrCode) [lindex [lindex $ecfHardware(Column.qrCode) 0] 0]
    ttk::label $w.lf$i.f8label -text "QR Code:"
    ttk::combobox $w.lf$i.f8value -textvariable data(qrCode) -values [lindex $ecfHardware(Column.qrCode) 0] -state readonly
    set data(qrCodeWidget) $w.lf$i.f8value
    grid $w.lf$i.f8label -row 9 -column 1 -sticky e
    grid $w.lf$i.f8value -row 9 -column 2 -sticky ew

    set data(hardwareType) [lindex [lindex $ecfHardware(Column.hardwareType) 0] 0]
    ttk::label $w.lf$i.f9label -text "Hardware Type:"
    ttk::combobox $w.lf$i.f9value -textvariable data(hardwareType) -values [lindex $ecfHardware(Column.hardwareType) 0] -state readonly
    set data(hardwareTypeWidget) $w.lf$i.f9value
    grid $w.lf$i.f9label -row 10 -column 1 -sticky e
    grid $w.lf$i.f9value -row 10 -column 2 -sticky ew

    global ecfTypes
    if {[catch {sdds load $data(topLevelDir)/experimentTemplates/ecf_measurementTypes.sdds ecfTypes} results]} {
	set ecfTypes(Parameter.type) ""
	set ecfTypes(Column.parameterLabel) ""
	set ecfTypes(Column.parameterName) ""
	set ecfTypes(Column.parameterType) ""
    }

    set data(measurementType) [lindex $ecfTypes(Parameter.type) 0]
    ttk::label $w.lf$i.f10label -text "Measurement Type:"
    ttk::combobox $w.lf$i.f10value -textvariable data(measurementType) -values $ecfTypes(Parameter.type) -state readonly
    grid $w.lf$i.f10label -row 11 -column 1 -sticky e
    grid $w.lf$i.f10value -row 11 -column 2 -sticky ew

    if 0 {
    set id 9
    set row 10
    set data(additionalParameters.count) 0
    set data(additionalParameters.parent) $w.lf$i
    set data(additionalParameters.id) 10
    set data(additionalParameters.row) 11
    foreach label [lindex $ecfTypes(Column.parameterLabel) 0]  name [lindex $ecfTypes(Column.parameterName) 0] datatype [lindex $ecfTypes(Column.parameterType) 0] {
         incr id
         incr row
         set data($name) ""
         incr data(additionalParameters.count)
         ttk::label $w.lf$i.f${id}label -text "${label}:"
         ttk::entry $w.lf$i.f${id}value -textvariable data($name)
         grid $w.lf$i.f${id}label -row $row -column 1 -sticky e
         grid $w.lf$i.f${id}value -row $row -column 2 -sticky ew
    }
    }


    #Increment by 20 here so that we can have 20 additional parameters without messing up the GUI
    set id 30
    set row 31
    set data(dataSetNumber) 0
#    set data(ecfName) "$data(topLevelDir)/data/$data(componentTag)/$data(qrCode)/[clock format [clock seconds] -format %Y]/[clock format [clock seconds] -format %m]/[clock format [clock seconds] -format %d]/$data(measurementType)-$data(componentTag)-$data(qrCode)-[format %04d $data(dataSetNumber)].ecf"
    set data(ecfName) "$data(topLevelDir)/data/$data(hardwareType)/$data(measurementType)/$data(componentTag)/$data(qrCode)/$data(measurementType)-$data(componentTag)-$data(qrCode)-[format %04d $data(dataSetNumber)].ecf"
    set data(timeCreated) ""
    set data(dateCreated) ""
    set data(timeLastModified) ""
    set data(dateLastModified) ""
    ttk::label $w.lf$i.f${id}label -text "Date Created:"
    ttk::entry $w.lf$i.f${id}value -textvariable data(dateCreated) -state readonly
    grid $w.lf$i.f${id}label -row $row -column 1 -sticky e
    grid $w.lf$i.f${id}value -row $row -column 2 -sticky ew
    trace add variable data(timeCreated) write UpdatedDateInfo

    incr id
    incr row
    ttk::label $w.lf$i.f${id}label -text "Date Last Modified:"
    ttk::entry $w.lf$i.f${id}value -textvariable data(dateLastModified) -state readonly
    grid $w.lf$i.f${id}label -row $row -column 1 -sticky e
    grid $w.lf$i.f${id}value -row $row -column 2 -sticky ew
    trace add variable data(timeLastModified) write UpdatedDateInfo

    trace add variable data(componentTag) write UpdatedECFName
    trace add variable data(qrCode) write UpdatedECFName
    trace add variable data(hardwareType) write UpdatedECFName
    trace add variable data(measurementType) write UpdatedECFName
    #trace add variable data(dataSetNumber) write UpdatedECFName

    incr id
    incr row
    ttk::frame $w.lf$i.miscLabel
    ttk::frame $w.lf$i.miscValue
    grid $w.lf$i.miscLabel -row $row -column 1 -sticky ew
    grid $w.lf$i.miscValue -row $row -column 2 -sticky ew

    ttk::style configure TNotebook -tabposition nw
    #ttk::style configure TNotebook.Tab -foreground green
    ttk::notebook .userFrame.notebook
    pack .userFrame.notebook -fill x -anchor nw
    set n .userFrame.notebook


    if {[catch {sdds load $data(topLevelDir)/experimentTemplates/ecf_keys.sdds ecfKeys} results]} {
        #bell
        #tk_messageBox -type ok -icon error -message "$results"
        #exit
	set ecfKeys(Column.name) [list "testInstrument experimentDataFile associatedFile loggedPVofInterest expDataSetModification plotScript automationScript"]
	set ecfKeys(Column.required)  [list "0 1 0 0 0 0 0"]
	set ecfKeys(Column.isFile) [list "0 2 1 0 0 1 1"]
	set ecfKeys(Column.hasDescription) [list "1 1 1 1 0 1 1"]
	set ecfKeys(Column.highlight) [list "1 1 1 1 0 0 0"]
	set ecfKeys(Column.type) [list "key key key key key key key"]
	set ecfKeys(Column.label) [list {"Test Instrument" "Experiment Data File" "Associated File" "Logged PVs" "Description of Modification" "Plot Script" "Automation Script"}]
    }
    set data(keyList) [lindex $ecfKeys(Column.name) 0]
    set data(keyReqList) [lindex $ecfKeys(Column.required) 0]
    set data(keyIsFileList) [lindex $ecfKeys(Column.isFile) 0]
    set data(keyHasDescriptionList) [lindex $ecfKeys(Column.hasDescription) 0]
    set data(keyHighlight) [lindex $ecfKeys(Column.highlight) 0]
    
    foreach type [lindex $ecfKeys(Column.type) 0] \
      name [lindex $ecfKeys(Column.name) 0] \
      required [lindex $ecfKeys(Column.required) 0] \
      label [lindex $ecfKeys(Column.label) 0] \
      isFile [lindex $ecfKeys(Column.isFile) 0] \
      hasDesc [lindex $ecfKeys(Column.hasDescription) 0] \
      highlight [lindex $ecfKeys(Column.highlight) 0] {
          if {$type != "key"} {
              continue
          }
          incr i
	  ttk::label .label$i -text $label
          ttk::labelframe $n.lf$i -labelwidget .label$i
          pack $n.lf$i -fill x
          ttk::frame $n.lf$i.buttons 
          ttk::button $n.lf$i.buttons.add -text "+" -style Toolbutton \
            -command "AddLine -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc"
          ttk::button $n.lf$i.buttons.remove -text "-" -style Toolbutton \
            -command "RemoveLine -widget $n.lf$i -name $name"
          ttk::button $n.lf$i.buttons.edit -text "Quick Edit" \
            -command "QuickEdit -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc"
          pack $n.lf$i.buttons -anchor nw -fill x
          pack $n.lf$i.buttons.add $n.lf$i.buttons.remove -side left
          pack $n.lf$i.buttons.edit -side right
          set data(${name}.count) 0
          if {$hasDesc} {
              ttk::frame $n.lf$i.data
	      ttk::label .labelv$i -text "Value"
	      ttk::label .labeld$i -text "Description"
              ttk::labelframe $n.lf$i.data.values -labelwidget .labelv$i
              ttk::labelframe $n.lf$i.data.descriptions -labelwidget .labeld$i
              pack $n.lf$i.data -fill both -expand true
              pack $n.lf$i.data.values $n.lf$i.data.descriptions -side left -fill x -expand true -anchor nw
          }
          AddLine -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc
          AddLine -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc
          AddLine -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc
          AddLine -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc
          AddLine -widget $n.lf$i -name $name -file $isFile -hasDescription $hasDesc
          $n add $n.lf$i -text " $label "
      }

    incr i
    set var userSpecified
    set label "User Specified"
    ttk::label .label$i -text $label
    ttk::labelframe $n.lf$i -labelwidget .label$i
    pack $n.lf$i -fill x
    ttk::frame $n.lf$i.buttons 
    ttk::button $n.lf$i.buttons.add -text "+" -style Toolbutton \
      -command "AddLine -widget $n.lf$i -name $var -userSpecifiedKey 1"
    ttk::button $n.lf$i.buttons.remove -text "-" -style Toolbutton \
      -command "RemoveLine -widget $n.lf$i -name $var"
    pack $n.lf$i.buttons -anchor nw
    pack $n.lf$i.buttons.add $n.lf$i.buttons.remove -side left
    set data(${var}.count) 0
    ttk::frame $n.lf$i.data
    ttk::label .labelk$i -text "Key"
    ttk::label .labelv$i -text "Value"
    ttk::label .labeld$i -text "Description"
    ttk::labelframe $n.lf$i.data.keys -labelwidget .labelk$i
    ttk::labelframe $n.lf$i.data.values -labelwidget .labelv$i
    ttk::labelframe $n.lf$i.data.descriptions -labelwidget .labeld$i
    pack $n.lf$i.data -fill both -expand true
    pack $n.lf$i.data.keys -side left -anchor nw
    pack $n.lf$i.data.values -side left -fill x -expand true -anchor nw
    pack $n.lf$i.data.descriptions -side left -fill x -expand true -anchor nw
    AddLine -widget $n.lf$i -name $var -userSpecifiedKey 1
    AddLine -widget $n.lf$i -name $var -userSpecifiedKey 1
    AddLine -widget $n.lf$i -name $var -userSpecifiedKey 1
    AddLine -widget $n.lf$i -name $var -userSpecifiedKey 1
    AddLine -widget $n.lf$i -name $var -userSpecifiedKey 1
    $n add $n.lf$i -text " $label "

    
    ttk::label .fname -text Files
    ttk::labelframe .userFrame.files -labelwidget .fname
    pack .userFrame.files -fill x -anchor nw

    set data(ecfName) ""
    set data(loadedECFname) ""
    ttk::label .userFrame.files.l1 -text "Next Dataset:"
    ttk::entry .userFrame.files.e1 -textvariable data(ecfName) -state readonly
    grid .userFrame.files.l1 -row 1 -column 1 -sticky e
    grid .userFrame.files.e1 -row 1 -column 2 -sticky ew
    grid columnconfigure .userFrame.files 2 -weight 1
    ttk::label .userFrame.files.l2 -text "Current Dataset:"
    ttk::entry .userFrame.files.e2 -textvariable data(loadedECFname) -state readonly
    grid .userFrame.files.l2 -row 2 -column 1 -sticky e
    grid .userFrame.files.e2 -row 2 -column 2 -sticky ew


    #ttk::style configure 

    ttk::frame .userFrame.buttons
    pack .userFrame.buttons -anchor nw -fill x
    ttk::button .userFrame.buttons.save -text " Save New Dataset " -command "Save"
    ttk::label .userFrame.buttons.unsaved -text " Changes not saved yet " -foreground red -background black
    ttk::button .userFrame.buttons.overwrite -text " Save Current Dataset " -command "Save -overwrite 1"
    ttk::button .userFrame.buttons.load -text " Load Old Dataset " -command "Load"
    pack .userFrame.buttons.save -side left
    #pack .userFrame.buttons.unsaved -side left -padx 5 -fill y
    pack .userFrame.buttons.overwrite .userFrame.buttons.load -side right
    .userFrame.buttons.overwrite state disabled

    .menu.file.menu insert 0 separator
    .menu.file.menu insert 0 command -label "Save Template" -command "Save -template 1"
    .menu.file.menu insert 0 command -label "Load Template" -command "Load -template 1"

    trace add variable data write UpdatedOverwriteButton

    wm resizable . 1 0
}

proc UpdatedOverwriteButton {name1 name2 op} {
    catch {pack .userFrame.buttons.unsaved -side left -padx 5 -fill y}
    if {[.userFrame.buttons.overwrite state] != "disabled"} {
        #.userFrame.buttons.overwrite configure -style Plain.Button
    }
}

proc UpdatedDateInfo {name1 name2 op} {
    global data
    if {([string is integer $data(timeCreated)]) && ($data(timeCreated) > 0)} {
        set data(dateCreated) [clock format $data(timeCreated)]
    } else {
        set data(dateCreated) ""
    }
    if {([string is integer $data(timeLastModified)]) && ($data(timeLastModified) > 0)} {
        set data(dateLastModified) [clock format $data(timeLastModified)]
    } else {
        set data(dateLastModified) ""
    }
}

proc UpdatedECFName {name1 name2 op} {
    global data ecfHardware ecfTypes env mbadmDir

    if {$name2 == "measurementType"} {
        if {$data(measurementType) == "longCoil"} {
            #Use X drive not Z drive for longCoil
            set data(topLevelDir) /net/oxygen/apsu/mbadm
            if {![file exists $data(topLevelDir)]} {
                set data(topLevelDir) C:/apsu/mbadm
                if {![file exists $data(topLevelDir)]} {
                    set data(topLevelDir) X:/apsu/mbadm
                    if {![file exists $data(topLevelDir)]} {
                        set data(topLevelDir) Z:/apsu/mbadm
                        if {![file exists $data(topLevelDir)]} {
                            set data(topLevelDir) D:/apsu/mbadm
                            if {![file exists $data(topLevelDir)]} {
                                set data(topLevelDir) /Users/soliday/apsu/mbadm
                            }
                        }
                    }
                }
            }
        } else {
            set data(topLevelDir) /net/oxygen/apsu/mbadm
            if {![file exists $data(topLevelDir)]} {
                set data(topLevelDir) C:/apsu/mbadm
                if {![file exists $data(topLevelDir)]} {
                    set data(topLevelDir) Z:/apsu/mbadm
                    if {![file exists $data(topLevelDir)]} {
                        set data(topLevelDir) X:/apsu/mbadm
                        if {![file exists $data(topLevelDir)]} {
                            set data(topLevelDir) D:/apsu/mbadm
                            if {![file exists $data(topLevelDir)]} {
                                set data(topLevelDir) /Users/soliday/apsu/mbadm
                            }
                        }
                    }
                }
            }
        }
        if {[info exists env(MBADM_DIR)]} {
            set data(topLevelDir) $env(MBADM_DIR)
        }
        if {$mbadmDir != ""} {
            set data(topLevelDir) $mbadmDir
        }
    }

    set data(dataSetNumber) 0
    set data(ecfName) "$data(topLevelDir)/data/$data(hardwareType)/$data(measurementType)/$data(componentTag)/$data(qrCode)/$data(measurementType)-$data(componentTag)-$data(qrCode)-[format %04d $data(dataSetNumber)].ecf"
    while {[file exists $data(ecfName)]} {
        incr data(dataSetNumber)
        set data(ecfName) "$data(topLevelDir)/data/$data(hardwareType)/$data(measurementType)/$data(componentTag)/$data(qrCode)/$data(measurementType)-$data(componentTag)-$data(qrCode)-[format %04d $data(dataSetNumber)].ecf"
    }
    if {$name2 == "componentTag"} {
        set i [lsearch -exact $ecfHardware(Parameter.componentTag) $data(componentTag)]
        set values [lindex $ecfHardware(Column.qrCode) $i]
        $data(qrCodeWidget) configure -values $values
        if {[lsearch -exact $values $data(qrCode)] == -1} {
            #uncomment this in future versions
            set data(qrCode) [lindex $values 0]
        }
        set values [lindex $ecfHardware(Column.hardwareType) $i]
        $data(hardwareTypeWidget) configure -values $values
        if {[lsearch -exact $values $data(hardwareType)] == -1} {
            #uncomment this in future versions
            set data(hardwareType) [lindex $values 0]
        }
    } elseif {$name2 == "measurementType"} {
        if 0 { #Use User Specified values instead
            set id $data(additionalParameters.id)
            for {set n 0} {$n < $data(additionalParameters.count)} {incr n} {
                destroy $data(additionalParameters.parent).f${id}label
                destroy $data(additionalParameters.parent).f${id}value
                incr id
            }
            set data(additionalParameters.count) 0
            set id $data(additionalParameters.id)
            set row $data(additionalParameters.row)
            set i [lsearch -exact $ecfTypes(Parameter.type) $data(measurementType)]
            if {$i != -1} {
                foreach label [lindex $ecfTypes(Column.parameterLabel) $i]  name [lindex $ecfTypes(Column.parameterName) $i] datatype [lindex $ecfTypes(Column.parameterType) $i] {
                    #set data($name) ""
                    incr data(additionalParameters.count)
                    ttk::label $data(additionalParameters.parent).f${id}label -text "${label}:"
                    ttk::entry $data(additionalParameters.parent).f${id}value -textvariable data($name)
                    grid $data(additionalParameters.parent).f${id}label -row $row -column 1 -sticky e
                    grid $data(additionalParameters.parent).f${id}value -row $row -column 2 -sticky ew
                    incr id
                    incr row
                }
            }
        }
    }
    #May remove this in future but probably not
    if {$data(experimentDataFile.count) >= 1} {
        if {$data(loadedECFname) != ""} {
            set data(experimentDataFile1) [file rootname $data(loadedECFname)]
        } else {
            set data(experimentDataFile1) [file rootname $data(ecfName)]
        }
    }
}


proc OpenlogBook {} {
    global data
    if {[catch {launchBrowser $data(logBook)} err]} {
        
    }
}

proc Save {args} {
    set template 0
    set overwrite 0
    APSStrictParseArguments "template overwrite"
    global data filetype

    set output(ParameterNames) "typeOfExperiment testProcedureLink testLocation operatorName operatorComment logBook componentTag qrCode hardwareType measurementType"
    if {!$template} {
        append output(ParameterNames) " dataSetNumber timeCreated timeLastModified"
    }
    if {[string length [string trim $data(typeOfExperiment)]] == 0} {
        bell
        tk_messageBox -type ok -icon warning -message "Invalid type of experiment"
        return
    }
    foreach name "componentTag qrCode hardwareType measurementType" {
        set s [string trim $data($name)]
        if {([string length $s] == 0) || ($s == "???")} {
            bell
            tk_messageBox -type ok -icon warning -message "Invalid parameter: $name"
            return
        }
        if {[llength $s] != 1} {
            bell
            tk_messageBox -type ok -icon warning -message "Spaces are not allowed in $name"
            return
        }
    }
    set output(Parameter.typeOfExperiment) [list [string trim $data(typeOfExperiment)]]
    set output(Parameter.testProcedureLink) [list [string trim $data(testProcedureLink)]]
    set output(Parameter.testLocation) [list [string trim $data(testLocation)]]
    set output(Parameter.operatorName) [list [string trim $data(operatorName)]]
    set output(Parameter.operatorComment) [list [string trim $data(operatorComment)]]
    set output(Parameter.logBook) [list [string trim $data(logBook)]]
    set output(Parameter.componentTag) [list [string trim $data(componentTag)]]
    set output(Parameter.qrCode) [list [string trim $data(qrCode)]]
    set output(Parameter.hardwareType) [list [string trim $data(hardwareType)]]
    set output(Parameter.measurementType) [list [string trim $data(measurementType)]]
    if 0 {
    global ecfTypes
    set i [lsearch -exact $ecfTypes(Parameter.type) $data(measurementType)]
    if {$i != -1} {
        foreach name [lindex $ecfTypes(Column.parameterName) $i] datatype [lindex $ecfTypes(Column.parameterType) $i] {
            if {!$template} {
                if {[string length [string trim $data($name)]] == 0} {
                    bell
                    tk_messageBox -type ok -icon warning -message "Invalid parameter: $name"
                    return
                }
            }
            append output(ParameterNames) " $name"
            set output(Parameter.$name) [list [string trim $data($name)]]
        }
    }
    }
    if {!$template} {
        #May remove this in future
        #Keeping it for now because this value may not be updated to the correct value after the last save
        if 1 {
            if {$data(experimentDataFile.count) >= 1} {
                if {$overwrite} {
                    set data(experimentDataFile1) [file rootname $data(loadedECFname)]
                } else {
                    set data(experimentDataFile1) [file rootname $data(ecfName)]
                }
            }
        }
        if {$overwrite} {
            set data(timeLastModified) [clock seconds]
            set output(Parameter.dataSetNumber) [list $data(loadedDataSetNumber)]
            set output(Parameter.timeCreated) [list $data(timeCreated)]
            set output(Parameter.timeLastModified) [list $data(timeLastModified)]
        } else {
            set data(timeCreated) [clock seconds]
            set data(timeLastModified) [clock seconds]
            set output(Parameter.dataSetNumber) [list $data(dataSetNumber)]
            set output(Parameter.timeCreated) [list $data(timeCreated)]
            set output(Parameter.timeLastModified) [list $data(timeLastModified)]
        }
        set output(ParameterInfo.dataSetNumber) "type SDDS_LONG"
        set output(ParameterInfo.timeCreated) "type SDDS_LONG"
        set output(ParameterInfo.timeLastModified) "type SDDS_LONG"
    } else {
        #We are not saving the experiment data file values in the template
        for {set i 1} {$i <= $data(experimentDataFile.count)} {incr i} {
            set data(experimentDataFile$i) ""
        }
    }

    for {set i 1} {$i <= $data(miscParameter.count)} {incr i} {
        set label [string trim $data(miscParameter$i.label)]
        set value [string trim $data(miscParameter$i.value)]
        if {[string length $label] != 0} {
            if {[string first " " $label] != -1} {
                bell
                tk_messageBox -type ok -icon warning -message "Parameter names cannot have spaces"
                return
            }
            append output(ParameterNames) " $label"
            set output(Parameter.$label) [list $value]
        }
    }

    set output(ColumnNames) "key value description"
    set keyList ""
    set valueList ""
    set descriptionList ""

    foreach key $data(keyList) required $data(keyReqList) hasDesc $data(keyHasDescriptionList) {
        set uniqueValues ""
        set found 0
        for {set i 1} {$i <= $data($key.count)} {incr i} {
            set value [string trim $data(${key}$i)]
            if {[string length $value] == 0} {
                continue
            }
            lappend keyList $key
            lappend valueList $value
            if {[lsearch -exact $uniqueValues $value] != -1} {
                bell
                tk_messageBox -type ok -icon warning -message "Data in $key has a duplicate entry of: $value"
                return
            }
            lappend uniqueValues $value
            if {$hasDesc} {
                lappend descriptionList [string trim $data(Desc${key}$i)]
            } else {
                lappend descriptionList ""
            }
            set found 1
        }
        if {!$template && $required && !$found} {
            bell
            tk_messageBox -type ok -icon warning -message "Data in $key is required"
            return
        }
    }
    for {set i 1} {$i <= $data(userSpecified.count)} {incr i} {
        set key [string trim $data(userSpecified$i.key)]
        if {[llength $key] > 1} {
            bell
            tk_messageBox -type ok -icon warning -message "User specified key cannot have spaces"
            return
        }
        if {[llength $key] == 0} {
            continue
        }
        set value [string trim $data(userSpecified$i)]
        set description [string trim $data(DescuserSpecified$i)]
        if 0 {
            if {!$template && ([string length $value] == 0)} {
                bell
                tk_messageBox -type ok -icon warning -message "Key $key has no value"
                return
            }
        }
        lappend keyList $key
        lappend valueList $value
        lappend descriptionList $description
    }
    set output(Column.key) [list $keyList]
    set output(Column.value) [list $valueList]
    set output(Column.description) [list $descriptionList]

    set types {
        {{ECF Template Files}   {*template*.ecf} }
        {{ECF Files}        {.ecf}       }
        {{SDDS Files}       {.sdds}       }
        {{All Files}        *             }
    }
    
    if {$template} {
        set initialDir $data(topLevelDir)/experimentTemplates
        set filetype {ECF Template Files}
        set initialFile $data(measurementType)-$data(componentTag)-$data(qrCode)_template.ecf
        set filename [tk_getSaveFile -initialdir $initialDir -initialfile $initialFile -defaultextension .ecf -parent . -filetypes $types -typevariable filetype]
	if {[string range $filename end-7 end] == ".ecf.ecf"} {
	    set filename [string range $filename 0 end-4]
	}
    } else {
        if {$overwrite} {
            set f $data(loadedECFname)
        } else {
            set f $data(ecfName)
        }
        set initialDir [file dirname $f]
        if {![file exists $initialDir]} {
            if {[catch {file mkdir $initialDir} results]} {
                bell
                tk_messageBox -type ok -icon warning -message "$results"
                set initialDir ""
            }
        }
        set filetype {ECF Files}
        set initialFile [file tail $f]
        #Do not give users a file dialog box
        set filename $f
    }
    if {$filename != ""} {
        if {[file exists $filename]} {
            set i 0
            while {[file exists ${filename}.bak[format %03d $i]]} {
                incr i
            }
            file rename -force $filename ${filename}.bak[format %03d $i]
        }
        if {[catch {sdds save $filename output} results]} {
            bell
            tk_messageBox -type ok -icon warning -message "$results"
        } else {
            if {!$template} {
                set data(loadedECFname) $filename
                if {!$overwrite} {
                    set data(loadedDataSetNumber) $data(dataSetNumber)
                }
                UpdatedECFName null null null
                .userFrame.buttons.overwrite state !disabled
                #.userFrame.buttons.overwrite configure -style TButton
            }
            catch {pack forget .userFrame.buttons.unsaved}
        }
    }
}

proc LoadTemplate {widget} {
    global data
    set type [$widget get]
    if {![string length $type]} {
        return
    }
    set dir $data(topLevelDir)/experimentTemplates
    set files [glob -nocomplain -directory $dir *template*.ecf]
    if {[catch {eval exec sddscombine -collapse $files -pipe=out | sdds2stream -pipe=in -col=typeOfExperiment} templateTypes]} {
        bell
        tk_messageBox -type ok -icon warning -message "No valid templates found in $dir."
        return
    }
    set i [lsearch -exact $templateTypes $type]
    if {$i != -1} {
        Load -template 1 -filename [lindex $files $i]
    }

}

proc Load {args} {
    set template 0
    set filename ""
    APSStrictParseArguments "template filename"
    global data input filetype initialDir
    set types {
        {{ECF Template Files}  {*template*.ecf} }
        {{ECF Files}        {.ecf}           }
        {{SDDS Files}       {.sdds}           }
        {{All Files}        *                 }
    }
    .userFrame.buttons.overwrite state disabled
    #.userFrame.buttons.overwrite configure -style TButton
    if {$template} {
        set initialDir $data(topLevelDir)/experimentTemplates
        set filetype {ECF Template Files}
    } else {
        if {![info exists initialDir]} {
            set initialDir $data(topLevelDir)/data
        } elseif {($initialDir == "$data(topLevelDir)/experimentTemplates")} {
            set initialDir $data(topLevelDir)/data
        } else {
            set initialDir ""
        }
        set filetype {ECF Files}
    }
    if {$filename == ""} {
        set filename [tk_getOpenFile -initialdir $initialDir -filetypes $types -typevariable filetype]
    }

    if {$filename == ""} {
	.userFrame.buttons.overwrite state !disabled
        return
    }
    unset -nocomplain input
    if {[catch {sdds load $filename input} results]} {
        bell
        tk_messageBox -type ok -icon warning -message "$results"
        return
    }
    set standardParameters "typeOfExperiment testProcedureLink testLocation operatorName operatorComment logBook componentTag qrCode hardwareType measurementType timeCreated timeLastModified"
    foreach parameter $standardParameters {
        set data($parameter) ""
    }
    set data(loadedDataSetNumber) 0
    while {$data(miscParameter.count) > 0} {
        RemoveParameter
    }
    foreach parameter $input(ParameterNames) {
        if {[lsearch -exact $standardParameters $parameter] >= 0} {
            set data($parameter) [lindex $input(Parameter.$parameter) 0]
        } elseif {$parameter == "dataSetNumber"} {
            set data(loadedDataSetNumber) [lindex $input(Parameter.$parameter) 0]
        }
    }
    if 0 {
    global ecfTypes 
    set i [lsearch -exact $ecfTypes(Parameter.type) $data(measurementType)]
    if {$i != -1} {
        foreach name [lindex $ecfTypes(Column.parameterName) $i] {
            if {[info exists input(Parameter.$name)]} {
                set data($name) [lindex $input(Parameter.$name) 0]
            } else {
                set data($name) ""
            }
            append standardParameters " $name"
        }
    }
    }
    set i 0
    foreach parameter $input(ParameterNames) {
        if {([lsearch -exact $standardParameters $parameter] == -1) && ($parameter != "dataSetNumber")} {
            AddParameter
            incr i
            set data(miscParameter$i.label) $parameter
            set data(miscParameter$i.value) [lindex $input(Parameter.$parameter) 0]
        }
    }
    set i 2
    foreach name $data(keyList) {
        while {[set data(${name}.count)] > 0} {
            RemoveLine -widget .userFrame.notebook.lf$i -name $name
        }
        incr i
    }
    set ii $i
    while {[set data(userSpecified.count)] > 0} {
        RemoveLine -widget .userFrame.notebook.lf$i -name userSpecified
    }
    if {![info exists input(Column.description)]} {
        foreach value [lindex $input(Column.value) 0] {
            lappend input(Column.description) ""
        }
        set input(Column.description) [list $input(Column.description)]
    }
    foreach key [lindex $input(Column.key) 0] value [lindex $input(Column.value) 0] description [lindex $input(Column.description) 0] {
        set i [lsearch -exact $data(keyList) $key]

        if {$i >=0} {
            set isFile [lindex $data(keyIsFileList) $i]
            set hasDesc [lindex $data(keyHasDescriptionList) $i]
            incr i 2
            AddLine -widget .userFrame.notebook.lf$i -name $key -file $isFile -hasDescription $hasDesc
            set data(${key}[set data(${key}.count)]) $value
            if {$hasDesc} {
                set data(Desc${key}[set data(${key}.count)]) $description
            }
        } else {
            incr i 2
            AddLine -widget .userFrame.notebook.lf$ii -name userSpecified -userSpecifiedKey 1
            set data(userSpecified[set data(userSpecified.count)].key) $key
            set data(userSpecified[set data(userSpecified.count)]) $value
            set data(DescuserSpecified[set data(userSpecified.count)]) $description
        }
    }
    set i 1
    foreach key $data(keyList) isFile $data(keyIsFileList) hasDesc $data(keyHasDescriptionList) {
        incr i
        while {$data(${key}.count) < 5} {
            AddLine -widget .userFrame.notebook.lf$i -name $key -file $isFile -hasDescription $hasDesc
        }
    }
    incr i
    while {[set data(userSpecified.count)] < 5} {
        AddLine -widget .userFrame.notebook.lf$i -name userSpecified -userSpecifiedKey 1 
    }
    if {!$template} {
        set data(loadedECFname) $filename
    }
    #May remove this in future
    if {$data(experimentDataFile.count) >= 1} {
        if {$data(loadedECFname) != ""} {
            set data(experimentDataFile1) [file rootname $data(loadedECFname)]
        } else {
            set data(experimentDataFile1) [file rootname $data(ecfName)]
        }
    }
    if {!$template} {
        .userFrame.buttons.overwrite state !disabled
        #.userFrame.buttons.overwrite configure -style TButton
    }
    catch {pack forget .userFrame.buttons.unsaved}
}

proc launchBrowser url {
    global tcl_platform

    if {$tcl_platform(platform) eq "windows"} {
        set command [list {*}[auto_execok start] {}]
        # Windows shell would start a new command after &, so shell escape it with ^
        set url [string map {& ^&} $url]
    } elseif {$tcl_platform(os) eq "Darwin"} {
        # It *is* generally a mistake to use $tcl_platform(os) to select functionality,
        # particularly in comparison to $tcl_platform(platform).  For now, let's just
        # regard it as a stylistic variation subject to debate.
        set command [list open]
    } else {
        set command [list xdg-open]
    }
    exec {*}$command $url &
}

set filename ""
set mbadmDir ""
set args $argv
APSStrictParseArguments {filename mbadmDir}

if {[info exists env(MBADM_DIR)]} {
    set data(topLevelDir) $env(MBADM_DIR)
}
if {$mbadmDir != ""} {
    set data(topLevelDir) $mbadmDir
}

SetupGUI

if {[catch {.menu.file.menu entrycget 3 -label} label]} {
    set restartIndex 4
} else {
    if {$label == "Restart"} {
	set restartIndex 3
    } else {
	set restartIndex 4
    }
}
.menu.file.menu entryconfigure $restartIndex -command "exec  $apsOagwishInstance [join [split $apsScriptCommand \\] /] & ; exit"


UpdatedECFName null null null
catch {pack forget .userFrame.buttons.unsaved}


proc NewDay {args} {
    global milliSecondsTillTomorrow
    UpdatedECFName null null null
    catch {pack forget .userFrame.buttons.unsaved}

    set milliSecondsTillTomorrow [expr [clock scan tomorrow] - [clock seconds] + 10]
    after $milliSecondsTillTomorrow NewDay
}

set milliSecondsTillTomorrow [expr ([clock scan tomorrow] - [clock seconds] + 10) * 1000]
after $milliSecondsTillTomorrow NewDay



if {$filename != ""} {
    pack forget .userFrame.buttons.save 
    grid forget .userFrame.files.l1 
    grid forget .userFrame.files.e1
    .userFrame.buttons.overwrite configure -command {
	set answer [tk_messageBox -title "ECF Overwrite Requested" -message "Are you sure you which to overwrite the previous ECF file?" -type yesno]
	if {$answer == "yes"} {
	    Save -overwrite 1
	}
    }

    Load -filename $filename
}
