#
#  gpsman --- GPS Manager: a manager for GPS receiver data
#
#  Copyright (c) 1998-2008 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: command.tcl
#  Last change:  25 September 2008
#

# this file is only source-ed in command-line mode (even if the graphical
#  interface is launched to obey the command)

### change some initial values if needs be

if { $COMMAND(rec) } {
    # use an "accept anything from receiver" setting
    RecCanSendAnything $MYGPS
}

if { $COMMAND(log) } {
    set NotLogging 0
}

##### executing command

proc ExecCommand {} {
    # execute command from command line
    # return 0 on success, 1 on error, "wait" to loop, "-0" to quit fast
    global COMMAND CMDLINE NoImgLib GSHPVersion RealTimeLogAnim PVTState \
	 PVTDumping RealTimeGettingFix MESS GPSProtocol

    if { [set prot $COMMAND(prot)] != "" } {
	set GPSProtocol $prot
    }
    switch $COMMAND(name) {
	checkconn {
	    # "is connected" command
	    return [ExecGPSConnectFail]
	}
	show {
	    CmdShow $COMMAND(what)
	    return "-0"
	}
	haslib {
	    switch $COMMAND(what) {
		gpsmanshp {
		    if { $GSHPVersion == "" } { return 1 }
		}
		Img {
		    if { $NoImgLib } { return 1 }
		}
		default { return 1 }
	    }
	}
	getwrite {
	    if { [CmdGetFails $COMMAND(rectypes)] || \
		    [CmdWriteFails $COMMAND(format) $COMMAND(path) \
			 $COMMAND(out,params) $COMMAND(filetypes)] } {
		return 1
	    }
	}
	readput {
	    if { [CmdReadFails $COMMAND(format) $COMMAND(path) \
		               $COMMAND(in,params) $COMMAND(filetypes)] || \
		    [CmdPutFails $COMMAND(rectypes)] } {
		return 1
	    }
	}
	translate {
	    CmdSetTranslateParams $COMMAND(params)
	    if { [CmdReadFails $COMMAND(infmt) $COMMAND(inpath) \
		               $COMMAND(in,params) $COMMAND(intypes)] || \
		    [CmdWriteFails $COMMAND(format) $COMMAND(path) \
			          $COMMAND(out,params) $COMMAND(filetypes)] } {
		return 1
	    }
	    CmdRestoreTranslation
	}
	getrtimelog {
	    if { [CmdCantStartRTimeLog Ignore Ignore] || \
		     [CmdRTimeDumpFails $COMMAND(path)] } { return 1 }
	    # force calls to SavePVTData $PVTDFile
	    set PVTDumping 1
	    set PVTState on
	    return wait
	}
	getfix {
	    # interval for real-time log
	    set COMMAND(interv) 2
	    if { [CmdCantStartRTimeLog Ignore Ignore] || \
		     [CmdRTimeDumpFails $COMMAND(path)] } { return 1 }
	    set RealTimeGettingFix 1
	    trace variable RealTimeGettingFix w CmdRTimeGotFix
	    if { $COMMAND(timeout) != 0 } {
		after [expr $COMMAND(timeout)*1000] \
		    { set RealTimeGettingFix -1 }
	    }
	    # avoid calls to SavePVTData $PVTDFile
	    set PVTDumping 0
	    set PVTState on
	    return wait
	}
	getalmanac {
	    if { [CmdGetAlmanacFails $COMMAND(path)] } { return 1 }
	}
	starttravel {
	    # enter graphical mode
	    set CMDLINE 0
	    GMInit
	    if { ! [CmdCantStartRTimeLog EnableGPS \
			[list GMMessage $MESS(receiver)]] } {
		set RealTimeLogAnim 1
		ToTravel
	    }
	    return wait
	}
	project {
	    if { [CmdBadProjArgs] || [CmdBadProjSetup] } { return 1 }
	    set proj $COMMAND(proj)
	    foreach "x y" [Proj${proj}Point MPData \
		    $COMMAND(latd) $COMMAND(longd) $COMMAND(ptsdatum)] {}
	    puts "$x\t$y"
	    return "-0"
	}
	georef {
	    if { [CmdBadGeoRefArgs] || [CmdBadGeoRefSetup] } { return 1 }
	    CmdGenerateGeoRef
	    return "-0"
	}
	geopicts {
	    global Number Datum SYMBOLS DEFAULTSYMBOL
	    set type $COMMAND(intypes)
	    if { [CmdReadFails $COMMAND(infmt) $COMMAND(inpath) \
		      $COMMAND(in,params) $type] || $Number($type) == 0 } {
		return 1
	    }
	    set fmt $COMMAND(format)
	    set ix [expr $Number($type)-1]
	    set mdate pict ; set dhour 0
	    if { $fmt == "GPX" } {
		set datum "WGS 84"
	    } else { set datum $Datum }
	    set sy scenic
	    set prefix P
	    foreach "lhs rhs" $COMMAND(params) {
		switch $lhs {
		    id {
			if { [set ix [IndexNamed $type $rhs]] == -1 } {
			    GMMessage "$MESS(notlisted): $rhs"
			    return 1
			}
		    }
		    date {
			set mdate $rhs
		    }
		    dh {
			set dhour $rhs
		    }
		    datum {
			if { [EllipsdOf $rhs] == "" } {
			    GMMessage "$MESS(unkndatum): $rhs"
			    return 1
			}
			if { $fmt != "GPX" } { set datum $rhs }
		    }
		    sy {
			if { [lsearch -exact $SYMBOLS $rhs] == -1 } {
			    GMMessage "$MESS(badSYMBOLcode): $rhs"
			    return 1
			}
			set sy $rhs
		    }
		    prefix {
			set prefix $rhs
		    }
		    __picts {
			set pcs $rhs
		    }
		}
	    }
	    if { [set lts [GetFilesDates $pcs $mdate $dhour]] == "" || \
		     [set lts [GeoAdapt $type $ix $datum $lts]] == "" } {
		GMMessage $MESS(missingdata)
		return 1
	    }
	    if { [CmdProcParamsFails $fmt $COMMAND(out,params)] || \
		     [CmdGPictsOutputFails $fmt $COMMAND(path) \
			  $lts $datum $sy $prefix] } {
		return 1
	    }
	}
	source {
	    # file is assumed to be in system encoding
	    if { [catch {source $COMMAND(path)}] } { return 1 }
	    return wait
	}
	read {
    	    if { ! $COMMAND(script) } {
		# enter graphical mode
		set CMDLINE 0
		GMInit
		if { [CmdReadFails $COMMAND(format) $COMMAND(path) \
			  $COMMAND(in,params) $COMMAND(filetypes)] } {
		    GMMessage "$MESS(badfile): $COMMAND(path)"
		}
		return wait
	    }
	    return [CmdReadFails $COMMAND(format) $COMMAND(path) \
			$COMMAND(in,params) $COMMAND(filetypes)]
	}
	exec {
	    if { [catch {set f [open $COMMAND(path) r]}] } { return 1 }
	    set COMMAND(script) 1
	    return [CmdInterpret $f]
	}
	write {
	    return [CmdWriteFails $COMMAND(format) $COMMAND(path) \
		                  $COMMAND(out,params) $COMMAND(filetypes)]
	}
	get {
	    return [CmdGetFails $COMMAND(rectypes)]
	}
	put {
	    return [CmdPutFails $COMMAND(rectypes)]
	}
    }
    return 0
}

