#
# This file is part of:
#
#  gpsman --- GPS Manager: a manager for GPS receiver data
#
# Copyright (c) 1998-2011 Miguel Filgueiras migf@portugalmail.pt
#
#    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 3 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: plugins.tcl
#  Last change:  17 September 2011
#
# Includes contributions by
#  - Rudolf Martin (rudolf.martin _AT_ gmx.de) marked "RM contribution"
#    [gnuplot plug-ins from file dated 28 January 2011]
#

### which toplevels support plug-ins (used for documentation only)
# indices are patterns of toplevel window paths
# contents are lists of lists whose heads are widget types (button, menu)
#  and whose rests are sub-window paths (frame, menu) where the plug-in
#  widgets or entries will be inserted

  ## windows, procedures, title index in TXT, comment
  #   .         GMInit		GMtit		main window (map or lists)
  #   .gmWP*	GMWPoint	waypoint	WP edit/show windows
  #   .*.topc   GMTRCompute	TRcomp		TR computation window
  #   .gmRT*	GMRoute		route		RT edit/show windows
  #   .gmTR*	GMTrack		track		TR edit/show windows
  #   .gmLN*	GMLine		nameLN		LN edit/show windows
  #   .gmGR*	GMGroup		group		GR edit/show windows
array set PLGSWelcomed {
    .      {{menu fr.frm.top.frmap0.udefs.mn.plugin.exec
	          mpw.fr.frmi.frcoords.udefs.mn.plugin.exec}}
    .gmWP* {{button .fr.fr6}}
    .gmRT* {{button .fr.frdw}}
    .gmTR* {{button .fr.frdw}}
    .*.topc {{menu .fr.frsel.hgraph.mn.el .fr.frsel.hgraph.mn
                   .fr.frsel.more.mn}}
    .gmLN* {{button .fr.frdw}}
    .gmGR* {{button .fr.frdw}}
}

# check for the following comments inserted in other source files
    # frame used for plug-ins (see array PLGSWelcomed, plugins.tcl)
    # menu used for plug-ins (see array PLGSWelcomed, plugins.tcl)
# call that must be made from procedures accepting plug-ins
#    AttachPlugIns $w


proc SetUpPlugIn {name where} {
    # make plug-in known to procedures setting up toplevel windows
    global PLGSForWindow

    foreach t $where {
	foreach {patt type widget} $t { break }
	set e [list $name $type $widget]
	if { [catch {set ts $PLGSForWindow($patt)}] } {
	    set PLGSForWindow($patt) [list $e]
	} else {
	    lappend ts $e
	    set PLGSForWindow($patt) $ts
	}
    }
    return
}

