#
#  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: know.tcl
#  Last change:  25 October 2001
#
# Includes contributions by Brian Baulch (baulchb@onthenet.com.au)
#  marked "BSB contribution"
#

proc NewItem {wh} {
    # open window for defining a new item
    #  $wh in $TYPES
    global CREATIONDATE Proc DataDefault

    set opts {create revert cancel}
    switch $wh {
	WP  {
	    if { $CREATIONDATE } {
		GMWPoint -1 $opts [FormData WP Date [list [Now]]]
	    } else {
		GMWPoint -1 $opts [FormData WP Commt [list [DateCommt [Now]]]]
	    }
	}
	default {
	    $Proc($wh) -1 $opts $DataDefault($wh)
	}
    }
    return
}

proc CreateItem {wh data} {
    # create a new item of given type and with given data
    # return index of new item
    global Index Number WPRoute

    set ix $Index($wh)
    incr Index($wh) ; incr Number($wh) ; incr Number(Data)
    SetItem $wh $ix $data ; ListAdd $wh $ix
    if { $Number(Data) == 1 } { ChangeOnStateData normal }
    if { "$wh" == "WP" } { set WPRoute($ix) "" }
    return $ix
}

proc ItemData {wh index} {
    # find data for item with given index
    #  $wh in $TYPES
    # return list of values in the order given by $Storage($wh)
    # see GMStart (main.tcl) for the description of data arrays
    global Storage

    set l ""
    foreach s $Storage($wh) {
	global $s

	set l [lappend l "[set [set s]($index)]"]
    }
    return $l
}

proc FormData {wh names vals} {
    # create a data list for an item of type $wh (in $TYPES, or TP)
    #  $names is a list of data array names without the prefix $wh
    #  $vals is a list of values aligned with $names
    # return list of values in the order given by $DataIndex($wh)
    #  (if $wh in $TYPES that is the order of $Storage($wh)) using
    #  default values for those not given in $vals
    # see GMStart (main.tcl) for the description of data arrays
    global DataDefault DataIndex

    set l $DataDefault($wh)
    foreach n $names v $vals {
	set i $DataIndex(${wh}$n)
	set l [lreplace $l $i $i $v]
    }
    return $l
}

proc SetItem {wh index data} {
    # set data for item with given index
    #  $wh in $TYPES
    # see GMStart (main.tcl) for description of data arrays
    global Storage IndexOf

    set ids [lindex $Storage($wh) 0]
    global $ids

    set name [lindex $data 0]
    if { ! [catch {set oldname [set [set ids]($index)]}] && \
	    "$oldname" != "$name" } {
	unset IndexOf($wh,$oldname)
    }
    set IndexOf($wh,$name) $index
    foreach val $data field $Storage($wh) {
	global $field

	set [set field]($index) $val
    }
    return
}

proc UnsetItem {wh index} {
    # destroy data for item with given index
    #  $wh in $TYPES
    # see GMStart (main.tcl) for description of data arrays
    global Storage IndexOf

    set ids [lindex $Storage($wh) 0]
    global $ids

    unset IndexOf($wh,[set [set ids]($index)])
    foreach field $Storage($wh) {
	global $field

	unset [set field]($index)
    }
    return
}

proc Forget {wh ix} {
    # forget an item with given index; $wh in $TYPES
    global ${wh}Displ RTIdNumber RTWPoints Number MESS TXT
    # BSB contribution
    global MYGPS WPName WPNum UnusedICInx UnusedWPInx

    if { [set ${wh}Displ($ix)] && ![UnMap $wh $ix] && "$wh" != "GR" } {
	GMMessage [format $MESS(cantfgt) $TXT(name$wh)]
	return 0
    }
    switch $wh {
	WP {
	    # BSB contribution
	    if { "$MYGPS" == "Lowrance" } {
		if { [string match "ICON*" $WPName($ix)] } {
		    lappend UnusedICInx $WPNum($ix)
		} else {
		    lappend UnusedWPInx $WPNum($ix)
		}
	    }
	}
	RT {
	    UnsetWPRoute $RTIdNumber($ix) $RTWPoints($ix)
	}
    }
    ListDelete $wh $ix ; UnsetItem $wh $ix
    incr Number($wh) -1 ; incr Number(Data) -1
    if { $Number(Data) == 0 } { ChangeOnStateData disabled }
    return 1
}