proc CmdProcessLine {line} {
    # split $line into command name and arguments taking care of quotes
    # return list similar to argv or ERROR on error

    set line [string trim $line]
    regsub -all "\t" $line " " line
    while { [regsub -all "  " $line " " line] } { continue }
    set l ""
    while { [string first "\"" $line] != -1 } {
	if { ! [regexp {^([^"]*)"([^"]*)"(.*)$} $line m pre in rest] } {
	    return ERROR
	}
	if { $pre != "" } {
	    set l [concat $l [split [string trim $pre] " "]]
	}
	lappend l $in
	set line [string trim $rest]
    }
    if { $line != "" } { set l [concat $l [split $line " "]] }
    return $l
}

proc CmdInterpret {file} {
    # interpret commands from $file
    # return 1 on error, 0 on success
    global argv

    set prev ""
    while { ! [eof $file] } {
	gets $file line
	set line [string trim $line " \t"]
	# discards comment lines whose first non-blank is "#"
	if { $line == "" || [regexp {^#} $line] } { continue }
	# check continuation line indicator (backslash as last char)
	#  if there is a unmatched quote this will cause error!
	if { [string index $line end] == "\\" } {
	    set prev "$prev$line "
	    continue
	}
	set line [string trim "$prev$line" " \t"]
	set argv [CmdProcessLine $line]
	if { [BadCommandLine] } {
	    puts stderr "bad command: $line"
	    return 1
	}
	if { [ExecCommand] == 1 } {
	    puts stderr "command failed: $line"
	    return 1
	}
	set prev ""
    }
    # continuation line not found
    if { $prev != "" } { return 1 }
    return 0
}

proc ExecGPSConnectFail {args} {
    #  $args is list with 1st and 2nd argument to proc GPSConnection
    # return 1 on error, 0 on success
    global GPSOpResult

    if { $args == "" } {
       if { [GPSConnection Ignore Ignore] == 0 } { return 1 }
    } elseif { [GPSConnection [lindex $args 0] [lindex $args 1]] == 0 } {
	return 1
    }
    vwait GPSOpResult
    return $GPSOpResult
}

proc CmdCantStartRTimeLog {connproc errorproc} {
    # return 0 on success, 1 on error
    global COMMAND GPSProtocol

    # this depends on the Garmin variant...
    if { [string first "garmin" $GPSProtocol] == 0 && \
	     [ExecGPSConnectFail $connproc $errorproc] } { return 1 }
    if { ! [StartRealTimeLog $COMMAND(interv)] } { return 1 }
    return 0
}

proc CmdGetFails {types} {
    # get items of given $types
    # return 0 on success
    global GPSOpResult

    if { [ExecGPSConnectFail] } { return 1 }
    foreach t $types {
	GetGPS $t
	vwait GPSOpResult
	if { $GPSOpResult } { return 1 }
    }
    return 0
}

proc CmdGetAlmanacFails {path} {
    # get almanac and print it to file
    # return 0 on success
    global ALDataTxt

    if { [CmdGetFails AL] || [set f [CmdOpenFile $path out]] == -1 } {
	return 1
    }
    puts $f $ALDataTxt
    close $f
    return 0
}

proc CmdPutFails {types} {
    # put items of given $types
    # return 0 on success
    global GPSOpResult Storage

    if { [ExecGPSConnectFail] } { return 1 }
    foreach wh $types {
	set ids [lindex $Storage($wh) 0]
	global $ids

	PutGPS $wh [array names $ids]
	vwait GPSOpResult
	if { $GPSOpResult } { return 1 }
    }
    return 0
}

proc CmdOpenFile {path mode} {
    # open file
    #   $mode in {in, out, app}
    # if $path in {stdin, stdout} for suitable $mode return $path
    #  otherwise return file descriptor or -1 on error

    if { $mode == "in" } {
	if { $path == "stdin" } { return stdin }
	set mode r
    } elseif { $path == "stdout" } {
	set mode w
	return stdout
    } elseif { $mode == "out" } {
	set mode w
    } else { set mode a }
    if { [catch {set f [open $path $mode]}] } { return -1 }
    return $f
}

proc CmdReadFails {fmt path pars types} {
    # read file in format $fmt
    # if  $path==stdin  use standard input unless $fmt is Shapefile in which
    #  case return failure
    # return 0 on success
    global FILEFORMAT File

    if { [CmdProcParamsFails $fmt $pars] } { return 1 }
    switch -glob $fmt {
	GPSMan {
	    if { [set f [CmdOpenFile $path in]] == -1 || \
		    [catch {set r [LoadFileFrom $f Data]}] || \
		    $r == 0 } { return 1 }
	}
	Shapefile {
	    if { $path == "stdin" } { return 1 }
	    # a single type per file
	    return [ImportShapefileFrom $path $types]
	}
	default {
	    if { $FILEFORMAT($fmt,filetype) != "data" } {
		# a single type per file
		set wh $types
	    } else { set wh Data }
	    if { $fmt == "GPStrans" } {
		set cr 1
	    } else { set cr 0 }
	    if { [set f [CmdOpenFile $path in]] == -1 } { return 1 }
	    InitInputFileVars $f $wh $cr 0
	    set File($wh) $path
	    if { [catch {set r [ImportFileFrom $f $wh $fmt]}] || $r == 1 } {
		return 1
	    }
	}
    }
    return 0
}	    

proc CmdWriteFails {fmt path pars types} {
    # write data to file in format $fmt
    # if  $path==stdout  use standard output unless $fmt is Shapefile
    #  in which case return failure
    # return 0 on success
    global FILEFORMAT

    if { [CmdProcParamsFails $fmt $pars] } { return 1 }
    switch -glob $fmt {
	GPSMan {
	    if { [set f [CmdOpenFile $path out]] == -1 } { return 1 }
	    if { [catch {set fts $FILEFORMAT(GPSMan,types)}] } {
		set fts [lindex $FILEFORMAT(GPSMan,io_types) 1]
	    }
	    if { [llength $fts] == [llength $types] } {
		if { [catch {SaveFileTo $f all Data}] } { return 1 }
	    } else {
		foreach t $types {
		    if { [catch {SaveFileTo $f all $t}] || \
			    [set f [CmdOpenFile $path app]] == -1 } {
			return 1
		    }
		}
		if { $path != "stdout" } { close $f }
	    }
	}
	Shapefile {
	    if { $path == "stdout" } { return 1 }
	    # a single type per file
	    return [ExportFileTo $path all $fmt $types]
	}
	default {
	    if { [set f [CmdOpenFile $path out]] == -1 } { return 1 }
	    if { $FILEFORMAT($fmt,filetype) != "data" } {
		# a single type per file
		if { [catch {set r [ExportFileTo $f all $fmt $types]}] || \
			$r == 1 } { return 1 }
	    } else {
		set lp [AllIndicesForType Data $types]
		if { [catch {Export_$fmt $f $lp}] } { return 1 }
	    }
	}
    }
    return 0
}

proc CmdProcParamsFails {fmt pars} {
    # process parameters: check the given/default values, convert them, and
    #  use them in defining global variables
    global FILEFORMAT MESS

    if { $pars == "" } { return 0 }
    if { [llength $pars] & 1 == 1 } { BUG Bad parameters list }
    set gvcsvl ""
    foreach "p val" $pars {
	foreach "gvar conversion constraint" $FILEFORMAT($fmt,param,$p) {
	    break
	}
	if { [catch {eval $conversion}] } {
	    GMMessage [format $MESS(badconv) $p $val]
	    return 1
	}
	lappend gvcsvl $p $gvar $constraint $val
    }
    foreach "p gvar constraint val" $gvcsvl {
	if { [catch {set r [eval $constraint]}] || $r == 0 } {
	    GMMessage [format $MESS(badprmval) $p $val]
	    return 1
	}
	global $gvar
	set $gvar $val
    }
    return 0
}

proc CmdSetTranslateParams {pars} {
    # set globals for the translation
    global CmdSAVED

    foreach "p val" $pars {
	switch -- $p {
	    itoffset {
		global FromTimeOffset
		set CmdSAVED(FromTimeOffset) $FromTimeOffset
		set FromTimeOffset $val
	    }
	    otoffset {
		global TimeOffset
		set CmdSAVED(TimeOffset) $TimeOffset
		set TimeOffset $val
	    }
	}
    }
    return
}

proc CmdRestoreTranslation {} {
    # restore any globals changed for the translation
    global CmdSAVED

    if { [info exists CmdSAVED] } {
	foreach g [array names CmdSaved] {
	    global $g
	    set g $CmdSaved($g)
	}
	unset CmdSAVED
    }
    return
}

proc CmdRTimeDumpFails {path} {
    # start dumping real-time log continuously
    # return 0 on success
    global PVTDFile

    if { [set PVTDFile [CmdOpenFile $path out]] == -1 } { return 1 }
    return 0
}

proc CmdRTimeGotFix {args} {
    # global  RealTimeGettingFix has been changed to either -1 for a timeout
    #  or a list with formatted real-time position data --- see procs
    #  UseRealTimeData and RTimeDumpLine
    # exit with 1 on timeout
    # if the fix is valid write to $PVTDFile and exit with 0, otherwise
    #  reset RealTimeGettingFix to 1
    global RealTimeGettingFix PVTDFile TXT DSCALE SPUNIT

    if { $RealTimeGettingFix == -1 } { exit 1 }
    foreach "n date lat long alt fix epe eph epv velx vely velz trk" \
	$RealTimeGettingFix { break }
    if { $fix != $TXT(posfixerror) && $fix != $TXT(posfix_) } {
	puts $PVTDFile "$lat $long"
	puts $PVTDFile "WGS 84"
	puts $PVTDFile $date
	puts $PVTDFile $trk
	# horizontal speed
	if { $velx != "" && $vely != "" } {
	    puts $PVTDFile [format "%.2f $SPUNIT" \
				[expr sqrt($velx*$velx+$vely*$vely)*$DSCALE]]
	} else { puts $PVTDFile "" }
	if { $velz != "" } {
	    puts $PVTDFile [format "%.1f" $velz]
	} else { puts $PVTDFile "" }
	puts $PVTDFile $epe
	puts $PVTDFile $eph
	puts $PVTDFile $epv
	if { $fix == $TXT(posfix3D) || $fix == $TXT(posfix3D-diff) } {
	    puts $PVTDFile $alt
	} else { puts $PVTDFile "" }
	close $PVTDFile
	exit 0
    }
    set RealTimeGettingFix 1
    return
}

proc CmdShow {what} {
    # print information to stdout
    global VERSION FILEFORMAT RECPROTS TXT MESS MAPKNOWNPROJS MAPPROJDATA \
	MAPPROJDTYPE MAPPARTPDATA MAPKNOWNTRANSFS GDATUM COMMAND SYMBOLS

    switch $what {
	help { puts $COMMAND(USAGE) }
	version { puts $VERSION }
	formats {
	    array set mode [list \
		    in  $TXT(fread) \
		    out $TXT(fwrite) \
		    {in out} $TXT(fread)/$TXT(fwrite)]
	    foreach f $FILEFORMAT(names) {
		if { ! [catch {set dep $FILEFORMAT($f,depends)}] && \
			! [eval $dep] } {
		    puts "$f:\t$MESS(shpwrongfile)"
		    continue
		}
		set m $mode($FILEFORMAT($f,mode))
		if { [set t $FILEFORMAT($f,filetype)] == "data" } {
		    set suff " $TXT(nameData)"
		} else { set suff "" }
		if { [catch {set ts $FILEFORMAT($f,types)}] } {
		    foreach "its ots" $FILEFORMAT($f,io_types) { break }
		    puts "$f:\t$mode(in)\t $its$suff"
		    puts "\t$mode(out)\t $ots$suff"
		} else { puts "$f:\t$m\t $FILEFORMAT($f,types)$suff" }
		set t 1
		foreach how "in out" {
		    if { ! [catch {set params $FILEFORMAT($f,$how,params)}] } {
			if { $t } {
			    puts " $TXT(params)"
			    set t 0
			}
			puts "\t$mode($how):"
			if { [catch {set pds $FILEFORMAT($f,$how,pdefts)}] } {
			    set pds ""
			}
			foreach p $params dv $pds {
			    if { [regexp {^global:(.+)$} $dv m dvv] } {
				global $dvv
				puts "\t\t$p\t[set $dvv]"
			    } else { puts "\t\t$p\t$dv" }
			}
		    }
		}
	    }
	}
	projections {
	    set pp [array names MAPPARTPDATA]
	    foreach p [lsort -dictionary $MAPKNOWNPROJS] {
		if { $p == "Schreiber" } {
		    puts "$p:\t$TXT(PRJ$p)"
		} else {
		    puts "$p:\t$TXT(PRJ$p)\n  $TXT(params)"
		    puts "\t?datum"
		    if { [lsearch -exact $pp $p] == -1 } {
			if { $p == "UTM" } {
			    puts "\t?UTMzone"
			    continue
			}
			foreach pm $MAPPROJDATA($p) {
			    if { [set t $MAPPROJDTYPE($pm)] != "reserved" } {
				regsub {^(list=)|(list:)} $t "" t
				puts "\t$pm\t($t)\t$TXT($pm)"
			    }
			}
		    }
		}
	    }
	}
	transfs {
	    foreach t [lsort -dictionary $MAPKNOWNTRANSFS] {
		puts "$t:\t$TXT(TRNSF$t)"
	    }
	}
	datums {
	    foreach d [lsort -dictionary [array names GDATUM]] {
		if { [set cmt [lindex $GDATUM($d) 5]] != "" } {
		    puts "$d\t:$cmt"
		} else { puts $d }
	    }
	}
	protocols {
	    foreach p [lsort -dictionary [array names RECPROTS *,*]] {
		regexp {^(.+),(.+)$} $p x rec prot
		puts "$prot ($rec)"
	    }
	}
	symbols {
	    foreach s [lsort -dictionary $SYMBOLS] {
		if { [string length $s] > 7 } {
		    set sep "\t"
		} else { set sep "\t\t" }
		puts "$s$sep$TXT(SY$s)"
	    }
	}
    }
    return
}

proc CmdBadProjArgs {} {
    # check all the arguments of the project command
    # return 0 on success, 1 on error
    global COMMAND MAPKNOWNPROJS MAPPROJDATA MAPPROJDTYPE MAPPARTPROJ \
	    MAPPARTPDATA MPData

    foreach a "latd longd ptsdatum proj params" {
	set $a $COMMAND($a)
    }
    if { ! [CheckCoord GMMessage DDD $latd N 90] || \
	    ! [CheckCoord GMMessage DDD $longd E 180] || \
	    [EllipsdOf $ptsdatum] == "" || \
	    [lsearch -exact $MAPKNOWNPROJS $proj] == -1 } {
	return 1
    }
    set missdat 1
    if { [set pars $COMMAND(params)] != "" } {
	if { [llength $pars] & 1 == 1 } { BUG Bad parameters list }
	foreach "p val" $pars {
	    if { $p == "datum" } {
		if { [EllipsdOf $val] == "" } { return 1 }
		set MPData(datum) $val
		set missdat 0
	    } else {
		if { [catch {set type MAPPROJDTYPE($p)}] || \
			$type == "reserved" } { return 1 }
		set CMD_$p $val
	    }
	}
    }
    if { $missdat } { set MPData(datum) $ptsdatum }
    # UTM has an optional parameter
    if { $proj == "UTM" && [catch {set CMD_UTMzone}] } { return 0 }
    if { [catch {set mp $MAPPARTPROJ($proj)}] } {
	foreach p $MAPPROJDATA($proj) {
	    if { [set type $MAPPROJDTYPE($p)] != "reserved" } {
		if { [catch {set val [set CMD_$p]}] || \
			[BadParam "" $type $val] } {
		    return 1
		}
		set MPData($p) $val
	    }
	}
    } else {
	foreach e $MAPPROJDATA($mp) v $MAPPARTPDATA($proj) {
	    set MPData($e) $v
	}
	set COMMAND(proj) $mp
    }
    return 0
}

proc CmdBadProjSetup {} {
    # initialize projection
    # return 0 on success, 1 on error
    global COMMAND

    foreach a "latd longd ptsdatum proj" {
	set $a $COMMAND($a)
    }
    if { [BadProjSetup MPData $proj $latd $longd $ptsdatum] } { return 1 }
    return 0
}

proc CmdBadGeoRefArgs {} {
    # check the arguments of the georef command and prepare data
    # return 0 on success, 1 on error
    global COMMAND MapLoadPos

    foreach a "transf ptsdatum proj params" {
	set $a $COMMAND($a)
    }
    # used by proc CmdBadProjArgs
    set COMMAND(latd) $COMMAND(0,lat)
    set COMMAND(longd) $COMMAND(0,long)
    if { [CmdBadProjArgs] } { return 1 }
    set npts $COMMAND(npts)
    for { set p 0 } { $p < $npts } { incr p } {
	foreach pp "lat long x y" {
	    set $pp $COMMAND($p,$pp)
	}
        if { ! [CheckCoord GMMessage DDD $lat N 90] || \
		! [CheckCoord GMMessage DDD $long E 180] || \
		! [CheckFloat GMMessage $x] || ! [CheckFloat GMMessage $y] } {
	    return 1
	}
	set MapLoadPos($p,x) $x ; set MapLoadPos($p,y) $y
    }
    return 0
}

proc CmdProjCoords {npts} {
    # return list of projected coordinates for points given in command line
    #  $npts is number of points
    # assumes that the following elements are defined in array COMMAND
    #   ptsdatum
    #   $n,lat   for $n in 0..$npts-1
    #   $n,long
    #   proj     projection
    # assumes that the projection parameters were initialized in array MPData
    global COMMAND

    set ptsdatum $COMMAND(ptsdatum) ; set proj $COMMAND(proj)
    set tcs ""
    for { set p 0 } { $p < $npts } { incr p } {
	lappend tcs [Proj${proj}Point MPData \
		$COMMAND($p,lat) $COMMAND($p,long) $ptsdatum]
    }
    return $tcs
}

proc CmdBadGeoRefSetup {} {
    # initialize projection and transformation
    # return 0 on success, 1 on error
    global COMMAND

    if { [CmdBadProjSetup] } { return 1 }
    MapProjectionIs $COMMAND(proj)
    if { [set transf $COMMAND(transf)] == "NoRot" } {
	set proc InitNoRotTransf
    } else { set proc MapInit${transf}Transf }
    if { ! [$proc] } { return 1 }
    return 0
}

proc CmdGenerateGeoRef {} {
    # output geo-ref information file
    global COMMAND

    SaveMapBack $COMMAND(image) stdout
    return
}

proc CmdGPictsOutputFails {fmt path lts datum sy prefix} {
    # write a waypoint for each tuple in $lts to file in format $fmt
    #  $fmt must be GPX (for the time being)
    #  $lts is list of tuples with the latitude and longitude (decimal
    #     degrees, for $datum) and altitude (metre), date in seconds from
    #     $YEAR0, file path, and date in "%Y:%m:%d %H:%M:%S" format
    #  $sy the symbol code to use for WPs
    #  $prefix is the name prefix to be used when generating WP names
    # if  $path==stdout  use standard output
    # return 0 on success

    if { $fmt != "GPX" } { BUG CmdGPictsOutputFails: format must be GPX }
    if { $path != "stdout" } {
	if { [catch {set file [open $path w]}] } { return 1 }
    } else { set file stdout }

    # output GPX
    set xml_hdr {<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
  <gpx
    version="1.0"
    creator="GPSMan" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.topografix.com/GPX/1/0"
    xmlns:topografix="http://www.topografix.com/GPX/Private/TopoGrafix/0/2"
    xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.topografix.com/GPX/Private/TopoGrafix/0/2 http://www.topografix.com/GPX/Private/TopoGrafix/0/2/topografix.xsd">
    <author>anonymous GPSMan user</author>
    <email>undefined</email>
    <url>undefined</url>
    <urlname>undefined</urlname>
}

    set xml_footer {</gpx>}

    set xml_wptalt {<wpt lat="%s" lon="%s">
    <name>%s</name>    <ele>%s</ele>
    <symbol>%s</symbol>
    <desc>%s</desc>
    <extensions><picture>%s</picture></extensions>
</wpt>
}

    set xml_wpt {<wpt lat="%s" lon="%s">
    <name>%s</name>
    <symbol>%s</symbol>
    <desc>%s</desc>
    <extensions><picture>%s</picture></extensions>
</wpt>
}
    set n 0
    set dpre "Photo"
    puts $file $xml_hdr
    foreach tuple $lts {
	foreach "la lo alt secs fpath date" $tuple { break }
	set name "$prefix[format %05d $n]"
	incr n
	set fname [file tail $fpath]
	set dscr "$dpre $fname"
	if { $alt != "" } {
	    puts $file [format $xml_wptalt $la $lo $name $alt $sy $dscr $fname]
	} else {
	    puts $file [format $xml_wpt $la $lo $name $sy $dscr $fname]
	}
    }
    puts $file $xml_footer
    if { $path != "stdout" } { close $file }
    return 0
}    

##### logo window

proc ShowGPSMan {} {
    # create widgets for displaying information about GPSMan in root window
    global SmallLogo VERSION COLOUR EPOSX EPOSY TXT

    wm protocol . WM_DELETE_WINDOW { exit 1 }
    frame .fr -relief flat -borderwidth 5 -bg $COLOUR(messbg)
    if { $SmallLogo != "" } {
	label .fr.im -image $SmallLogo -relief sunken
	pack .fr.im
    }
    label .fr.title -text "$TXT(GMtit) $VERSION" -relief sunken
    bind . <Button-1> About

    pack .fr.title -side top -pady 5
    pack .fr -side top
    update idletasks
    return
}




