########################################################################
#                                                                      #
#     Drawing Graph for Swumsuit                                       #
#                                                since 2005.1.18       #
#                                                (c) Motomu Nakashima  #
########################################################################

# Draw graph
proc DrawGraph { filename } {
    global gnum flag_dim
    set flag_dim($gnum) 0

    # load titles, etc.
    if {[file exists Output_data/$filename]==0} {
        global No_data_file
        tk_messageBox -type ok -message $No_data_file \
                      -icon error
        return
    }

    toplevel .graph$gnum
    wm title .graph$gnum "Swumsuit: Graph"

    set f [open Output_data/$filename r]
    if {$f==""} { return }
    foreach e {title xtitle ytitle ynum datatitle xdim ydim xunit yunit} {
        gets $f line
        set line [string trim $line]
        set $e [string trim [string range $line 1 end]]
    }

    # make data list for x
    set x ""
    while {[gets $f line]>=0} {
        set x "$x [lindex $line 0]"
    }
    close $f
    
    # make data list(s) for y
    set data "\{ $x \}"
    for {set i 1} {$i<=$ynum} {incr i} {
        set f [open Output_data/$filename r]
        for {set j 1} {$j<=9} {incr j} {gets $f line}
        set y($i) ""
        while {[gets $f line]>=0} {
            set y($i) "$y($i) [lindex $line $i]"
        }
        close $f
        set data "$data \{ $y($i) \} "
    }
    set dataorg $data

    # BLT setup
    package require BLT
    catch { namespace import blt::* }
    graph .graph$gnum.blt -width 3.5i -height 3i -relief groove \
         -plotborderwidth 2 -plotbackground "\#ffffff" -bd 2
    global orggraphbackcolor
    set orggraphbackcolor [.graph$gnum.blt cget -background]
    bind .graph$gnum.blt <ButtonPress-1> {FindClosestPoint %x %y %W}
    bind .graph$gnum.blt <Motion> {FindClosestPoint %x %y %W}
    #bind .graph$gnum.blt <Enter>  {EnterPlottingArea %W}
    #bind .graph$gnum.blt <Leave>  {LeavePlottingArea %W}
 
    # create pens
    global Platform
    if {$Platform=="windows"} {
        .graph$gnum.blt pen create pen1 -symbol "" \
                  -color blue
        .graph$gnum.blt pen create pen2 -symbol "" \
                  -color red    -dashes { 3 1 }
        .graph$gnum.blt pen create pen3 -symbol "" \
                  -color green  -dashes { 1 1 1 1 }
        .graph$gnum.blt pen create pen4 -symbol "" \
                  -color cyan   -dashes { 3 1 1 1 }
        .graph$gnum.blt pen create pen5 -symbol "" \
                  -color magenta -dashes { 3 1 1 1 1 1 }
    } else {
        .graph$gnum.blt pen create pen1 -symbol "" \
                  -color blue
        .graph$gnum.blt pen create pen2 -symbol "" \
                  -color red    -dashes { 10 3 }
        .graph$gnum.blt pen create pen3 -symbol "" \
                  -color green  -dashes { 3 3 3 3 }
        .graph$gnum.blt pen create pen4 -symbol "" \
                  -color cyan   -dashes { 10 3 3 3 }
        .graph$gnum.blt pen create pen5 -symbol "" \
                  -color magenta -dashes { 10 3 3 3 3 3 }
    }

    # draw graph
    for {set i 1} {$i<=$ynum} {incr i} {
        .graph$gnum.blt element create line$i \
           -xdata $x -ydata $y($i) -pixels 2 \
           -label [lindex $datatitle [expr $i-1]] \
           -pen pen$i
    }

    # configure graph
    .graph$gnum.blt configure -title $title
    .graph$gnum.blt axis configure x -title $xtitle
    .graph$gnum.blt axis configure y -title $ytitle
    if {$ynum>=2} { .graph$gnum.blt configure -width 5i }

    # panel
    frame .graph$gnum.p
    global dimension
    checkbutton .graph$gnum.p.dim -text $dimension \
              -variable flag_dim($gnum) -onvalue 1 -offvalue 0
    bind .graph$gnum.p.dim <ButtonPress-1> "ChangeGraphDimension $gnum $ynum {$datatitle} {$data} {$dataorg} {$xdim} {$ydim} {$xtitle} {$ytitle} {$xunit} {$yunit}"

    global Output Close
    button .graph$gnum.p.output -text $Output -command \
    "tk_popup .outputmenu$gnum \[winfo pointerx .\] \[expr \[winfo pointery .\]+5\]"
    menu .outputmenu$gnum -tearoff false
    global Display_text_data Clipboard WMF EMF EPS
    .outputmenu$gnum add command -label $Clipboard \
      -command "OutputGraph .graph$gnum.blt $filename Clipboard"
    .outputmenu$gnum add command -label $WMF \
      -command "OutputGraph .graph$gnum.blt $filename WMF"
    .outputmenu$gnum add command -label $EMF \
      -command "OutputGraph .graph$gnum.blt $filename EMF"
    .outputmenu$gnum add command -label $EPS \
      -command "OutputGraph .graph$gnum.blt $filename EPS"
    .outputmenu$gnum add separator
    .outputmenu$gnum add command -label $Display_text_data \
      -command "OutputGraph .graph$gnum.blt $filename Display_text_data"
    button .graph$gnum.p.close  -text $Close \
                                 -command "destroy .graph$gnum"
    # for range setting
    global Range
    button .graph$gnum.p.range  -text $Range \
                    -command "PopupGraphRange $gnum"
    global graph_xstart graph_xend graph_ystart graph_yend
    set graph_xstart($gnum) ""
    set graph_xend($gnum)   ""
    set graph_ystart($gnum) ""
    set graph_yend($gnum)   ""

    # for sync animation
    global Sync_anim
    checkbutton .graph$gnum.p.sa -variable syncanim($gnum) \
        -text "$Sync_anim"
    # disable when the quantity is "for per cycle"
    if {$filename=="swimming_speed.dat"||$filename=="stroke_length.dat"||$filename=="direction.dat"||$filename=="power_efficiency1.dat"||$filename=="power_efficiency2.dat"||$filename=="input_power.dat"||$filename=="output_power1.dat"||$filename=="output_power2.dat"} {
        .graph$gnum.p.sa configure -state disabled
    } else {
        # bind to enter loop
        bind .graph$gnum.p.sa <ButtonPress-1> \
            "ChangeSyncGraph $gnum $xdim"
    }

    # packing
    pack .graph$gnum.p.dim \
         .graph$gnum.p.sa \
         .graph$gnum.p.range \
              -expand 0 -pady 5 -padx 5 -side left
    pack .graph$gnum.p.output -side left
    pack .graph$gnum.p.close -side right -padx 10

    pack .graph$gnum.blt -side top -fill both -expand 1
    pack .graph$gnum.p -side top -fill x -anchor s

    # read & draw time (sync animation)
    set time -1000.0
    .graph$gnum.blt marker create line -name line0 \
        -coords { $time -Inf $time Inf } -outline red -linewidth 2

    ChangeIcon .graph$gnum
    incr gnum
}