proc IndexNamed {wh name} {
    # find index for item with given name; $wh in $TYPES
    global IndexOf

    if { [catch {set ix $IndexOf($wh,$name)}] } {
	return -1
    }
    return $ix
}

proc NameOf {wh ix} {
    # return name of item with given index; $wh in $TYPES
    global Storage

    set ids [lindex $Storage($wh) 0]
    global $ids
    return [set [set ids]($ix)]
}

proc NewName {wh} {
    # return a unique new name for an item of type $wh in $TYPES
    # numbers from 100 are used

    set n 100
    while { [IndexNamed $wh $n] != -1 } { incr n }
    return $n
}

proc SetWPRoute {rt wps} {
    # insert (in order) RT name $rt in list of RTs of each known WP
    #  whose name belongs to $wps
    global WPRoute

    foreach wp "$wps" {
	if { [set ix [IndexNamed WP $wp]] != -1 } {
	    if { [lsearch -exact $WPRoute($ix) $rt] == -1 } {
		set WPRoute($ix) [linsert $WPRoute($ix) 0 $rt]
		set WPRoute($ix) [lsort $WPRoute($ix)]
	    }
	}
    }
    return
}

proc UnsetWPRoute {rt wps} {
    # delete RT name $rt in list of RTs of each known WP
    #  whose name belongs to $wps
    global WPRoute

    foreach wp "$wps" {
	set ix [IndexNamed WP $wp]
	if { $ix != -1 } {
	    set wi [lsearch -exact $WPRoute($ix) $rt]
	    if { $wi != -1 } {
		set WPRoute($ix) [lreplace $WPRoute($ix) $wi $wi]
	    }
	}
    }
    return
}

proc DateCommt {date} {
    # create comment from date
    global COMMENTLENGTH NOLOWERCASE

    regsub -all {:|\.} "$date" "" date
    if { [string length "$date"] > $COMMENTLENGTH } {
	set date [string range "$date" 0 [expr $COMMENTLENGTH-1]]
    }
    if { $NOLOWERCASE } {
	return [string toupper "$date"]
    }
    return "$date"
}

## operations on groups

proc GRsElements {ixs rec wh} {
    # find elements of type $wh (in $TYPES) in groups with
    #  given indices; if $wh==GR the initial GRs are included in the result;
    #  undefined elements are not included
    #  $rec is 1 if search is recursive
    # return list of indices
    global GMember

    catch "unset GMember"
    if { "$wh" == "GR" } {
	foreach ix $ixs { set GMember($ix) 1 }
    }
    GRsElsCollect $ixs $rec $wh
    set l [array names GMember]
    catch "unset GMember"
    return $l
}

proc GRsElsCollect {ixs rec wh} {
    # mark defined elements of type $wh (in $TYPES) in groups with
    #  given indices
    #  $rec is 1 if search is recursive
    # marked elements with index $i will have GMember($i) set
    global GRConts GMember

    foreach ix $ixs {
	foreach p $GRConts($ix) {
	    if { "[lindex $p 0]" == "$wh" } {
		foreach e [lindex $p 1] {
		    if { [set eix [IndexNamed $wh $e]] != -1 } {
			set GMember($eix) 1
		    }
		}
		if { ! $rec } { break }
	    }
	    if { $rec && "[lindex $p 0]" == "GR" } {
		set rixs [Apply [lindex $p 1] IndexNamed GR]
		while { [set i [lsearch -exact $rixs -1]] != -1 } {
		    set rixs [lreplace $rixs $i $i]
		}
		GRsElsCollect $rixs 1 $wh
	    }
	}
    }
    return
}

## storing data items just read in

proc SamePosn {ix data} {
    # check whether WP with given index has the same position as the
    #  WP with given data even if the datums used are different
    global WPPosn WPDatum DataIndex

    set ip $DataIndex(WPPosn)
    set id $DataIndex(WPDatum)
    set p [lindex $data $ip] ; set d [lindex $data $id]
    if { "$WPDatum($ix)" != "$d" } {
	set p [ConvertDatum [lindex $p 0] [lindex $p 1] $d $WPDatum($ix) DDD]
    }
    return [expr [lindex $p 0]==[lindex $WPPosn($ix) 0] && \
	         [lindex $p 1]==[lindex $WPPosn($ix) 1]]
}

