#
#  gpsman --- GPS Manager: a manager for GPS receiver data
#
#  Copyright (c) 2002 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: check.tcl
#  Last change:  4 February 2002
#

proc CheckName {errproc name} {
    # check length and characters of name; call $errproc on error
    global NAMELENGTH NOLOWERCASE MYGPS RECNAMECHARS MESS

    set n [string length $name]
    if { $n > $NAMELENGTH } {
	$errproc [format $MESS(namelgth) $NAMELENGTH]
	return 0
    }
    if { $n == 0 } {
	$errproc $MESS(namevoid)
	return 0
    }
    if { ! $NOLOWERCASE } {
	set name [string toupper $name]
    }
    if { [regexp $RECNAMECHARS($MYGPS) $name] } {
	return 1
    }
    $errproc $MESS(badstrg)
    return 0
}

proc CheckDateEls {y m d h mn s} {
    # check year, month, day, hour, minutes, seconds
    global YEAR0 DAYSOF

    if { $y<$YEAR0 || $m<1 || $m>12 || $d<1 || $d>$DAYSOF($m) || \
	    $h<0 || $h>23 || $mn<0 || $mn>59 || $s<0 || $s>59 } {
	return 0
    }
    return 1
}

proc CheckDate {errproc date} {
    global CREATIONDATE
                             # STOP-GAP
    if { ! $CREATIONDATE } { return 1 }
    return 1
}

proc CheckConvDate {string} {
    # convert string to date
    global DateFormat MESS

    set l [split $string -] ; set n [llength $l]
    if { $n > 1 } {
	# there are "-"s
	if { $n == 3 } {
	    set d [string trimleft [lindex $l 0] 0] ; set s 0
	    if { [set m [Month [lindex $l 1]]] } {
		set n [scan [lindex $l 2] "%d %d:%d:%d" y h mn s]
		if { $n>2 && [CheckDateEls $y $m $d $h $mn $s] } {
		    return [list [FormatDate $DateFormat $y $m $d $h $mn $s] \
			         [DateToSecs $y $m $d $h $mn $s]]
		}
	    }
	}
    } else {
	set l [split $string /] ; set n [llength $l]
	if { $n > 1 } {
	    # there are "/"s
	    if { $n == 3 } {
		set m [string trimleft [lindex $l 0] 0] ; set s 0
		set d [string trimleft [lindex $l 1] 0]
		set n [scan [lindex $l 2] "%d %d:%d:%d" y h mn s]
		if { $n>2 && [CheckDateEls $y $m $d $h $mn $s] } {
		    return [list [FormatDate $DateFormat $y $m $d $h $mn $s] \
			         [DateToSecs $y $m $d $h $mn $s]]
		}
	    }
	} else {
	    # neither "-"s nor "/"s
	    set l [split $string .] ; set n [llength $l]
	    if { $n > 1 } {
		if { $n == 3 } {
		    set y [string trimleft [lindex $l 0] 0] ; set s 0
		    set m [string trimleft [lindex $l 1] 0]
		    set n [scan [lindex $l 2] "%d %d:%d:%d" d h mn s]
		    if { $n>2 && [CheckDateEls $y $m $d $h $mn $s] } {
			return [list [FormatDate $DateFormat $y $m $d \
				                 $h $mn $s] \
			             [DateToSecs $y $m $d $h $mn $s]]
		    }
		}
	    }
	}
    }
    GMMessage "$MESS(baddate): $string"
    return ""
}

proc CheckLat {errproc lat pformt} {
                                   # positive latitudes to North
    return [CheckCoord $errproc $pformt "$lat" N 90]
}

proc CheckLong {errproc long pformt} {
                                   # positive longitudes to East
    return [CheckCoord $errproc $pformt "$long" E 360]
}

proc CheckCoord {errproc pformt coord posh max} {
    # check coordinate $coord under format $pformt, with positive heading $posh
    #  and maximum value $max; call $errproc on error
    global MESS TXT

    set coord [string trim $coord]
    set h [string index "$coord" 0]
    if { ! [regexp {[0-9]} $h] } {
	if { ! [regexp {[+-]} $h] && "$h" != "$posh" && \
		"$h" != "[ChangeCoordSign $posh]" } {
	    $errproc [format $MESS(badhdg) $h $posh/[ChangeCoordSign $posh]]
	    return 0
	}
	set coord [string range "$coord" 1 end]
    }
    switch $pformt {
	DMS {
	    if { [scan "$coord" "%d %d %f%s" d m s err] == 3 } {
		if { ($d<$max && $m<60 & $s<60) || \
			($d==$max && $m==0 && $s==0) } { return 1 }
	    }
	}
	DMM {
	    if { [scan "$coord" "%d %f%s" d m err] == 2 } {
		if { ($d<$max && $m<60) || ($d==$max && $m==0) } {
		    return 1
		}
	    }
	}
	DDD {
	    if { [scan "$coord" "%f%s" d err] == 1 } {
		if { $d <= $max } { return 1 }
	    }
	}
    }
    $errproc [format $MESS(badcoord) $coord $TXT($pformt)]
    return 0
}

