#
#  gpsman --- GPS Manager: a manager for GPS receiver data
#
#  Copyright (c) 2001 Miguel Filgueiras (mig@ncc.up.pt) / Universidade do Porto
#
#    This program is free software; you can redistribute it and/or modify
#      it under the terms of the GNU General Public License as published by
#      the Free Software Foundation; either version 2 of the License, or
#      (at your option) any later version.
#
#      This program is distributed in the hope that it will be useful,
#      but WITHOUT ANY WARRANTY; without even the implied warranty of
#      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#      GNU General Public License for more details.
#
#      You should have received a copy of the GNU General Public License
#      along with this program.
#
#  File: lists.tcl
#  Last change:  2 September 2001
#

proc ChangeOnStateList {wh st} {
    # change state of items list when list becomes empty/non-empty
    #  $wh in $TYPES; $st in {normal, disabled}
    global LsW RcW RcMenu GPSState WConf RECTYPES

    if { "$wh" == "GR" } {
	set es "1 3 4 5 6 7" ; set aes "1 2 3 4 5 6"
	set bs "frget.frget2.getGR frput.putGR"
	# assume GR is last in $RECTYPES
	$RcMenu.gm entryconfigure last -state $st
	$RcMenu.ptm entryconfigure last -state $st
    } else {
	set es "1 4 5" ; set aes "1 3 4"
	set bs "frput.put$wh"
	# not good programming...
	set ix [lsearch -exact $RECTYPES $wh]
	if { [set ixic [lsearch -exact $RECTYPES IC]] != -1 && $ix > $ixic } {
	    incr ix -1
	}
	$RcMenu.ptm entryconfigure $ix -state $st
    }
    foreach e $es {
	$LsW.frl$wh.frb.file.m entryconfigure $e -state $st
    }
    if { "[set p $WConf(additemstate)]" != "" } {
	foreach e $aes {
	    ${p}$wh entryconfigure $e -state $st
	}
    }
    if { "$st" == "normal" && "$GPSState" == "online" } {
	set sg normal
    } else { set sg disabled }
    foreach b $bs {
	$RcW.$b configure -state $sg
    }
    return
}

proc ChangeOnStateData {st} {
    # change state of some menu entries when item set becomes empty/non empty
    #  $st in {normal, disabled}
    global WConf

    foreach p $WConf(datastate) {
	switch [lindex $p 0] {
	    menu {
		foreach m [lindex $p 1] {
		    set w [lindex $m 0]
		    foreach e [lindex $m 1] {
			$w entryconfigure $e -state $st
		    }
		}
	    }
	    button -  menubutton {
		foreach b [lindex $p 1] {
		    $b configure -state $st
		}
	    }
	}
    }
    return
}

proc ClearList {wh} {
    # forget all items in a list; $wh in $TYPES
    global ListInds List EdWindow GM${wh}Index MESS TXT

    if { "$ListInds($wh)" != "" && \
	 [GMConfirm [format $MESS(forgetall) $TXT(name$wh)]] } {
            foreach i $ListInds($wh) {
		if { [winfo exists $EdWindow($wh)] && \
			[set GM${wh}Index]==$i } {
		    GMMessage [format $MESS(cantfgted) $TXT(name$wh)]
		} else { Forget $wh $i }
	    }
	    if { "$ListInds($wh)" == "" } {
		ChangeOnStateList $wh disabled
	    }
    }
    return
}

proc Count {wh} {
    # count items in list; $wh in $TYPES
    global Number MESS TXT

    GMMessage [format $MESS(counted) $Number($wh) $TXT(name$wh)]
    return
}

proc OpenListItem {wh} {
    # edit or display selected item in a list; $wh in $TYPES
    global LsW ListInds

    set s [$LsW.frl$wh.frl.box curselection]
    if { "$s" != "" } {
	OpenItem $wh [lindex $ListInds($wh) $s]
    }
    return
}

proc ToggleDisplayItem {wh sel} {
    # un-/display on map selected item in a list
    #  $wh in $TYPES; $sel is selection index in list
    global ListInds EdWindow GM${wh}Index ${wh}Displ Number

    if { $Number($wh)>0 && "$sel" != "" } {
	set index [lindex $ListInds($wh) $sel]
	set w $EdWindow($wh)
	if { [winfo exists $w] && [set GM${wh}Index]==$index } {
	    Raise $w ; bell
	    return
	}
	if { [set [set wh]Displ($index)] } {
	    UnMap $wh $index
	} else { PutMap $wh $index }
    }
    return
}

proc ToggleDisplayNamed {wh name} {
    # un-/display on map item with given name
    #  $wh in $TYPES
    global EdWindow GM${wh}Index ${wh}Displ

    if { [set index [IndexNamed $wh $name]] == -1 } { return }
    set w $EdWindow($wh)
    if { [winfo exists $w] && [set GM${wh}Index]==$index } {
	Raise $w ; bell
    } elseif { [set [set wh]Displ($index)] } {
	UnMap $wh $index
    } else { PutMap $wh $index }
    return
}

