# À faire :
# - Docstring
# - Modifier couleur et matériaux
# - Refactoriser logique visualisation / parsing.

# ==================================================
# VMD Pharmacophore & Interaction Visualizer Plugin
# ==================================================
namespace eval StrangeType {
    variable PHARMACOPHORE "pharmacophore"
    variable INTERACTION "interaction"
}

namespace eval StrangeField {
    # Phamacophore.
    variable PHARMACOPHORE "PHARMACOPHORE"

    variable X "COORDINATE_X"
    variable Y "COORDINATE_Y"
    variable Z "COORDINATE_Z"

    # Interaction.
    variable INTERACTION "INTERACTION"

    variable X_A "COORDINATE_X_A"
    variable Y_A "COORDINATE_Y_A"
    variable Z_A "COORDINATE_Z_A"

    variable X_B "COORDINATE_X_B"
    variable Y_B "COORDINATE_Y_B"
    variable Z_B "COORDINATE_Z_B"
}


# Parse header into a dict mapping column name -> index
proc parse_header {header separator} {
    set mapping {}

    for {set i 0} {$i < [llength $header]} {incr i} {
        dict set mapping [lindex $header $i] $i
    }

    return $mapping
}


proc load_csv {file_path type {separator ","}} {
    variable StrangeType::PHARMACOPHORE
    variable StrangeType::INTERACTION

    if {![file exists $file_path]} {
        error "\[Err##\] File '$file_path' does not exist."
    }

    set file [open $file_path r]
    set data [split [read $file] "\n"]
    close $file

    set header [split [lindex $data 0] $separator]
    set mapping [parse_header $header $separator]
    set body [lrange $data 1 end]

    if {$type eq $StrangeType::PHARMACOPHORE} {
        draw delete all

        variable StrangeField::PHARMACOPHORE

        variable StrangeField::X
        variable StrangeField::Y
        variable StrangeField::Z

        foreach line $body {
            if {$line eq ""} {
                continue
            }

            set fields [split $line $separator]
            set ph_type [
                lindex $fields [dict get $mapping $StrangeField::PHARMACOPHORE]
            ]

            set x [lindex $fields [dict get $mapping $StrangeField::X]]
            set y [lindex $fields [dict get $mapping $StrangeField::Y]]
            set z [lindex $fields [dict get $mapping $StrangeField::Z]]

            graphics top color red
            graphics top material Transparent
            graphics top sphere "$x $y $z" radius 0.5
        }
    } elseif {$type eq $StrangeType::INTERACTION} {
        draw delete all

        variable StrangeField::INTERACTION

        variable StrangeField::X_A
        variable StrangeField::Y_A
        variable StrangeField::Z_A

        variable StrangeField::X_B
        variable StrangeField::Y_B
        variable StrangeField::Z_B

        foreach line $body {
            if {$line eq ""} {
                continue
            }

            set fields [split $line $separator]
            set int_type [
                lindex $fields [dict get $mapping $StrangeField::INTERACTION]
            ]

            set x1 [lindex $fields [dict get $mapping $StrangeField::X_A]]
            set y1 [lindex $fields [dict get $mapping $StrangeField::Y_A]]
            set z1 [lindex $fields [dict get $mapping $StrangeField::Z_A]]

            set x2 [lindex $fields [dict get $mapping $StrangeField::X_B]]
            set y2 [lindex $fields [dict get $mapping $StrangeField::Y_B]]
            set z2 [lindex $fields [dict get $mapping $StrangeField::Z_B]]

            graphics top color blue
            graphics top material Transparent
            graphics top line "$x1 $y1 $z1" "$x2 $y2 $z2" width 3
        }
    } else {
        error "\[Err##\] Unknown type '$type'. "\
            "Use 'pharmacophore' or 'interaction'."
    }
}

# ==================================================
# GUI with Tk
# ==================================================
proc StrangeGUI {} {
    variable StrangeType::PHARMACOPHORE
    variable StrangeType::INTERACTION

    if {[winfo exists .strange]} {
        raise .strange
        return
    }

    toplevel .strange
    wm title .strange "strange"

    label .strange.label_file -text "File \[.csv\]:"
    entry .strange.file -width 40 -textvariable ::csv_file
    button .strange.browse -text "browse" -command {
        set file [
            tk_getOpenFile -filetypes {
                {"File \[.csv\]" {.csv}}
                {"All Files" {*}}
            }
        ]

        if {$file ne ""} {
            set ::csv_file $file
        }
    }

    label .strange.label_type -text "Type:"
    ttk::combobox .strange.type \
        -values [list \
            $StrangeType::PHARMACOPHORE \
            $StrangeType::INTERACTION
        ]\
        -textvariable ::csv_type
    set ::csv_type "$StrangeType::PHARMACOPHORE"

    label .strange.label_separator -text "Separator:"
    entry .strange.separator -width 3 -textvariable ::csv_separator
    set ::csv_separator ","

    button .strange.run -text "LOAD AND DRAW" -command {
        if {$::csv_file eq ""} {
            tk_messageBox \
                -icon error \
                -message "\[Err##\]Please select a CSV file!"
        } else {
            load_csv $::csv_file $::csv_type $::csv_separator
        }
    }

    grid .strange.label_file .strange.file .strange.browse
    grid .strange.label_separator .strange.separator
    grid .strange.label_type .strange.type
    grid .strange.run -columnspan 3 -sticky ew
}

# ==================================================
# Register menu entry in Extensions
# ==================================================
menu tk register "Visualization/strange" StrangeGUI