proc AttachPlugIns {hostwindow} {
    # make plug-ins available from window $hostwindow using information
    #  in the global array PLGSForWindow from first matched pattern
    # creates buttons and/or menu entries
    global PLUGIN PLGSForWindow

    foreach patt [array names PLGSForWindow] {
	if { [string match $patt $hostwindow] } {
	    foreach t $PLGSForWindow($patt) {
		foreach {plugin type sub} $t { break }
		# if sub-window does not exist do nothing
		set wd $hostwindow$sub
		if { ! [winfo exists $wd] } { continue }
		set pdata $PLUGIN($plugin)
		foreach {remark unavail params pcode} $pdata { break }
		set cmd "expr $unavail"
		if { [catch {set unavail [uplevel #0 $cmd]} err] } { continue }
		if { $unavail } {
		    set state disabled
		} else { set state normal }
		set cmd ""
		append cmd PlugInExec " " "{$plugin}" " " $hostwindow " " \
		    [uplevel subst -nocommands \"$params\"]
		switch $type {
		    button {
			regsub -all { } $plugin "___" plref
			set b [button $wd.pl_$plref -text $plugin \
				   -command $cmd -state $state]
			BalloonBindings $b "{=$remark}"
			foreach {col row} [grid size $wd] { break }
			incr row -1
			grid $b -row $row -column $col -padx 10
		    }
		    menu {
			$wd add command -label $plugin -command $cmd \
			    -state $state
		    }
		}
	    }
	}
    }
    return
}

proc PlugInExec {plugin window args} {
    # execute plug-in called from $window
    #  $args is a list of consecutive elements NAME VALUE
    #    a variable NAME being set to VALUE before evaluation of
    #    the plug-in code
    global PLUGIN MESS

    foreach {v val} $args {
	if { [string index $v 0] != "_" } {
	    DisplayInfo [format $MESS(badpluginparamexec) $plugin $p]
	    return
	}
	set $v $val
    }
    if { [catch {eval [lindex $PLUGIN($plugin) 3]} err] } {
	DisplayInfo [format $MESS(pluginfailed) $plugin $err]
    }
    return
}

### predefined plug-ins
#  names and remarks must be in TXT

set PLUGIN($TXT(wptotwitter)) \
    [list $TXT(wptotwitternb) \
	 {[catch {package require TclCurl}]} \
	 {_ed $ed _ix $index} \
	 {   set _url http://twitter.com/statuses/update.xml
	     set _mess "#GPSMan #waypoint\n"
	     if { $_ed } {
		 global GMEd ChangedPosn
		 set _p [PosnGetCheck .gmWP.fr.frp.frp1 $GMEd(WP,Datum) \
			     GMMessage ChangedPosn]
		 if { $_p != "nil" } {
		     set _alt [AltitudeList \
				   [string trim [.gmWP.fr.fr11.alt get]]]
		     if { $_alt == "nil" } { set _alt "" }
		     set _datum $GMEd(WP,Datum)
		     set _name [.gmWP.fr.fr1.id get]
		     set _commt [.gmWP.fr.fr2.commt get]
		 }
	     } else {
		 global WPName WPPosn WPDatum WPAlt WPCommt
		 set _p $WPPosn($_ix) ; set _datum $WPDatum($_ix)
		 set _alt $WPAlt($_ix)
		 set _name $WPName($_ix) ; set _commt $WPCommt($_ix)
	     }
	     if { $_p != "nil" } {
		 global COUTFMT
		 set _lat [lindex $_p 0] ; set _long [lindex $_p 1]
		 append _mess lat= [format $COUTFMT(deg) [lindex $_p 0]] " " \
		     long= [format $COUTFMT(deg) [lindex $_p 1]]
		 if { $_alt != "" } {
		     append _mess "\nalt=" $_alt
		 }
		 append _mess "\ndatum=" [QuoteString $_datum]
		 if { $_name != "" } {
		     append _mess "\nname=" [QuoteString $_name]
		 }
		 if { $_commt != "" } {
		     append _mess "\ncomment=" [QuoteString $_commt]
		 }
		 WebPost Twitter 1 $_url status $_mess 140
	     }
	 } \
	 {{.gmWP* button .fr.fr6}}]


#############################################################
# RM contribution
#############################################################

#####
# plugin for plotting 2D altitudecharts with gnuplot
# contributed by R. Martin 2010
# refer to wrtdials.tcl - proc GMTRCompute

# MF change: test gnuplot by executing quit
set PLUGIN($TXT(gpTRtoGnuplot2d)) \
    [list $TXT(gpTRtoGnuplot2d_nb) \
	 {[catch {exec gnuplot -e quit}]} \
	 {_lll {$lll} _speeds {$speeds} _trname {[$window.fr.fr1.id get]} \
	          _cumula $cumula _cumuld $cumuld _td $td _tt $tt \
                  _avsp $avsp _minalt $minalt _maxalt $maxalt \
	          _datum {$datum} _tps {$tps} _rest {$rest}} \
	 {   
             PCode_TRtoGnuplot2d $_lll $_speeds $_trname $_cumula $_cumuld \
		 $_td $_tt $_avsp $_minalt $_maxalt $_datum $_tps $_rest
	 } \
	 {{.*.topc menu .fr.frsel.hgraph.mn.el}}]

#####
# plugin for plotting 3D-charts with gnuplot
# contributed by R. Martin 2010
# refer to wrtdials.tcl - proc GMTRCompute

# MF change: test gnuplot by executing quit
set PLUGIN($TXT(gpTRtoGnuplot3d)) \
    [list $TXT(gpTRtoGnuplot3d_nb) \
	 {[catch {exec gnuplot -e quit}]} \
	 {_tmp3D {$tmp3D} _tmp3D2 {$tmp3D2} _trname {[$window.fr.fr1.id get]}\
                _minalt $minalt _maxalt $maxalt _datum {$datum}} \
	 { 
             PCode_TRtoGnuplot3d $_tmp3D $_tmp3D2 $_trname\
                                 $_minalt $_maxalt $_datum
	 } \
	 {{.*.topc menu .fr.frsel.hgraph.mn.el}}]


# plugin for calculating estimated hiking time
# contributed by R. Martin 2010
# refer to wrtdials.tcl - proc GMTRCompute
# 

set PLUGIN($TXT(htCalcHikeTime)) \
    [list $TXT(htCalcHikeTime_nb) \
	 { 0 } \
	 {_trname {[$window.fr.fr1.id get]} \
	          _cumula $cumula _cumuld $cumuld _td $td _tt $tt \
	          _tmt $tmt _trt $trt} \
	 {
	     global MESS TXT ALSCALE DSCALE

             lappend htParam [list "DAV   " 4 300 500]
             lappend htParam [list "GROUP " 5 300 600]
             lappend htParam [list "SINGLE" 5 400 800]

             # convert to meters
             set _cumula [expr round($_cumula*$ALSCALE)]
             set _cumuld [expr round($_cumuld*$ALSCALE)]
             set _td [format "%4.2f" [expr $_td/$DSCALE]]
             
             DisplayInfo $TXT(htHeader)
             DisplayInfo " "
             DisplayInfo [format $MESS(htResult1) $_trname]
             DisplayInfo [format $MESS(htResult2) \
                          "${_td}km" "${_cumula}m" "${_cumuld}m"]
             
             if {$_trt != 0 && $_tt != 0} { 
                 set perc [format "%2.0f" \
		       [expr double([TimeToSecs $_trt])/[TimeToSecs $_tt]*100]]
             } else {
                 set perc 0
             }
 
             if {$_tt != 0} { 
                 DisplayInfo [format $MESS(htResult3) \
                              $_tt $_trt "$perc%" $_tmt]
             } 
             
             DisplayInfo " "

	     foreach element $htParam {
	         set desc [lindex $element 0]
	         set cap_plain [lindex $element 1]
	         set cap_asc [lindex $element 2]
	         set cap_desc [lindex $element 3]

	         set time_plain [expr $_td/double($cap_plain)]
	         set time_elevation \
		   [expr $_cumula/double($cap_asc) + $_cumuld/double($cap_desc)]
	         if {$time_plain > $time_elevation} {
	                 set hiketime [expr $time_plain + $time_elevation/2]
	         } else {
	                 set hiketime [expr $time_elevation + $time_plain/2]
	         }
	         set hiketime [FormatTime [expr $hiketime*3600]] 

	         DisplayInfo [format $MESS(htResult4) $desc \
	                 "${cap_plain}km" "${cap_asc}m" "${cap_desc}m" $hiketime]
	     }
	     
             DisplayInfo " "
             DisplayInfo $TXT(htFooter1)
             DisplayInfo $TXT(htFooter2)
            
	 } \
	 {{.*.topc menu .fr.frsel.more.mn}}]
	 
# plugin for display rest periods in tracks
# contributed by R. Martin 2010
# refer to wrtdials.tcl - proc GMTRCompute
# 
# the calculation is done in wrtdials (list $rest)
#
set PLUGIN($TXT(srShowRest)) \
    [list $TXT(srShowRest_nb) \
	 { 0 } \
	 {_trname {[$window.fr.fr1.id get]} \
	           _rest {$rest} _tt $tt _tmt $tmt _trt $trt _td $td}\
	 {
	     global MESS TXT DTUNIT

             DisplayInfo [format $MESS(srResult1) $_trname]
             DisplayInfo " "
             DisplayInfo [format "%5s  %10s    %10s  %10s"\
                          "Index" $TXT(srChainage) $TXT(srTRTime) $TXT(srRest)]
             foreach element $_rest {
		     set i [format "%4.0f" [lindex $element 0]]
		     set chain [lindex $element 1]
		     set tracktime [FormatTime [lindex $element 2]]
		     set resttime [FormatTime [lindex $element 3]]
                     DisplayInfo [format "%5d  %8.3f%-5s   %8s    %8s"\
                                  $i $chain $DTUNIT $tracktime $resttime]
             }
             if {$_trt != 0 && $_tt != 0} { 
                 set perc [format "%2.0f" \
		       [expr double([TimeToSecs $_trt])/[TimeToSecs $_tt]*100]]
             } else {
                 set perc 0
             }
             DisplayInfo " "
             DisplayInfo $TXT(srTotals)
             DisplayInfo [format "       %8.3f%-5s   %8s    %8s %s"\
                          $_td $DTUNIT $_tt $_trt "($perc%)"]
	 } \
	 {{.*.topc menu .fr.frsel.more.mn}}]
	 

# end of RM contribution


### set up predefined plug-ins and menu description

set PREDEFPLUGINDESCR {}
if { [catch {set uplugins [set $DefSpecs(plugin,ulist)]}] } {
    set uplugins {}
}

foreach plugin [lsort -dictionary [array names PLUGIN]] {
    if { [lsearch -exact $uplugins $plugin] == -1 } {
	if { [regexp {^(@|(---))} $plugin] } {
	    # avoid clashes with special denotations used by proc FillMenu
	    lappend PREDEFPLUGINDESCR " $plugin"
	} else { lappend PREDEFPLUGINDESCR $plugin }
	SetUpPlugIn $plugin [lindex $PLUGIN($plugin) end]
    }
}



##### procedures called from plug-ins

#################################################################
# RM contribution
#################################################################

#####
proc PCode_TRtoGnuplot2d {_lll _speeds _trname _cumula _cumuld _td _tt\
                          _avsp _minalt _maxalt _datum _tps _rest} {
                          
     global MESS TXT DTUNIT ALUNIT SPUNIT DISPLAYCMD USERTMPDIR UNIX \
            DateFormat NoImgLib

     #  get settings for gnuplot
     global _gpParam

     # set default values
     array set _gpParam {
	totals  gpRight
	rests  gpSymTime
	hours  gpTimetop
	speed   gpHike
	help text
	limit_dist 0.100
	limit_stat 0.500
	width   800
	height  600
     }
     # setting output-filename
     set _gpParam(filename) "2D_chart_$_trname.png"

     # set up list of variables
     set vars {}
     foreach v {totals rests hours speed filename help limit_dist limit_stat
                width height} {
	 lappend vars _gpParam($v)
     }

     set descs [list\
		"~$TXT(gpSTotals)/[list gpLeft gpRight gpNone]"\
		"~$TXT(gpSRests)/[list gpSymTime gpSymText gpText gpSym gpNone]"\
		"~$TXT(gpSHours)/[list gpTimetop gpTimebot gpNone]"\
		"~$TXT(gpSSpeed)/[list gpHike gpBike gpDrive gpGlide gpNone]"\
		"=$TXT(gpFilename)"\
		"@@gp2D_hlp"\
		"=$TXT(gpLimitDist)"\
		"=$TXT(gpLimitStat)"\
                "=$TXT(gpCanwidth)"\
		"=$TXT(gpCanheight)"]

     set mess $TXT(gpParam2d)
     while 1 {
	if { [GMChooseParams $mess $vars $descs] == 0 } { return }
	if { [CheckNumber GMMessage $_gpParam(width)] && \
		 [CheckNumber GMMessage $_gpParam(height)] } { break }
     }

     set limit_dist $_gpParam(limit_dist)
     # limit for distance from trackpoint to WP in km
     # waypoints outside of this delimiter will be discarded

     set limit_stat $_gpParam(limit_stat)
     # only one hit within this tracklenght                        

     if {$_tt == 0} {
	 # no time information
	 set $_gpParam(hours) "gpNone"
	 set $_gpParam(rests) "gpNone"
	 set $_gpParam(speed) "gpNone"
     }

     # checking for bad data
     foreach a $_lll {
	foreach "stat alt newsegm" $a { break }
	# extraction of stat, alt with check
	if {   [regexp \
	       {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $stat]\
		  && $alt != "" } {
	    # good data
	    lappend chartdata [list $stat $alt]
	}
     }   

     # for setting the labels in the chart we need some altitudes
     set altbegin [lindex [lindex $chartdata 0] 1]            
     set altend [lindex [lindex $chartdata end-1] 1] 
     # gnuplot generates different scalings
     set diffalt [expr $_maxalt-$_minalt]
     foreach l {500 1000 2000 5000 1e70} v {50 100 200 500 1000} {
	 if { $diffalt < $l } {
	     # set min/max to even number
	     set minaltr [expr $v*($_minalt / $v) ]
	     set maxaltr [expr $v*($_maxalt / $v +1) ]
	     set ytics_alt $v
	     break
	 }
     }
     set altmid [expr ($minaltr+$maxaltr)/2]

     # writing stat, alt to temporary datafile
     set tmp_alt [file join $USERTMPDIR gp_2d_alt.tmp]
     set fh [open $tmp_alt w]
     foreach element $chartdata {
	 puts $fh $element
     }
     close $fh

     if { $_gpParam(speed) != "gpNone" } {
	     # writing velocity to temporary datafile
	     set tmp_speed [file join $USERTMPDIR gp_2d_speed.tmp]
	     set fh [open $tmp_speed w]
	     foreach element $_speeds {
		 puts $fh $element
	     }
	     close $fh
     }

     if { $_gpParam(hours) != "gpNone" } {
	     # writing hours to temporary datafile
	     set tmp_time [file join $USERTMPDIR gp_2d_time.tmp]
	     set fh [open $tmp_time w]
	     if { $_gpParam(hours) == "gpTimetop" } {
		 set alt_time $maxaltr
	     } else {
		 set alt_time $minaltr
	     }
	     set hour0 99
	     # first point
	     set tp_sec [lindex [lindex $_tps 0] 5]
	     set ttime [DateIntsFromSecs $tp_sec]
	     set hour [lindex $ttime 3]
	     set minute [format "%02d" [lindex $ttime 4]]
	     if {$minute < 45} {
		 puts $fh [list "0" $alt_time [append hour ":" $minute]]
	     }
	     for {set i 0} {$i < [llength $_tps]} {incr i} {
		 # loop for all tp
		 set tp_sec [lindex [lindex $_tps $i] 5]
		 set ttime [DateIntsFromSecs $tp_sec]
		 set hour [lindex $ttime 3]
		 if {$hour > $hour0} {
		     set chain [lindex [lindex $chartdata $i] 0]
		     puts $fh [list $chain $alt_time [append hour ":00"]]
		 }
		 set hour0 $hour
	     }
	     # last point
	     set minute [format "%02d" [lindex $ttime 4]]
	     if {$minute > 15} {
		 set chain [lindex [lindex $chartdata [incr i -1] ] 0]
		 puts $fh [list $chain $alt_time [append hour ":" $minute]]
	     }
	     close $fh
     }


     if { $_gpParam(rests) != "gpNone" } {
	     # writing rest periods to temporary datafile
             set tmp_rest [file join $USERTMPDIR gp_2d_rest.tmp]
	     set fh [open $tmp_rest w]
	     foreach element $_rest {
		 set chain [expr [lindex $element 1]]
		 if {$_gpParam(rests) == "gpSymTime"} {
		     set resttime [expr round([lindex $element 3]/60.0)]
		     append resttime "min"
		     puts $fh [list $chain $minaltr $resttime] 
		 } else {
		     puts $fh [list $chain $minaltr $TXT(gpRest)] 
		 }
	     }
	     close $fh
     }

     #  search for all Waypoints in corresponding group 
     global GRConts WPPosn WPAlt
     set wpns "";  # list of waypoints
     # look for the ID of groupname == trackname
     if { ( $_trname != "" && \
		[set ix [IndexNamed GR $_trname]] != -1 ) || \
	      [set ix [ChooseItems GR single]] != "" } {
	 # look for wp in group
	 foreach p $GRConts($ix) {
	     if { [lindex $p 0] == "WP" } {
		 set wpns [lindex $p 1]
		 break
	     }
	 }
     }

     # handle waypoints
     # write matching waypoints to temporary datafile
     set foundwpl 0
     set foundwph 0
     if { $wpns != {} } {
	 set tmp_wpl [file join $USERTMPDIR gp_2d_wpl.tmp] ; # low
	 set tmp_wph [file join $USERTMPDIR gp_2d_wph.tmp] ; # high
	 set fhl [open $tmp_wpl w]
	 set fhh [open $tmp_wph w]
	 while { $wpns != "" } {
	     # when wpns exist look for waypoint-index wpix 
	     while { $wpns != "" && \
			 [set wpix [IndexNamed WP [lindex $wpns 0]]] == -1 } {
		 GMMessage [format $MESS(undefinedWP) [lindex $wpns 0]]
		 set wpns [lreplace $wpns 0 0]
	     }
	     set wpname [lindex $wpns 0]

	     # get lat, lon, alt 
	     set wp_lat [lindex $WPPosn($wpix) 0]
	     set wp_lon [lindex $WPPosn($wpix) 1]
	     set wp_alt [lindex $WPAlt($wpix) 0]
	     set wp_alt [UserAltitude $wp_alt]

	     # searching the trackdata
	     set nearestDist 1e10
	     set nearestIndex -1
	     set nearestStat 0
	     set nearestAlt 0

	     for {set i 0} {$i < [llength $_tps]} {incr i} {
		 # loop for all tp
		 set tp_lat [lindex [lindex $_tps $i] 0]
		 set tp_lon [lindex [lindex $_tps $i] 1]
		 set tp_alt [lindex [lindex $_tps $i] 6]
		 set tp_stat [lindex [lindex $chartdata $i] 0]

		 # get distance waypoint to trackpoint
		 # this is a quick hack with no exact calculation
		 #      due to fast computing time
		 # we only calculate the difference in decimaldegrees
		 #   and convert to km
		 # limit_dist refers to lat and to long

		 set diff_lat [expr abs($wp_lat - $tp_lat)*111.325]
		 set diff_lon [expr abs($wp_lon - $tp_lon)*111.325* \
				   cos($tp_lat*3.1415926/180)]

		 if { [expr $tp_stat-$nearestStat] > $limit_stat  && \
			  $nearestIndex != -1 } {
		     # the last found trackpoint is stored 
		     #      when it lays > $limit_stat behind

		     # check wp_alt
		     if {$wp_alt != "" || [set alt $nearestAlt] == ""} {
			 set alt $wp_alt
		     } 

		     if {$alt > $altmid} {
			 puts $fhh [list $nearestStat $alt $wpname]
			 set foundwph 1
		     } else {
			 puts $fhl [list $nearestStat $alt $wpname]
			 set foundwpl 1
		     }

		     # reset search of trackdata
		     set nearestDist 1e10
		     set nearestIndex -1
		 }

		 if { ($diff_lat < $limit_dist) && ($diff_lon < $limit_dist) } {
		     set currDist [expr $diff_lat + $diff_lon]
		     if { $nearestIndex == -1 || $currDist < $nearestDist} {
			 # found new nearest trackpoint
			 set nearestIndex $i
			 set nearestStat $tp_stat
			 set nearestAlt $tp_alt
			 set nearestDist $currDist
		     }
		 }
	     };   # for-loop for tps

	     if { $nearestIndex > -1 } {
		 # store last found point
		 # check wp_alt
		 if {$wp_alt != "" || [set alt $nearestAlt] == ""} {
		     set alt $wp_alt
		 } 
		 if {$alt > $altmid} {
		     puts $fhh [list $nearestStat $alt $wpname]
		     set foundwph 1
		 } else {
		     puts $fhl [list $nearestStat $alt $wpname]
		     set foundwpl 1
		 }
	     }

	     set wpns [lreplace $wpns 0 0];  # removes first element
	 };  # while-loop for wps
	 close $fhl
	 close $fhh
     }; # end if wpns != {}

     # get the date of the track, only if hours are shown
     set date ""
     if { $_gpParam(hours) != "gpNone" } {
         set date [lindex [lindex $_tps 0] 4]
	 foreach {y m d} [ScanDate $date] { break }
	 if { $d != "" } {
	     set date [FormatDay $DateFormat $y $m $d]
	     set date "($date)"
	 }
     }

     # writing gnuplot scriptfile
     set tmp_script [file join $USERTMPDIR gp_2d_script.plt]
     set fh [open $tmp_script w]

     puts $fh "\# gnuplot scriptfile created by GPSMan"
     puts $fh {reset}
 
     #  create outputfile, no display on screen
     puts $fh "set terminal png size $_gpParam(width),$_gpParam(height)"
     puts $fh "set output \"$_gpParam(filename)\""

     puts $fh {set grid}
     puts $fh {set lmargin 8}
     puts $fh {set multiplot layout 2,1}
     puts $fh {set size 1,0.80}
     puts $fh {set origin 0,0.20}
     puts $fh "set title \"$_trname  $date\""
     puts $fh {set format x}
     puts $fh "set xlabel '$TXT(distance) ($DTUNIT)' offset 0,0.5"
     puts $fh "set ylabel '$TXT(alt) ($ALUNIT)' offset 2"
     puts $fh {set style fill solid 0.5 border -1}
     puts $fh "set label 1 '$TXT(gpGenerated)' at screen 0.98,screen 0.02 right front"
     puts $fh "set ytics $ytics_alt"

     if { $_gpParam(totals) == "gpLeft" } {
	 # data left side
	 if {$altbegin > $altmid } {  
	    # bottom
	    puts $fh "set label 4 \" $TXT(alt_cumula) = $_cumula $ALUNIT\" at graph 0,graph 0.20 left front"
	    puts $fh "set label 5 \" $TXT(alt_cumuld) = $_cumuld $ALUNIT\" at graph 0,graph 0.15 left front"
	    puts $fh "set label 2 \" $TXT(totdst) = $_td $DTUNIT\" at graph 0,graph 0.10 left front"
	    if {$_tt > 0 } {
	      puts $fh "set label 3 \" $TXT(tottime) = $_tt \" at graph 0,graph 0.05 left front"
	    }
	 } else {
	    # top
	    puts $fh "set label 4 \" $TXT(alt_cumula) = $_cumula $ALUNIT\" at graph 0,graph 0.95 left front"
	    puts $fh "set label 5 \" $TXT(alt_cumuld) = $_cumuld $ALUNIT\" at graph 0,graph 0.90 left front"
	    puts $fh "set label 2 \" $TXT(totdst) = $_td $DTUNIT\" at graph 0,graph 0.85 left front"
	    if {$_tt > 0 } {
	      puts $fh "set label 3 \" $TXT(tottime) = $_tt \" at graph 0,graph 0.80 left front"
	    }
	 }   
     } elseif { $_gpParam(totals) == "gpRight" } {
	 # data right side
	 if {$altend > $altmid } {  
	    # bottom
	    puts $fh "set label 4 \" $TXT(alt_cumula) = $_cumula $ALUNIT\" at graph 1,graph 0.20 right front"
	    puts $fh "set label 5 \" $TXT(alt_cumuld) = $_cumuld $ALUNIT\" at graph 1,graph 0.15 right front"
	    puts $fh "set label 2 \" $TXT(totdst) = $_td $DTUNIT\" at graph 1,graph 0.10 right front"
	    if {$_tt > 0 } {
	      puts $fh "set label 3 \" $TXT(tottime) = $_tt \" at graph 1,graph 0.05 right front"
	    }
	 } else {
	    # top
	    puts $fh "set label 4 \" $TXT(alt_cumula) = $_cumula $ALUNIT\" at graph 1,graph 0.95 right front"
	    puts $fh "set label 5 \" $TXT(alt_cumuld) = $_cumuld $ALUNIT\" at graph 1,graph 0.90 right front"
	    puts $fh "set label 2 \" $TXT(totdst) = $_td $DTUNIT\" at graph 1,graph 0.85 right front"
	    if {$_tt > 0 } {
	      puts $fh "set label 3 \" $TXT(tottime) = $_tt \" at graph 1,graph 0.80 right front"
	    }
	 }  
     }
 
     # way of display waypoints
     if { $foundwpl } {
	 set script_wpl ", '$tmp_wpl' with labels left rotate point pt 9 offset -0.50,1.0 notitle"
     } else {
	 set script_wpl ""
     }
     if { $foundwph } {
	 set script_wph ", '$tmp_wph' with labels right rotate point pt 9 offset -0.50,-1.0 notitle"
     } else {
	 set script_wph ""
     }

     # way of display rests
     if {$_gpParam(rests) == "gpSymText" || $_gpParam(rests) == "gpSymTime"} {
	 set script_rest ", '$tmp_rest' with labels tc lt 1 left rotate point pt 9 lc 1 offset -0.50,0.25 notitle"
     } elseif {$_gpParam(rests) == "gpText"} {
	 set script_rest ", '$tmp_rest' with labels tc lt 1 left rotate point pt 0 offset -0.50,0.25 notitle"
     } elseif {$_gpParam(rests) == "gpSym"} {
	 set script_rest ", '$tmp_rest' with point pt 9 lc 1 notitle"
     } else {
	 set script_rest ""
     }

     # way of display timestamps
     if { $_gpParam(hours) == "gpTimetop" } {
	 set script_time ", '$tmp_time' with labels tc lt 1 center point pt 11 lc 1  offset 0.00,0.50 notitle"
     } elseif { $_gpParam(hours) == "gpTimebot" } {
	 set script_time ", '$tmp_time' with labels tc lt 1 center point pt 11 lc 1  offset 0.00,0.50 notitle"
     } else {
	 set script_time ""  
     }
 
     puts $fh "plot '$tmp_alt' notitle with filledcurve y1=0 lt rgb \"#009000\" \
	       $script_wpl $script_wph $script_rest $script_time"
 
     if { $_gpParam(speed) != "gpNone" } {
         # this part defines the velocity chart
         puts $fh {set notitle}
         puts $fh {unset label 1}
         puts $fh {unset label 2}
         puts $fh {unset label 3}
         puts $fh {unset label 4}
         puts $fh {unset label 5}
         puts $fh {set size 1,0.20}
         puts $fh {set origin 0,0.02}
         if {$_gpParam(speed) == "gpHike"} {
		puts $fh {set yrange [0:8] # setting for hike}
		puts $fh {set ytics 2}
         } elseif {$_gpParam(speed) == "gpBike"} {
		puts $fh {set yrange [0:60] # setting for bike}
		puts $fh {set ytics 10}
         } elseif {$_gpParam(speed) == "gpDrive"} {
		puts $fh {set yrange [0:175] # setting for drive}
		puts $fh {set ytics 25}
         } else {
		puts $fh {set yrange [0:350] # setting for glide}
		puts $fh {set ytics 50}
         }
         puts $fh {set format x ""}
         puts $fh {set xlabel ""}
         puts $fh "set ylabel '$TXT(speed) ($SPUNIT)' offset 0.5"
         puts $fh {set style fill solid 0.5 border -1}
         puts $fh "plot '$tmp_speed' notitle with filledcurve y1=0 lt rgb \"#009000\",\
		   '$tmp_speed' notitle with lines lt 4 lw 3 smooth sbezier"
     }
     puts $fh {unset multiplot}

     close $fh

     # start gnuplot
     exec gnuplot $tmp_script &


     if { $NoImgLib } {
	     # displaycmd is only needed when libtk-img isn't installed
	     # then show image with external program, if available
	     if { $DISPLAYCMD != "" } {
	         after 1000
		 catch {exec $DISPLAYCMD $_gpParam(filename) &}
	     } else {
		 DisplayInfo [format $MESS(gpOutfile) $_gpParam(filename)]
	     }
     } else {
	     # display result in toplevel window
             after 1000
	     set gnuplotImage [image create photo -file $_gpParam(filename)]

	     if { [winfo exists .showimage] } {
	             .showimage.gnuplot configure -image $gnuplotImage
		     focus .showimage
		     raise .showimage
	     } else {
		 # MF changes: use proc GMToplevel to create top level window
		 #  and add an Ok button
		 global DPOSX DPOSY
		 GMToplevel .showimage namePlot +$DPOSX+$DPOSY {} {} {}

		     focus .showimage
		     wm title .showimage $_gpParam(filename)
		     label .showimage.gnuplot -image $gnuplotImage
		     button .showimage.ok -text $TXT(ok) \
		         -command {destroy .showimage}
		     pack .showimage.gnuplot .showimage.ok -side top -pady 5
	     }
     }

     # temporary files in $USERTMPDIR will be deleted by gpsman when starting

}; # end gnuplot2d

#####
proc PCode_TRtoGnuplot3d {_tmp3D _tmp3D2 _trname\
                          _minalt _maxalt _datum} {
	                     
     global MESS TXT UNIX TERMCMD USERTMPDIR

     if { $UNIX && $TERMCMD == "" } {
	 GMMessage $MESS(defTERMCMD)
	 return
     }

     #  get settings for gnuplot
     global _gpParam

     # set default values
     array set _gpParam {
	width   800
	height  600
	direction gpForward
     }
     # setting output-filename
     set _gpParam(filename) "3D_chart_$_trname.png"

     # set up list of variables
     set vars {}
     foreach v {direction filename width height} {
	lappend vars _gpParam($v)
     }

     set descs [list\
		     "~$TXT(gpDirection)/[list gpForward gpBackward]"\
		     "=$TXT(gpFilename)"\
                     "=$TXT(gpCanwidth)"\
		     "=$TXT(gpCanheight)"]

     set mess $TXT(gpParam3d)
     while 1 {
	if { [GMChooseParams $mess $vars $descs] == 0 } { return }
	if { [CheckNumber GMMessage $_gpParam(width)] && \
	     [CheckNumber GMMessage $_gpParam(height)] } { break }
     }

     # rounding minalt
     set _minalt [expr round( [expr $_minalt / 100] ) * 100]
     # set minalt to even 200 factor
     if {($_minalt % 200) != 0} { set _minalt [expr $_minalt -100] }

     # up rounding maxalt for use in gnuplot-zrange, not used yet
     set _maxalt [expr round( [expr $_maxalt / 100 +1] ) * 100]

     # writing 3d data to two temporary datafile
     # the first file generates the color "curtain", the second file
     #  generates the 3d-line
     #    tmp3D contains lat, lon, datum
     #    tmp3D2 contains altitude
     # we need lat, lon, alt
     # then    lat, lon, min_alt
     set tmp_ [file join $USERTMPDIR gp_3d.tmp]
     set tmp_mod [file join $USERTMPDIR gp_3d_mod.tmp]
     set fh [open $tmp_ w]
     set fh2 [open $tmp_mod w]

     # initialise Transverse Mercator projection
     global ASKPROJPARAMS P3DData
     set oldask $ASKPROJPARAMS
     set ASKPROJPARAMS 0
     ProjInit TM P3DData $_datum $_tmp3D
     set ASKPROJPARAMS $oldask

     set lines [llength $_tmp3D]
     set els2 {}
     if { $_gpParam(direction) == "gpForward" } {
	 for {set i 0} {$i < $lines} {incr i} {
		set lat [lindex [lindex $_tmp3D $i] 0]
		set lon [lindex [lindex $_tmp3D $i] 1]
		set dat [lindex [lindex $_tmp3D $i] 2]
		set alt [lindex $_tmp3D2 $i]

		# convert position in lat/long signed degrees and given
		#  datum to TM coordinates
		# return [list $x $y]
		set p [ProjTMPoint P3DData $lat $lon $dat]
		set east [expr double([lindex $p 0])/1000 ]
		set north [expr double([lindex $p 1])/1000 ]
		set element [list $north $east $alt]
		lappend els2 [list $north $east $_minalt]

		puts $fh $element
		puts $fh2 $element
	 }
     } else {  
	 # backward, sometimes better display for overlaps
	 set lines [expr $lines-1]
	 for {set i $lines} {$i > 0 } {incr i -1} {
		set lat [lindex [lindex $_tmp3D $i] 0]
		set lon [lindex [lindex $_tmp3D $i] 1]
		set dat [lindex [lindex $_tmp3D $i] 2]
		set alt [lindex $_tmp3D2 $i]

		# convert position in lat/long signed degrees and given
		#  datum to TM coordinates
		# return [list $x $y]
		set p [ProjTMPoint P3DData $lat $lon $dat]
		set east [expr double([lindex $p 0])/1000 ]
		set north [expr double([lindex $p 1])/1000 ]
		set element [list $north $east $alt]
		lappend els2 [list $north $east $_minalt]

		puts $fh $element
		puts $fh2 $element
	 }
     }

     puts $fh2 ""

     foreach element $els2 {
	 puts $fh2 $element
     }
     close $fh
     close $fh2

     #  search for all Waypoints in corresponding group 
     #
     global GRConts WPPosn WPDatum WPAlt

     set wpns "";  # list of waypoints

     # look for the ID of groupname == trackname
     if { ( $_trname != "" && \
		[set ix [IndexNamed GR $_trname]] != -1 ) || \
	      [set ix [ChooseItems GR single]] != "" } {
	 # look for wp in group
	 foreach p $GRConts($ix) {
	     if { [lindex $p 0] == "WP" } {
		 set wpns [lindex $p 1]
		 break
	     }
	 }
     }

     # handle waypoints
     # write waypoints to temporary datafile
     set tmp_wp [file join $USERTMPDIR gp_3d_wp.tmp]
     set fh [open $tmp_wp w]
     set foundwp 0
     while { $wpns != "" } {
	 # when wpns exist look for waypoint-index wpix 
	 while { $wpns != "" && \
		   [set wpix [IndexNamed WP [lindex $wpns 0]]] == -1 } {
	     GMMessage [format $MESS(undefinedWP) [lindex $wpns 0]]
	     set wpns [lreplace $wpns 0 0]
	 }

	 set wpname [lindex $wpns 0]

	 # get lat and lon
	 set lat [lindex $WPPosn($wpix) 0]
	 set lon [lindex $WPPosn($wpix) 1]
	 set wp_alt [lindex $WPAlt($wpix) 0]
	 set wp_alt [UserAltitude $wp_alt]

	 if { [set alt $wp_alt] == "" } {
	     set alt $_minalt
	 }
	 set dat $WPDatum($wpix)

	 set p [ProjTMPoint P3DData $lat $lon $dat]
	 set east [expr double([lindex $p 0])/1000 ]
	 set north [expr double([lindex $p 1])/1000 ]

	 puts $fh [list $north $east $alt $wpname]

	 set wpns [lreplace $wpns 0 0];  # removes first element
	 set foundwp 1
     }

     close $fh

     # writing gnuplot scriptfile
     set tmp_script [file join $USERTMPDIR gp_3d_script.plt]
     set fh [open $tmp_script w]

     puts $fh {# gnuplot scriptfile created by GPSMan}
     puts $fh {reset}
     puts $fh {set lmargin 8}
     puts $fh "set title \"$_trname\" "
     puts $fh "set xlabel '$TXT(easting)'"
     puts $fh "set ylabel '$TXT(northing)'"
     puts $fh "set zlabel '$TXT(alt)'"
     puts $fh "set label 1 '$TXT(gpGenerated)' at screen 0.98,screen 0.02 right front"

     # use same scaling for 2Dmap, badly don't work in Linux with gnuplot ver 4.2
     #puts $fh {set view equal xy}

     # changing of colors
     # set palette rgbformulae 7,5,15
     #puts $fh {set palette defined ( 0 "black", 1 "blue", 2 "green", 3 "red", 4 "orange" )}
     puts $fh {set palette defined ( 0 "black", 1 "blue", 2 "red", 3 "orange", 4 "yellow" )}

     # puts $fh {set datafile separator ","}
     puts $fh {set xyplane 0}
     puts $fh {set grid}
     puts $fh {unset hidden3d}
     puts $fh {set pm3d}
     puts $fh {set pm3d corners2color max}
     if { $foundwp } {
	 puts $fh "splot '$tmp_mod' using 2:1:3 with points pointtype -1 notitle,\
		  '$tmp_' using 2:1:3 with lines linetype 8 linewidth 2  notitle,\
		  '$tmp_wp' using 2:1:3:4 with labels left rotate point pt 9 offset 0,0.5 notitle"
     } else {
	 # no waypoints
	 puts $fh "splot '$tmp_mod' using 2:1:3 with points pointtype -1 notitle,\
		  '$tmp_' using 2:1:3 with lines linetype 8 linewidth 2 notitle"
     }

     puts $fh "pause -1 '$TXT(gpModify)'"
     #   the pause command don't work well with Linux. You have to quit gnuplot
     #   within the xterm that startet gpsman.
     #   Normally you don't look at the xterm and gnuplot will not be closed.
     #   Within windows gnupot-pause opens a new messagebox for closing-command.
     #   We must use pause to change the viewing


     #  create outputfile, no display on screen
     puts $fh "set terminal png size $_gpParam(width),$_gpParam(height)"
     puts $fh "set output \"$_gpParam(filename)\""
     puts $fh replot

     close $fh

     # start gnuplot
     if { $UNIX } {
	 # start xterminal to get the gnuplot-pause-message
	 # the commandname depends on the linux version
	 exec $TERMCMD -e gnuplot $tmp_script &
     } else {
	 exec gnuplot $tmp_script &
     }

     DisplayInfo [format $MESS(gpModgnuplot) $_gpParam(filename)]

     if { $UNIX } {
	 DisplayInfo $MESS(gpQuitgnuplot)
     }

     # temporary files in $USERTMPDIR will be deleted by gpsman when starting

}; # end gnuplot3d

# end of RM contribution