proc CheckZE {errproc ze} {
    # check zone east of UTM coordinate; call $errproc on error
    global MESS

    if { [CheckNumber $errproc $ze] } {
	if { $ze<0 || $ze>99 } {
	    $errproc "$MESS(outofrng) \[0..99\]"
	} else { return 1 }
    }
    return 0
}

proc CheckZN {errproc zn} {
    # check zone north of UTM coordinate; call $errproc on error
    global MESS

    if { [regexp {^[A-Z]$} $zn] && "$zn" != "I" && "$zn" != "O" } { return 1 }
    $errproc $MESS(UTMZN)
    return 0
}

proc CheckZone {errproc zone pformt} {
    # check zone for the grid $pformt; call $errproc on error
    global MESS GRIDZN

    if { [regexp $GRIDZN($pformt) $zone] } { return 1 }
    $errproc $MESS(badgridzone)
    return 0
}

proc CheckMHLocator {errproc mh} {
    global MESS

    if { [regexp {^[A-R][A-R][0-9][0-9][A-X][A-X]$} $mh] } { return 1 }
    $errproc $MESS(badMHloc)
    return 0
}

proc CheckComment {errproc comm} {
    # check length and characters of comment; call $errproc on error
    global COMMENTLENGTH MESS

    if { [string length $comm] > $COMMENTLENGTH } {
	$errproc [format $MESS(cmmtlgth) $COMMENTLENGTH]
	return 0
    }
    return [CheckChars $errproc $comm]
}

proc CheckChars {errproc string} {
    # check characters in comment string; call $errproc on error
    global NOLOWERCASE MESS

    if { ! $NOLOWERCASE || [regexp {^[-A-Z0-9 -]*$} $string] } {
	return 1
    }
    $errproc $MESS(badstrg)
    return 0
}

proc CheckString {errproc string} {
    # check that string is not void; call $errproc on error
    global MESS

    if { [string length "$string"] == 0 } {
	$errproc $MESS(strgvoid)
	return 0
    }
    return 1
}

proc CheckNumber {errproc n} {
    # check that $n is a natural number; may be preceded/followed by spaces;
    # call $errproc on error
    global MESS

    if { [regexp {^ *[0-9]+ *$} $n] } { return 1 }
    $errproc [format $MESS(nan) $n]
    return 0
}

proc CheckFloat {errproc n} {
    # check that $n is floating-point number (not in exponential notation),
    #  that may be preceded/followed by spaces; scientific notation accepted
    # call $errproc on error
    global MESS

    if { [regexp {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $n] } {
	return 1
    }
    $errproc [format $MESS(nan) $n]
    return 0
}

proc CheckSignedFloat {errproc n} {
    # check that $n is a floating-point number, that may have a minus sign
    #  and be preceded/followed by spaces; scientific notation accepted
    # call $errproc on error
    global MESS

    if { [regexp {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $n] } {
	return 1
    }
    $errproc [format $MESS(nan) $n]
    return 0
}

proc CheckNB {text} {
    # delete empty lines and leading blanks from text

    while { [regsub -all "\n\n+" $text "\n" text] } {}
    return [string trim $text " \t\n"]
}

proc Ignore {args} {
    # to be used as error/checking procedure when ignoring errors

    return 0
}

proc CheckArrayElement {array val} {
    # check that $val is an element of $array
    # return 1 on success, 0 on error
    global $array

    foreach an [array names $array] {
	if { "[set [set array]($an)]" == "$val" } { return 1 }
    }
    return 0
}

proc BadAltitude {a} {
    # check value for altitude; used also for depth

    if { [CheckSignedFloat Ignore $a] || "$a" == "" } { return 0 }
    return 1
}

proc BadParam {name type value} {
    # check $value for numeric parameter of definition $name
    #  $type as used in MAPPROJDTYPE array (projections.tcl)
    #  $name is used only in the error message
    global MESS

    if { [regexp {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $value] } {
	switch -glob $type {
	    lat=*,* {
		regexp {lat=([^,]+),(.*)} $type z mn mx
		set e [expr $value<$mn || $value>$mx]
	    }
	    long=*,* {
		regexp {long=([^,]+),(.*)} $type z mn mx
		set e [expr $value<$mn || $value>$mx]
	    }
	    lat {
		set e [expr $value<-90 || $value>90]
	    }
	    long {
		set e [expr $value<-180 || $value>180]
	    }
	    float>* {
		regsub float> $type "" mn
		set e [expr $value<$mn]
	    }
	    list=* {
		regsub list= $type "" l
		set e 1
		foreach v [split $l ,] {
		    if { $value == $v } { set e 0 ; break }
		}
	    }
	    float {
		set e 0
	    }
	}
    } else { set e 1 }
    if { $e } {
	GMMessage [format $MESS(badparam) $name]
	return 1
    }
    return 0
}
