# copyright (C) 1997-2006 Jean-Luc Fontaine (mailto:jfontain@free.fr)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

# $Id: databar.tcl,v 2.40 2006/01/28 19:16:59 jfontain Exp $


class dataBarChart {

    set (plotBackground) $widget::option(button,background)
    set (list) {}

    proc dataBarChart {this parentPath noMinimum args} composite {[new frame $parentPath] $args} blt2DViewer {
        $widget::($this,path) [blt::barchart $widget::($this,path).bar -title {} -bottommargin 6 -plotbackground $(plotBackground)]
        0 $noMinimum
    } {
        if {$noMinimum} {set ($this,noMinimum) {}}
        set path $widget::($this,path).bar
        $path grid off                                                                                      ;# grid is on by default
        $path xaxis configure -hide 1; $path yaxis configure -hide 1
        set ($this,path) $path
        composite::complete $this
        lappend (list) $this                                 ;# remember bar charts in order to be able to globally set some options
        # display help message after object is completely constructed for the message virtual procedure to work:
        after idle "dataBarChart::updateMessage $this"
    }

    proc ~dataBarChart {this} {
        ldelete (list) $this
        if {[string length $composite::($this,-deletecommand)]>0} {
            uplevel #0 $composite::($this,-deletecommand)                                   ;# always invoke command at global level
        }
    }

    proc options {this} {
        # force size values
        return [list\
            [list -cellcolors {} {}]\
            [list -deletecommand {} {}]\
            [list -draggable 0 0]\
            [list -height $global::viewerHeight]\
            [list -labelsposition right]\
            [list -mode normal normal]\
            [list -width $global::viewerWidth]\
            [list -ymaximum {} {}]\
            [list -ymaximumcell {} {}]\
            [list -yminimum $global::graphMinimumY]\
            [list -yminimumcell {} {}]\
        ]
    }

    proc set-cellcolors {this value} {                             ;# colors of soon to be created cells when initializing from file
        if {$composite::($this,complete)} {
            error {option -cellcolors cannot be set dynamically}
        }
        blt2DViewer::setCellColors $this $value
    }

    proc set-deletecommand {this value} {}

    foreach option {-height -width} {
        proc set$option {this value} "\$widget::(\$this,path) configure $option \$value"
    }

    proc set-draggable {this value} {
        if {$composite::($this,complete)} {
            error {option -draggable cannot be set dynamically}
        }
        if {$value} {
            blt2DViewer::allowDrag $this
        }
    }

    proc set-mode {this value} {
        $($this,path) configure -barmode $value
    }

    proc set-labelsposition {this value} {
        blt2DViewer::updateLayout $this
    }

    proc set-ymaximum {this value} {
        blt2DViewer::setLimit $this maximum $value
    }
    proc set-ymaximumcell {this value} {
        blt2DViewer::setLimitCell $this maximum $value
    }
    proc set-yminimum {this value} {
        if {[info exists ($this,noMinimum)]} return                                   ;# minimum limits useless when fixed 0 minimum
        blt2DViewer::setLimit $this minimum $value
    }
    proc set-yminimumcell {this value} {
        if {[info exists ($this,noMinimum)]} return                                   ;# minimum limits useless when fixed 0 minimum
        blt2DViewer::setLimitCell $this minimum $value
    }

    proc newElement {this path args} {                                                          ;# invoked from 2D viewer base class
        return [eval new element $path $args]
    }

    virtual proc updateElement {this element seconds value} {                   ;# value is either a valid number or the ? character
        if {[string equal $value ?]} {                                                                          ;# handle void value
            element::update $element 0
        } else {
            element::update $element $value
        }
    }

    proc modified {this monitored} {                                                                    ;# number of monitored cells
        $($this,path) yaxis configure -hide [expr {$monitored == 0}]                               ;# hide if no elements to display
        updateMessage $this
    }

    proc updateMessage {this} {
        # viewer may have been immediately deleted after construction when a cell of an invalid type was dropped:
        if {[catch {classof $this}]} return
        if {[llength [blt2DViewer::cells $this]] == 0} {
            centerMessage $widget::($this,path) [message $this] $(plotBackground) $global::viewerMessageColor
        } else {
            centerMessage $widget::($this,path) {}
        }
    }

    virtual proc message {this}

    proc initializationConfiguration {this} {
        if {[info exists ($this,noMinimum)]} {                                        ;# minimum limits useless when fixed 0 minimum
            set list {}
        } else {
            set list [list -yminimum $composite::($this,-yminimum) -yminimumcell $composite::($this,-yminimumcell)]
        }
        return [concat\
            [list\
                -ymaximum $composite::($this,-ymaximum) -ymaximumcell $composite::($this,-ymaximumcell)\
                -labelsposition $composite::($this,-labelsposition)\
            ] $list [blt2DViewer::_initializationConfiguration $this]\
        ]
    }

}

class dataBarChart {

    class element {