# Change sync graph
proc ChangeSyncGraph { gnum xdim } {
    global syncanim
    if {$syncanim($gnum)=="0"} { 
        after 500 DrawTime $gnum $xdim
    }
}


# Loop to draw time (sync animation)
proc DrawTime { gnum xdim } {
    global syncanim flag_dim
    set time -1000.0
    catch {
        set openfile [open "time_sync.dat" r]
        gets $openfile time
        close $openfile
        if {$flag_dim($gnum)=="0"} {
        # non-dimensional case
            .graph$gnum.blt marker configure line0 \
                -coords { $time -Inf $time Inf } 
        } else {
        # dimensional case
            set time [expr $time * $xdim]
            .graph$gnum.blt marker configure line0 \
                -coords { $time -Inf $time Inf } 
        }
    }
    update
    if {$syncanim($gnum)=="0"} { 
        # exit loop
        set time -1000.0
        .graph$gnum.blt marker configure line0 \
            -coords { $time -Inf $time Inf } 
    } else { 
        # call myself (re-enter loop)
        after 150 DrawTime $gnum $xdim
    }
}


# Change Graph Dimension
proc ChangeGraphDimension {gnum ynum datatitle data dataorg xdim ydim xtitle ytitle xunit yunit} {
    global flag_dim
    set x [lindex $data 0]
    for {set i 1} {$i<=$ynum} {incr i} {
        set y($i) [lindex $data $i]
    }

    # if button is pressed when flag_dim is 0
    if {$flag_dim($gnum)==0} {
        set xd ""
        foreach e $x {
            set xd "$xd [expr $e*$xdim]"
        }

        for {set i 1} {$i<=$ynum} {incr i} {
            set yd ""
            foreach e $y($i) {
                set yd "$yd [expr $e*$ydim]"
            }
            # draw graph
            .graph$gnum.blt element configure line$i \
               -xdata $xd -ydata $yd \
               -label [lindex $datatitle [expr $i-1]]
            .graph$gnum.blt axis configure x -title "$xtitle $xunit"
            .graph$gnum.blt axis configure y -title "$ytitle $yunit"
        }

        # change xmin and xmax
        global graph_xstart graph_xend
        if {$graph_xstart($gnum)!=""} {
            set graph_xstart($gnum) [expr $graph_xstart($gnum)*$xdim]
        }
        if {$graph_xend($gnum)!=""} {
            set graph_xend($gnum) [expr $graph_xend($gnum)*$xdim]
        }
        .graph$gnum.blt axis configure x -min $graph_xstart($gnum) \
                                         -max $graph_xend($gnum)

        # change ymin and ymax
        global graph_ystart graph_yend
        if {$graph_ystart($gnum)!=""} {
            set graph_ystart($gnum) [expr $graph_ystart($gnum)*$ydim]
        }
        if {$graph_yend($gnum)!=""} {
            set graph_yend($gnum) [expr $graph_yend($gnum)*$ydim]
        }
        .graph$gnum.blt axis configure y -min $graph_ystart($gnum) \
                                         -max $graph_yend($gnum)

    # if button is pressed when flag_dim is 1
    } else {

        #set dataorg [lindex $dataorg 0]
        set x [lindex $dataorg 0]
        for {set i 1} {$i<=$ynum} {incr i} {
             set y($i) [lindex $data $i]
            .graph$gnum.blt element configure line$i \
               -xdata $x -ydata $y($i)
            .graph$gnum.blt axis configure x -title $xtitle
            .graph$gnum.blt axis configure y -title $ytitle
        }

        # change xmin and xmax
        global graph_xstart graph_xend
        if {$graph_xstart($gnum)!=""} {
            set graph_xstart($gnum) [expr $graph_xstart($gnum)/$xdim]
        }
        if {$graph_xend($gnum)!=""} {
            set graph_xend($gnum) [expr $graph_xend($gnum)/$xdim]
        }
        .graph$gnum.blt axis configure x -min $graph_xstart($gnum) \
                                         -max $graph_xend($gnum)

        # change ymin and ymax
        global graph_ystart graph_yend
        if {$graph_ystart($gnum)!=""} {
            set graph_ystart($gnum) [expr $graph_ystart($gnum)/$ydim]
        }
        if {$graph_yend($gnum)!=""} {
            set graph_yend($gnum) [expr $graph_yend($gnum)/$ydim]
        }
        .graph$gnum.blt axis configure y -min $graph_ystart($gnum) \
                                         -max $graph_yend($gnum)

    }
}


