# copyright (C) 1997-2001 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

set rcsId {$Id: record.tcl,v 2.11 2000/12/31 23:14:19 jfontain Exp $}


class record {

    proc record {this args} switched {$args} {
        switched::complete $this
    }

    proc ~record {this} {
        variable ${this}data
        catch {unset ${this}data}
    }

    proc options {this} {
        return [list\
            [list -file {} {}]\
        ]
    }

    proc set-file {this value} {}

    proc globalData {} {
        append data "version $global::applicationVersion\n"
        set seconds [clock seconds]
        append data "date [clock format $seconds -format %D] time [clock format $seconds -format %T]\n"
        return $data
    }

    proc data {{snapshot 0}} {
        if {!$snapshot} {
            set data [globalData]
        }
        append data "configuration \{\n"
        foreach name [configuration::variables 0] {                                                  ;# indent configuration entries
            append data "    [list $name [set ::global::$name]]\n"
        }
        append data \}\n
        # main window coordinates are not saved as it would be bad manners to force initial window placement
        set path $::widget::($global::scroll,path)                   ;# use scroll area size as icons area may or may not be present
        append data "width [winfo width $path] height [winfo height $path]\n"
        append data "pollTime $global::pollTime\n"
        append data "modules \{\n"
        foreach instance $modules::(instances) {
            set namespace $modules::instance::($instance,namespace)
            append data "    $namespace \{\n"
            append data "        arguments \{$modules::instance::($instance,arguments)\}\n"
            append data "        tables \{\n"
            foreach table $dataTable::(list) {
                # filter other module tables
                if {![string equal $namespace [namespace qualifiers [composite::cget $table -data]]]} continue
                foreach {x y width height} [canvasWindowManager::getGeometry $global::windowManager $widget::($table,path)] {}
                set level [canvasWindowManager::getStackLevel $global::windowManager $widget::($table,path)]
                append data "            $table \{\n"
                append data "                x $x y $y width $width height $height level $level\n"
                foreach {switch value} [dataTable::initializationConfiguration $table] {
                    append data "                $switch [list $value]\n"
                }
                append data "            \}\n"
            }
            append data "        \}\n"
            append data "    \}\n"
        }
        append data \}\n
        append data "viewers \{\n"
        foreach viewer $viewer::(list) {
            append data "    $viewer \{\n"
            set class [classof $viewer]
            append data "        class $class\n"
            if {![string equal $class ::thresholds]} {                                         ;# thresholds viewer is not displayed
                foreach {x y width height} [canvasWindowManager::getGeometry $global::windowManager $widget::($viewer,path)] {}
                set level [canvasWindowManager::getStackLevel $global::windowManager $widget::($viewer,path)]
                append data "        x $x y $y width $width height $height level $level\n"
            }
            append data "        cells {[viewer::cells $viewer]}\n"
            foreach {switch value} [viewer::initializationConfiguration $viewer] {
                append data "        $switch [list $value]\n"
            }
            append data "    \}\n"
        }
        append data \}
        return $data
    }

    proc write {this} {
        if {[string length $switched::($this,-file)]==0} {
            error {-file option undefined}
        }
        set file [open $switched::($this,-file) w+]                                                           ;# create or overwrite
        puts $file [data]
        close $file
    }

    proc read {this} {
        variable ${this}data

        if {[string length $switched::($this,-file)]==0} {
            error {-file option undefined}
        }
        if {[catch {set file [open $switched::($this,-file)]} message]} {
            puts stderr $message
            exit 1
        }
        if {![regexp {^(version [1-9]\d*\.\d+(\.\d+)*)$} [gets $file]]} {
            puts stderr "file $switched::($this,-file) is not a valid moodss save file"
            exit 1
        }
        seek $file 0                                                                                                       ;# rewind
        array set ${this}data [::read $file]
        close $file
    }

    proc modules {this} {                            ;# indexed modules must be sorted so that they are created in the correct order
        variable ${this}data

        array set data [set ${this}data(modules)]
        return [lsort -dictionary [array names data]]
    }

    proc modulesWithArguments {this} {           ;# return list of format: module [-option [value] -option ...] module [-option ...]
        set list {}
        foreach module [modules $this] {
            moduleData $this $module data
            eval lappend list $module $data(arguments)
        }
        return $list
    }

    proc pollTime {this} {
        variable ${this}data

        return [set ${this}data(pollTime)]
    }

    proc sizes {this} {
        variable ${this}data

        return "[set ${this}data(width)] [set ${this}data(height)]"
    }

    proc viewersData {this} {
        variable ${this}data

        array set data [set ${this}data(viewers)]
        set list {}
        foreach id [lsort -integer [array names data]] {
            catch {unset viewer}
            set viewer(level) {}        ;# for backward compatibility when level was not stored in save file (versions 5.1 and down)
            array set viewer $data($id)
            set options {}                                  ;# gather viewer specific switched options in a switch / value pair list
            foreach {name value} [array get viewer -*] {
                lappend options $name $value
            }
            if {[string equal $viewer(class) ::thresholds]} {                                  ;# thresholds viewer is not displayed
                lappend list $viewer(class) $viewer(cells) {} {} {} {} {} $options
            } else {
                lappend list $viewer(class) $viewer(cells) $viewer(x) $viewer(y) $viewer(width) $viewer(height) $viewer(level)\
                    $options
            }
        }
        return $list
    }

    proc moduleData {this module dataName} {
        variable ${this}data
        upvar $dataName data

        array set all [set ${this}data(modules)]
        array set data $all($module)
    }

    proc tableData {this module creationIndex dataName} {              ;# index is module data table creation index, starting with 0
        variable ${this}data
        upvar $dataName data

        moduleData $this $module moduleData
        array set tablesData $moduleData(tables)
        unset moduleData
        set data(level) {}              ;# for backward compatibility when level was not stored in save file (versions 5.1 and down)
        # use table identifier at the specified index in creation order sorted table indices
        array set data $tablesData([lindex [lsort -integer [array names tablesData]] $creationIndex])
    }

    proc tableWindowManagerData {this module creationIndex} {
        tableData $this $module $creationIndex data
        return [list $data(x) $data(y) $data(width) $data(height) $data(level)]
    }

    proc tableOptions {this module creationIndex} {
        tableData $this $module $creationIndex data
        set options {}                                       ;# gather table specific switched options in a switch / value pair list
        foreach {name value} [array get data -*] {
            lappend options $name $value
        }
        return $options
    }

    proc configurationData {this} {                                                             ;# return a global name / value list
        variable ${this}data

        return [set ${this}data(configuration)]
    }

    proc snapshot {} {                                                                             ;# remember current configuration
        set (data) [data 1]
    }

    proc changed {} {                                                        ;# see if configuration has changed since last snapshot
        if {[info exists (data)]} {
            return [string compare $(data) [data 1]]
        } else {    ;# snapshot was not yet taken, assume there was no change (can happen when user closes window right after start)
            return 0
        }
    }

}