proc ListAdd {wh index} {
    # add new item with given index to non-empty list; $wh in $TYPES
    global LsW ListInds Storage

    set ids [lindex $Storage($wh) 0]
    global $ids
    set name [set [set ids]($index)]
    if { "$ListInds($wh)" == "" } {
	set ListInds($wh) $index
	$LsW.frl$wh.frl.box insert end $name
	ChangeOnStateList $wh normal
    } else {
	set a 0 ; set b [expr [$LsW.frl$wh.frl.box size]-1]
	while 1 {
	    set i [expr int(floor(($a+$b)/2))]
	    if { [string compare $name [$LsW.frl$wh.frl.box get $i]] < 0 } {
		set b $i
	    } else { set a $i }
	    if { $b == $a } {
                if { [string compare $name \
			[$LsW.frl$wh.frl.box get $a]] > 0 } {
		    incr a
		}
		$LsW.frl$wh.frl.box insert $a $name
		set ListInds($wh) [linsert $ListInds($wh) $a $index]
		break
            } elseif { $b == $a+1 } {
		if { [string compare $name \
			[$LsW.frl$wh.frl.box get $a]] > 0 } {
		    incr a
		    if { [string compare $name \
			    [$LsW.frl$wh.frl.box get $a]] > 0 } {
			incr a
		    }
		}
		$LsW.frl$wh.frl.box insert $a $name
		set ListInds($wh) [linsert $ListInds($wh) $a $index]
		break
	    }
	}
    }
    return
}

proc ListDelete {wh index} {
    # delete item with given index from list; $wh in $TYPES
    global LsW ListInds

    set n [lsearch -exact $ListInds($wh) $index ]
    $LsW.frl$wh.frl.box delete $n
    set ListInds($wh) [lreplace $ListInds($wh) $n $n]
    if { [$LsW.frl$wh.frl.box size] == 0 } {
	ChangeOnStateList $wh disabled
    }
    return
}

proc FillItemsMenu {menu act whit whchg} {
    # create and fill $menu with items from list
    #  $act is use as argument to the call-back
    #  $whit in $TYPES identifies the list
    #  $whchg either in $TYPES being the type of item that will be modified,
    #   or matches Search* when proc is used in the search dialog
    # menus will have continuation sub-menus to keep size <= $MAXMENUITEMS
    # the callback for each item $it in the menus is
    #  GM${whchg}Change $act $it
    global LsW MAXMENUITEMS TXT

    if { [winfo exists $menu] } {
	$menu delete 0 end
    } else { menu $menu -tearoff 0 }
    set n 0 ; set m 0
    foreach it [$LsW.frl$whit.frl.box get 0 end] {
	if { $n > $MAXMENUITEMS } {
	    $menu add cascade -label "$TXT(more) ..." -menu $menu.m$m
	    set menu $menu.m$m ; destroy $menu ; menu $menu  -tearoff 0
	    set n 0 ; incr m
	}
	$menu add command -label $it -command [list GM${whchg}Change $act $it]
	incr n
    }
    return
}

proc ChooseItems {wh} {
    # create modal dialog for selecting from list of items
    #  $wh in $TYPES
    global NAMEWIDTH Storage ListInds TXT

    set ids [lindex $Storage($wh) 0]
    global $ids
    set ns ""
    foreach i $ListInds($wh) { lappend ns [set [set ids]($i)] }
    return [GMChooseFrom many [list $TXT(select) $TXT(name$wh)] \
	             $NAMEWIDTH $ns $ListInds($wh)]
}

proc InputToGR {whs notwhs preproc proc postproc fmt} {
    # input data according to contents of group(s)
    # items of types in $whs (except those in $notwhs) will be read in
    #  $preproc will be called immediately before input is really required
    #     and should return 0 unless operation is to be cancelled;
    #     arguments: GR and $fmt; proc Ignore can be used if nothing is to
    #     be done
    #  $proc is the input procedure, whose arguments will be:
    #     type of item to input, list of indices and $fmt if not "receiver"
    #  $postproc will be called after the last call to $proc; single
    #     argument: GR; proc Ignore can be used if nothing is to be done
    #  $fmt in {GPSMan, GPStrans, receiver} is the format for input
    global MESS TXT GCHow ListInds Storage

    set gts "" ; set ts ""
    foreach t $whs {
	if { [lsearch -exact $notwhs $t] == -1 } {
	    lappend gts $t ; lappend ts $TXT(name$t)
	}
    }
    set vals [list $TXT(notinGR) $TXT(onlyinGR)]
    set import [string compare $fmt GPSMan]
    while {1} {
	set whs [GMChooseFrom many $MESS(readwhat) 6 $ts $gts \
		    GCHow [list $vals]]
	set compl [string compare $GCHow $TXT(onlyinGR)]
	if { [set i [lsearch -exact $whs GR]] != -1 } {
	    set whs [lreplace $whs $i $i]
	    set rec 1
	} else { set rec 0 }
    	if { $import && [llength $whs] > 1 } {
	    GMMessage $MESS(importonly1)
	} else { break }
    }
    if { "$whs" == "" || "[set ixs [ChooseItems GR]]" == "" } { return }
    if { [$preproc GR $fmt] } { return }
    foreach wh $whs {
	if { "[set l [GRsElements $ixs $rec $wh]]" != "" } {
	    if { $compl } {
		set ids [lindex $Storage($wh) 0]
		global $ids
		set l [linsert [Complement [array names $ids] $l] 0 -1]
	    }
	    if { $fmt != "receiver" } {
		$proc $wh $l $fmt
	    } else {
		$proc $wh $l
	    }
	}
    }
    $postproc GR
    return
}