        proc element {this path args} switched {$args} {
            $path element create $this -label {} -borderwidth 1 -xdata 0              ;# use object identifier as element identifier
            set ($this,path) $path
            switched::complete $this
        }

        proc ~element {this} {
            $($this,path) element delete $this
            if {[string length $switched::($this,-deletecommand)]>0} {
                uplevel #0 $switched::($this,-deletecommand)                                ;# always invoke command at global level
            }
        }

        proc options {this} {
            return [list\
                [list -color black black]\
                [list -deletecommand {} {}]\
            ]
        }

        proc set-color {this value} {
            $($this,path) element configure $this -foreground $value
        }

        proc set-deletecommand {this value} {}                                                   ;# data is stored at switched level

        proc update {this y} {                                                      ;# y is either a valid number or the ? character
            $($this,path) element configure $this -ydata $y
        }

    }

}

class dataSideBarChart {

    proc dataSideBarChart {this parentPath args} dataBarChart {$parentPath 0 $args} {
        composite::configure $this -mode aligned
    }

    proc ~dataSideBarChart {this} {}

    proc iconData {} {
        return {
            R0lGODdhJAAkAMYAAPj4+Hh4ePj8+DBgGHh8eKDweAAAAJjscJjkcJDgaJDcaIjYaIjUYIDMYIDEWHjAWHi8WHBIAHC4UOjUSHC0UODMQGisSNjEQNjASGCk
            SNC4SGCgQMiwSFiYQMioSFiYOMCgSFiQOLiYSFCMOLiQSICEgFCIMLCMSBBgeIiQiEiEMKiESMDQ2JCYkEiAKKh8SKjA0KCkoEB4KKB0SJC0wKisqJhsSLi8
            uEBwIJhkSHiouMDEwDhsIJBcSGCYsMjQyNDY0ODk4Ojs6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAJAAkAAAH/oAAgoOCAYSHhoeDiYWKhIyKkIiPhAIDl5iZk44AkIkBAQQDBaSlpAMG
            oKqrrK2ggpYHsrOyAwSUnJ6VAwi9vr22uI66g5YJx8jHwYucnbigogrS09KorteusAML3N3cy425wgCWDObn5uDO4szFAw3w8fDqkuOfoe/y8dbY/a/kAxwI
            HCiQXjNi2h4oXKhQHQEB7MJpg0CxIsUBETJq3LgpHLQBEkKKDIlxgsmTJiOk8qeNgsuXLjFWmElzZoRb7SQCtMCzJ0+MF4IKDXoTok5Ilnz6xIihqdOmRXOu
            +5ihqtWqGDVo3apVJQGWADeIHSsWI4ezaM/etLerg9u3/m4xephLd+5aqUgHfNjLdy9GEIADA456VJCBwwNCKF6sGKOIx5AfqzxMuTJlApgHjNjMeTNGEqBD
            g76JubTp0iVSDzDBujVrjCdiy44dAYXt27hTl0jBe4CK38B/Y1xBvDjx2iySK0+OggDvFtAHuJhOfTrGF9izY68No7v37s2hxxg/QIb58+YxzljPfn1tGvDj
            w28+vob98ujPY7TBvz//9/LF15x9NxQ4AA4IJoggRjk06GCDtekg4YQSNlfgDhgOwMOGHG6IUQ8ghghibT6UaGKJzWH4w4qZtIjRRjDiJmNzKwJhIxCn5ajj
            jqbZGMSPQAYp5JBEFinEkUgmB6nkkkw2GQgAOw==
        }
    }

    proc message {this} {
        return [mc "side bar chart:\ndrop data cell(s)"]
    }

}

class dataStackedBarChart {

    proc dataStackedBarChart {this parentPath args} dataBarChart {$parentPath 1 $args} {
        composite::configure $this -mode stacked
    }

    proc ~dataStackedBarChart {this} {}

    proc iconData {} {
        return {
            R0lGODdhJAAkAKUAAPj4+Hh4eHh8eDBgGPj8+KjweAAAAJjkcJDYaIjMYIDAWDg4OHi0UGioSGCgQFiUOHBIAPDYSOjMQODESNi4SNCwSMioSMCcSLiUSLCI
            SBBgeLDY6KDQ4ICEgJDE2IiQiIi80JCYkHi0yKCkoHCswKisqGCguLi8uFiYsMDEwEiQqMjQyNDY0ODk4Ojs6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAJAAkAAAG/kCAcCgMEI/G4zBZVBKZSiiSKFAOrtisdrsFEKqAgFgwKJjP6LQaPTAIBOIhYXCo2+/4/H0g
            +B7nCIGCg4SFg3x+RHMJjI2Oj5COAwFfBGFjAwqam5ydnpwDC29wcgMMp6ipqqupk5WKAw2ys7S1trSufbAOvL2+v8C+uZZiAWQPyMnKy8zKoaNMBBDT1NXW
            19eUunIQEd7f4OHi4BDaltwS6err7O3r5a/FAhAT9fb3+Pn3EKJv0RAUAgocSLDgQHjbhEirwLChw4cQHSI8pxCChYsYM2rcmHHipTcQLogcSbKkSZL8oHHD
            wLKly5cwXXrklqGmzZs4c96cqVCDv8+fQIMKFWoOgIGjBjRsWMq0qdOnTTUgPTpKgAYOWLNq3cpVq4aqAjqI7aDBg9mzaNOqRft1bIcPcD9oAEG3rt27eO1+
            jfshhN8QGkQIHky4sGHCX/+GGMF4hAYSkCNLnkxZ8tfGI0poLqHBhOfPoEOLBv11c4kTqE9oQMG6tevXsF1/TX0ihe0UGlTo3s27t2/eX2+nWEF8xdDjyH8K
            KL6ChXPnYKNLny7gOYsW2LNr3869u3cX4MOLH0++vPkgADs=
        }
    }