# Output graph
proc OutputGraph { w filename option } {
    global Platform sourcedir orggraphbackcolor
    if {$option=="Display_text_data"} {
        # Create window
        set wd $w.data
        if {[winfo exists $wd]==0} {
            toplevel $wd
            wm title $wd "Swumsuit: Graph Text data ($filename)"
            
            frame $wd.ft
            text  $wd.ft.t -xscrollcommand "$wd.ft.h set" \
                            -yscrollcommand "$wd.ft.v set" -wrap none 
            scrollbar $wd.ft.h -orient horizontal \
                                -command "$wd.ft.t xview" 
            scrollbar $wd.ft.v -orient vertical \
                                -command "$wd.ft.t yview"
            grid $wd.ft.t -row 0 -column 0 -sticky nsew
            grid $wd.ft.h -row 1 -column 0 -sticky ew
            grid $wd.ft.v -row 0 -column 1 -sticky ns
            grid rowconfigure    $wd.ft  0 -weight 100
            grid columnconfigure $wd.ft  0 -weight 100

            # panel
            frame $wd.p
            global Select_all Select_data_part_only Copy_to_clipboard Close
            button $wd.p.s -text $Select_all \
               -command "$wd.ft.t tag remove sel 1.0 end ; focus $wd.ft.t ; $wd.ft.t tag add sel 1.0 end"
            button $wd.p.d -text $Select_data_part_only \
               -command "$wd.ft.t tag remove sel 1.0 end ; focus $wd.ft.t ; $wd.ft.t tag add sel 10.0 end"
            button $wd.p.o -text $Copy_to_clipboard -command "tk_textCopy $wd.ft.t"
            button $wd.p.c -text $Close -command "wm withdraw $wd"
            pack $wd.p.s $wd.p.d $wd.p.o $wd.p.c \
                -side left -padx 20 -pady 10 -expand 1

            pack $wd.ft -fill both -expand 1
            pack $wd.p

            ChangeIcon $wd
        } else {
            wm deiconify $wd
        }

        # Clear text widget
        $wd.ft.t configure -state normal
        $wd.ft.t delete 1.0 end

        # Load data
        set f [open Output_data/$filename r]
        $wd.ft.t insert end [read $f]
        close $f
        $wd.ft.t configure -state disabled

    } elseif {$option=="Clipboard"} {
        if {$Platform!="windows"} { return }
        $w configure -background "\#ffffff" \
               -plotbackground "\#f0f0f0" -plotborderwidth 0 -relief flat
        $w legend configure -borderwidth 0
        $w snap -format wmf CLIPBOARD
        $w configure -background $orggraphbackcolor \
            -plotbackground "\#ffffff" -plotborderwidth 2 -relief groove
        $w legend configure -borderwidth 2
        global Outputted_to_clipboard
        tk_messageBox -type ok -message $Outputted_to_clipboard

    } elseif {$option=="WMF"} {
        if {$Platform!="windows"} { return }
        set f [tk_getSaveFile -initialdir [pwd] \
                   -filetypes { {"Windows Meta File" {.wmf}} \
                                {"All files" *} } ]
        if {$f==""} { return }
        if {[string range $f end-3 end]!=".wmf"} {
            set f "$f.wmf"
        }
        $w configure -background "\#ffffff" \
             -plotbackground "\#f0f0f0" -plotborderwidth 0 -relief flat
        $w legend configure -borderwidth 0
        $w snap -format wmf $f
        $w configure -background $orggraphbackcolor \
            -plotbackground "\#ffffff" -plotborderwidth 2 -relief groove
        $w legend configure -borderwidth 2

    } elseif {$option=="EMF"} {
        if {$Platform!="windows"} { return }
        set f [tk_getSaveFile -initialdir [pwd] \
                   -filetypes { {"Enhanced Meta File" {.emf}} \
                                {"All files" *} } ]
        if {$f==""} { return }
        if {[string range $f end-3 end]!=".emf"} {
            set f "$f.emf"
        }
        $w configure -background "\#ffffff" \
              -plotbackground "\#f0f0f0" -plotborderwidth 0 -relief flat
        $w legend configure -borderwidth 0
        $w snap -format emf $f
        $w configure -background $orggraphbackcolor \
            -plotbackground "\#ffffff" -plotborderwidth 2 -relief groove
        $w legend configure -borderwidth 2

    } elseif {$option=="EPS"} {
        set f [tk_getSaveFile -initialdir [pwd] \
                -filetypes { {"Encapsulated Postscript File" {.eps}} \
                                {"All files" *} } ]
        if {$f==""} { return }
        if {[string range $f end-3 end]!=".eps"} {
            set f "$f.eps"
        }
        $w configure -background "\#ffffff" \
                -plotbackground "\#f0f0f0" -plotborderwidth 0
        $w legend configure -borderwidth 0

        $w pen configure pen2 -dashes { 10 3 }
        $w pen configure pen3 -dashes { 3 3 3 3 }
        $w pen configure pen4 -dashes { 10 3 3 3 }
        $w pen configure pen5 -dashes { 10 3 3 3 3 3 }

        $w postscript output $f -decorations 0

        $w pen configure pen2 -dashes { 3 1 }
        $w pen configure pen3 -dashes { 1 1 1 1 }
        $w pen configure pen4 -dashes { 3 1 1 1 }
        $w pen configure pen5 -dashes { 3 1 1 1 1 1 }

        $w configure -background $orggraphbackcolor \
                 -plotbackground "\#ffffff" -plotborderwidth 2
        $w legend configure -borderwidth 2

    } else {
    }
}