proc AddToNB {nb txt} {
    # add $txt to remark $nb

    if { "$nb" != "" } {
	set i "$nb\n"
    } else { set i "" }
    return "${i}$txt"
}

proc StoreWP {ix name data todispl} {
    # store WP data just read in
    #  $todispl is true if the WP should be mapped
    global WPRoute WPDispl EQNAMEDATA TXT DataIndex

    if { $ix != -1 } {
	if { "$EQNAMEDATA" == "ovwrt" || [SamePosn $ix $data] } {
	    set olddispl $WPDispl($ix)
	    SetItem WP $ix $data
	    if { $todispl || $olddispl } {
		set WPDispl($ix) 1
		MoveOnMap WP $ix $name 0 $name
	    }
	    UpdateItemWindows WP $ix
	    return
	}
	set data [lreplace $data 0 0 [NewName WP]]
	set in $DataIndex(WPObs)
	set nb [lindex $data $in]
	set data [lreplace $data $in $in [AddToNB $nb "$TXT(oname): $name"]]
    }
    set ix [CreateItem WP $data]
    if { $todispl } { PutMap WP $ix }
    return
}

proc StoreRT {ix id data wps todispl} {
    # store RT data just read in
    #  $todispl is true if the RT should be mapped
    global RTWPoints RTDispl EQNAMEDATA TXT DataIndex

    if { $ix != -1 } {
	if { "$EQNAMEDATA" == "ovwrt" } {
	    if { $RTDispl($ix) } {
		UnMapRT $ix
		set todispl 1
	    }
	    UnsetWPRoute $id $RTWPoints($ix)
	    SetItem RT $ix $data
	    set RTDispl($ix) $todispl
	    UpdateItemWindows RT $ix
	} else {
	    set in $DataIndex(RTObs)
	    set nb [lindex $data $in]
	    set data [lreplace $data $in $in [AddToNB $nb "$TXT(oname): $id"]]
	    set ix [CreateItem RT [lreplace $data 0 0 [NewName RT]]]
	}
    } else {
	set ix [CreateItem RT $data]
    }
    if { $todispl } { PutMap RT $ix }
    SetWPRoute $id $wps
    return
}

proc StoreTR {ix id data todispl} {
    # store TR data just read in
    #  $todispl is true if the TR should be mapped
    global TRDispl EQNAMEDATA TXT DataIndex

    if { $ix != -1 } {
	if { "$EQNAMEDATA" == "ovwrt" } {
	    if { $TRDispl($ix) } {
		UnMapTR $ix
		set todispl 1
	    }
	    SetItem TR $ix $data
	    set TRDispl($ix) $todispl
	    UpdateItemWindows TR $ix
	} else {
	    set in $DataIndex(TRObs)
	    set nb [lindex $data $in]
	    set data [lreplace $data $in $in [AddToNB $nb "$TXT(oname): $id"]]
	    set ix [CreateItem TR [lreplace $data 0 0 [NewName TR]]]
	}
    } else {
	set ix [CreateItem TR $data]
    }
    if { $todispl } { PutMap TR $ix }
    return
}

proc StoreGR {ix id data todispl} {
    # store GR data just read in
    #  $todispl is true if the GR should be mapped
    global GRDispl EQNAMEDATA TXT DataIndex

    if { $ix != -1 } {
	if { "$EQNAMEDATA" == "ovwrt" } {
	    if { $GRDispl($ix) } {
		UnMapGR $ix
		set todispl 1
	    }
	    SetItem GR $ix $data
	    set GRDispl($ix) $todispl
	    UpdateItemWindows GR $ix
	} else {
	    set in $DataIndex(GRObs)
	    set nb [lindex $data $in]
	    set data [lreplace $data $in $in [AddToNB $nb "$TXT(oname): $id"]]
	    set ix [CreateItem GR [lreplace $data 0 0 [NewName GR]]]
	}
    } else {
	set ix [CreateItem GR $data]
    }
    if { $todispl } { PutMap GR $ix }
    return
}