    proc updateElement {this element seconds value} {                           ;# value is either a valid number or the ? character
        if {[string equal $value ?]} {                                                                          ;# handle void value
            dataBarChart::element::update $element 0
        } else {
            dataBarChart::element::update $element [expr {abs($value)}]                             ;# negative values make no sense
        }
    }

    proc message {this} {
        return [mc "stacked bar chart:\ndrop data cell(s)"]
    }

}

class dataOverlapBarChart {

    proc dataOverlapBarChart {this parentPath args} dataBarChart {$parentPath 0 $args} {
        composite::configure $this -mode overlap
    }

    proc ~dataOverlapBarChart {this} {}

    proc iconData {} {
        return {
            R0lGODdhJAAkAMYAAPj4+Hh4ePj8+DBgIHh8eKDweAAAAJjscJjocJDgcJDgaIjYaIjUaIDQYIDMYIDIYHjEWHjAWHBIAHC8WOjQQHC0UODIQGiwUNjEQNi8
            QGCoSNC0QGCkSMisQFigQMikQFicQMCgQFiYQLiYQFCQOLiQQICEgLCIQBBgeIiQiEiMOKiAQLjI0JCYkEiEMKh8QKCkoECAMKB0QKC4yKisqEB8MJhsQIio
            uLi8uEB4KJhkQMDEwDh0KJBcQHCgsMjQyODk4NDY0Ojs6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAJAAkAAAH/oAAgoOCAYSHhoeDiYWKhIyKkIiPhAIDl5iZmQCSlIuFAQQDBaSlpqQD
            BgGrrK2urIKWB7O0tbMDBJ2fu7EDCL/Awb+4uo28AJYJysvMygOrjsbGq6IK1tfY1qm5r92wyAML4uPk4s/FnJ69DOzt7uzn0enHlg329/j28dGQidQDDgIK
            HBhwm7eDvR4oXMhQ4T5H/SoNgECxokWKDyOpAxeho0cJIEOKFLnRX6gBE1KqlEChpcuXLSWoOpjIUoWbOCVY2Mmz504JBI5BsnShqFEJGJIqXZoUqFCJRo9m
            mEq16lQJAQRIm/dPg9evEjaIHUtWrExu3npxWMtWQoe3/nDjvsWqdd5WSx7y6pXwoa/fv33pbh06AIThwxJCKF7MWLFgu/MMSB4gorJlCSMya96cWabkz6Al
            Exg9gITp0xJKqF7NWjXQ0bBjjzZBu/Rp0xJO6N6tG4Xv38CB0zaRovgAFciTS1jBvDlzFCyiS58eHQWB4i2yD3DBvbuEF+DDg4dOvbz17DDSD4jBvr0EGfDj
            w0cxo779+/Wtp6fBf0CN/wBKYMOABA6Iwg0IJqgggtbxh8ODA+Qg4YQS6GDhhRYeuOCG1j24w4cD8CDiiBL0YOKJJqLgw4ostriidR/+IKMml4wkUnA4/kaA
            jED0CIRsQAYpZGxBBOHjkUgmEKnkkj4K4eSTUEYp5ZRUBgIAOw==
        }
    }

    proc updateElement {this element seconds value} {                           ;# value is either a valid number or the ? character
        dataBarChart::_updateElement $this $element $seconds $value                                               ;# update as usual
        set path $dataBarChart::($this,path)
        set list {}           ;# now update elements display so that none hides the others (ordered with largest values in the back)
        foreach name [$path element show] {
            set value [$path element cget $name -ydata]
            if {![string is double -strict $value]} {set value 0}                                                ;# may be undefined
            lappend list [list $name $value]
        }
        set names {}
        foreach list [lsort -real -index end -decreasing $list] {
            foreach {name value} $list {}
            lappend names $name
        }
        $path element show $names
    }

    proc message {this} {
        return [mc "overlap bar chart:\ndrop data cell(s)"]
    }

}