# Find closest point
proc FindClosestPoint {x y w} {

    # make point element
    if {[$w element exists cp]==0} {
        $w element create cp -label "" -pixels 4
    }

    # make point element
    if {[winfo exists $w.cp]==0} {
        label $w.cp -text ""  -highlightcolor black \
                -bd 1 -highlightthickness 1 -highlightbackground black
    }

    # find the closest point
    if {[$w element closest $x $y results -halo 20]==1} {
        set xg $results(x)
        set yg $results(y)

        # plot the point
        $w element configure cp -xdata $xg -ydata $yg

        # get x,y values at the point
        set xlist [$w element cget $results(name) -xdata]
        set ylist [$w element cget $results(name) -ydata]
        set xcp [lindex $xlist $results(index)]
        set ycp [lindex $ylist $results(index)]
        set xcp [string range $xcp 0 6]
        set ycp [string range $ycp 0 6]
        
        # change label
        $w.cp configure -text "( $xcp , $ycp )"
        
        # locate label
        set xp [winfo pointerx .]
        set yp [winfo pointery .]
        set x0 [winfo rootx $w]
        set y0 [winfo rooty $w]
        set xdcp [expr $xp-$x0+5] 
        set ydcp [expr $yp-$y0+5]
        set wgraph [winfo width $w]
        set wlabel [winfo width $w.cp]
        if {[expr $xdcp+$wlabel]>=$wgraph} {
            place $w.cp -x [expr $wgraph-$wlabel] -y $ydcp
        } else {
            place $w.cp -x $xdcp -y $ydcp
        }
        raise $w.cp

    } else {
        $w element configure cp -xdata "" -ydata ""
        destroy $w.cp
    }
}


# Popup range window
proc PopupGraphRange { gnum } {
    global graph_xstart graph_xend graph_ystart graph_yend

    if {[winfo exists .graph$gnum.r]==0} {
        toplevel .graph$gnum.r
        wm title .graph$gnum.r "Swumsuit: range setting"

        frame  .graph$gnum.r.x -bd 2 -relief groove
        frame  .graph$gnum.r.y -bd 2 -relief groove
        frame  .graph$gnum.r.p

        entry  .graph$gnum.r.x.e1 -width 8 \
                                  -textvariable graph_xstart($gnum)
        entry  .graph$gnum.r.x.e2 -width 8 \
                                  -textvariable graph_xend($gnum)
        global Abscissa_range
        label  .graph$gnum.r.x.l1 -text "$Abscissa_range :"
        label  .graph$gnum.r.x.l2 -text "-"
        pack   .graph$gnum.r.x.l1 \
               .graph$gnum.r.x.e1 \
               .graph$gnum.r.x.l2 \
               .graph$gnum.r.x.e2 \
                       -side left

        entry  .graph$gnum.r.y.e1 -width 8 \
                                  -textvariable graph_ystart($gnum)
        entry  .graph$gnum.r.y.e2 -width 8 \
                                  -textvariable graph_yend($gnum)
        global Ordinate_range
        label  .graph$gnum.r.y.l1 -text "$Ordinate_range :"
        label  .graph$gnum.r.y.l2 -text "-"
        pack   .graph$gnum.r.y.l1 \
               .graph$gnum.r.y.e1 \
               .graph$gnum.r.y.l2 \
               .graph$gnum.r.y.e2 \
                   -side left

        global OK Cancel
        button .graph$gnum.r.p.ok -text $OK \
                 -command "ChangeGraphRange $gnum"
        button .graph$gnum.r.p.cancel -text $Cancel \
                 -command "wm withdraw .graph$gnum.r"
        pack .graph$gnum.r.p.ok \
             .graph$gnum.r.p.cancel \
                 -side left -padx 10 -pady 10 -expand 1

        pack .graph$gnum.r.x \
             .graph$gnum.r.y \
             .graph$gnum.r.p \
                 -side top

        ChangeIcon .graph$gnum.r

    } else {
        wm deiconify .graph$gnum.r
    }

    # get present min & max values from graph
    set graph_xstart($gnum) [.graph$gnum.blt axis cget x -min]
    set graph_xend($gnum)   [.graph$gnum.blt axis cget x -max]
    set graph_ystart($gnum) [.graph$gnum.blt axis cget y -min]
    set graph_yend($gnum)   [.graph$gnum.blt axis cget y -max]
    
}


# Change graph range
proc ChangeGraphRange { gnum } {
    global graph_xstart graph_xend graph_ystart graph_yend
    .graph$gnum.blt axis configure x -min $graph_xstart($gnum) \
                                     -max $graph_xend($gnum)
    .graph$gnum.blt axis configure y -min $graph_ystart($gnum) \
                                     -max $graph_yend($gnum)
    wm withdraw .graph$gnum.r
}


# Initialize
set gnum 1
