/*======================================================================
  A GENESIS GUI for network models, with a  control panel, a graph with
  axis scaling, and a network view to visualize Vm in each cell
  ======================================================================*/

//=========================================
//      Function definitions used by GUI
//=========================================

function overlaytoggle(widget)
    str widget
    setfield /##[TYPE=xgraph] overlay {getfield {widget} state}
end

function change_stepsize(dialog)
   str dialog
   dt =  {getfield {dialog} value}
   setclock 0 {dt}
   echo "Changing step size to "{dt}
end


function change_runtime(dialog)
   str dialog
   tmax =  {getfield {dialog} value}
   setfield /data/voltage xmax {tmax}
   setfield /data/Inh_voltage xmax {tmax}
   setfield /MGBv_Vm/voltage xmax {tmax}    // from input_graphics.g
   setfield /EPSCform/EPSC_sum xmax {tmax}  // from ACnet2-3.g
end

function set_drive_weights(dialog)
   str dialog
   drive_weight = {getfield {dialog} value}
   setall_driveweights {drive_weight}
end

/*  A subset of the functions defined in genesis/startup/xtools.g
    These are used to provide a "scale" button to graphs.
    "makegraphscale path_to_graph" creates the button and the popup
     menu to change the graph scale.
*/

function setgraphscale(graph)
    str graph
    str form = graph @ "_scaleform"
    str xmin = {getfield {form}/xmin value}
    str xmax = {getfield {form}/xmax value}
    str ymin = {getfield {form}/ymin value}
    str ymax = {getfield {form}/ymax value}
    setfield {graph} xmin {xmin} xmax {xmax} ymin {ymin} ymax {ymax}
    xhide {form}
end

function showgraphscale(form)
    str form
    str x, y
    // find the parent form
    str parent = {el {form}/..}
    while (!{isa xform {parent}})
        parent = {el {parent}/..}
    end
    x = {getfield {parent} xgeom}
    y = {getfield {parent} ygeom}
    setfield {form} xgeom {x} ygeom {y}
    xshow {form}
end

function makegraphscale(graph)
    if ({argc} < 1)
        echo usage: makegraphscale graph
        return
    end
    str graph
    str graphName = {getpath {graph} -tail}
    float x, y
    str form = graph @ "_scaleform"
    str parent = {el {graph}/..}
    while (!{isa xform {parent}})
        parent = {el {parent}/..}
    end

    x = {getfield {graph} x}
    y = {getfield {graph} y}

    create xbutton {graph}_scalebutton  \
        [{getfield {graph} xgeom},{getfield {graph} ygeom},50,25] \
           -title scale -script "showgraphscale "{form}
    create xform {form} [{x},{y},180,170] -nolabel

    disable {form}
    pushe {form}
    create xbutton DONE [10,5,55,25] -script "setgraphscale "{graph}
    create xbutton CANCEL [70,5,55,25] -script "xhide "{form}
    create xdialog xmin [10,35,160,25] -value {getfield {graph} xmin}
    create xdialog xmax [10,65,160,25] -value {getfield {graph} xmax}
    create xdialog ymin [10,95,160,25] -value {getfield {graph} ymin}
    create xdialog ymax [10,125,160,25] -value {getfield {graph} ymax}
    pope
end

/* Add some interesting colors to any widgets that have been created */
function colorize
    setfield /##[ISA=xlabel] fg white bg blue3
    setfield /##[ISA=xbutton] offbg rosybrown1 onbg rosybrown1
    setfield /##[ISA=xtoggle] onfg red offbg cadetblue1 onbg cadetblue1
    setfield /##[ISA=xdialog] bg palegoldenrod
    setfield /##[ISA=xgraph] bg ivory
end

// function to return a color name from an index into the colorlist
// Usage example: str color = {colors 3}
function colors(col_num)
    int col_num
    str colorlist = "black blue cyan green magenta red orange"
    str color
    // convert col_num to range 1 though 7
    col_num = col_num - {trunc {col_num/7.0}}*7 + 1
    color = {getarg {arglist {colorlist}} -arg {col_num}}
    return {color}
end

/* Functions to drop and add plots of Vm for middle cell of input target row */

function add_Vmplot(row_num)
    int row_num, cell_num, dup_num, n, count
    str label, msglabel
    float offset
    float delta_y = 0.02 // vertical displacement of subsequent plots
    int first_row = 8 // the first row to be plotted has no vertical offset
    cell_num = row_num*Ex_NX  + {round {(Ex_NX -1)/2.0}}
    // generate PLOTSCALE options  {value} *{label} *{color} scale offset
    label = "row_" @ {row_num}
    offset = (row_num - first_row)*delta_y
    count = {getmsg /data/voltage -in -count}
    dup_num = -1  // default is that the message doesn't already exist
    for (n = 0; n < count; n = n +1)
        msglabel = {getmsg /data/voltage -in -slot {n} 1 }
        if ({msglabel} == {label})
            dup_num = n
            echo "Plot " {n} "  " {msglabel} " already exists"
        end
    end
    if (dup_num < 0)
      if({hflag} && {hsolve_chanmode > 1})
        addmsg /Ex_layer/{Ex_cell_name}[{cell_num}]/solver \
          /data/voltage PLOTSCALE \
          {findsolvefield /Ex_layer/{Ex_cell_name}[{cell_num}]/solver \
          soma Vm}  *{label} *{colors {row_num}} 1 {offset}
      else
        addmsg /Ex_layer/{Ex_cell_name}[{cell_num}]/soma /data/voltage \
          PLOTSCALE  Vm  *{label} *{colors {row_num}} 1 {offset}
      end
    end
    // MGBv inputs target y-coord range, not a row, and Inh cells have
    // twice the spacing of Ex cell.  Thus the row numbers of Inh inputs
    // increase at half the rate.
    cell_num =  {round {row_num*Inh_NX/2.0}}  + {round {(Inh_NX -1)/2.0}}
    // redo this for /data/Inh_voltage without assuming it has same messages
    count = {getmsg /data/Inh_voltage -in -count}
    dup_num = -1  // default is that the message doesn't already exist
    for (n = 0; n < count; n = n +1)
        msglabel = {getmsg /data/Inh_voltage -in -slot {n} 1 }
        if ({msglabel} == {label})
            dup_num = n
            echo "Plot " {n} "  " {msglabel} " already exists"
        end
    end
    if (dup_num < 0)
      if({hflag} && {hsolve_chanmode > 1})
        addmsg /Inh_layer/{Inh_cell_name}[{cell_num}]/solver \
          /data/Inh_voltage PLOTSCALE \
          {findsolvefield /Inh_layer/{Inh_cell_name}[{cell_num}]/solver \
          soma Vm}  *{label} *{colors {row_num}} 1 {offset}
      else
         addmsg /Inh_layer/{Inh_cell_name}[{cell_num}]/soma /data/Inh_voltage \
            PLOTSCALE  Vm *{label} *{colors {row_num}} 1 {offset}
      end
    end
end


/* This is a much simplified version of add_Vmplot, to add plots
   of synaptic currents.  It does no checking for existing plots.
*/

function add_Ikplot(row_num)
    int row_num, cell_num, dup_num, n, count
    str label, msglabel
    float offset
    float iscale = 100e-12 // 100 pA
    int first_row = 8 // the first row to be plotted has no vertical offset
    float delta_y = 2.0*iscale // vertical displacement of subsequent plots
    // target is middle cell in row targeted by row_num
    cell_num = row_num*Ex_NX + {round {(Ex_NX -1)/2.0}}

    // generate PLOTSCALE options  {value} *{label} *{color} scale offset
    label = "row_" @ {row_num}
    offset = (row_num - first_row)*delta_y  //

    if({hflag} && {hsolve_chanmode > 1})
        addmsg /Ex_layer/{Ex_cell_name}[{cell_num}]/solver \
          /Isyndata/syncurrent PLOTSCALE \
          {findsolvefield /Ex_layer/{Ex_cell_name}[{cell_num}]/solver \
          {Ex_ex_synpath} Ik} *{label} *{colors {row_num}} 1 {offset}

        addmsg /Ex_layer/{Ex_cell_name}[{cell_num}]/solver \
          /Isyndata/syncurrent PLOTSCALE  \
          {findsolvefield /Ex_layer/{Ex_cell_name}[{cell_num}]/solver \
            {Ex_inh_synpath}  Ik} *"Inh_"{label} *{colors {row_num}} 1 {offset}

        // MGBv inputs target y-coord range, not a row, and Inh cells have
        // twice the spacing of Ex cell.  Thus the row numbers of Inh inputs
        // increase at half the rate.
        cell_num = {round {row_num*Inh_NX/2.0}} + {round {(Inh_NX -1)/2.0}}

        addmsg /Inh_layer/{Inh_cell_name}[{cell_num}]/solver \
          /Isyndata/Inh_syncurrent PLOTSCALE  \
          {findsolvefield /Inh_layer/{Inh_cell_name}[{cell_num}]/solver \
            {Inh_ex_synpath} Ik} *{label} *{colors {row_num}} 1 {offset}
        addmsg /Inh_layer/{Inh_cell_name}[{cell_num}]/solver \
           /Isyndata/Inh_syncurrent PLOTSCALE  \
           {findsolvefield /Inh_layer/{Inh_cell_name}[{row_num}]/solver \
           {Inh_inh_synpath} Ik}  *"Inh_"{label} *{colors {row_num}} 1 {offset}
    else
        addmsg /Ex_layer/{Ex_cell_name}[{cell_num}]/{Ex_ex_synpath} \
            /Isyndata/syncurrent \
            PLOTSCALE  Ik  *{label} *{colors {row_num}} 1 {offset}
        addmsg /Ex_layer/{Ex_cell_name}[{cell_num}]/{Ex_inh_synpath} \
            /Isyndata/syncurrent \
            PLOTSCALE  Ik  *"Inh_"{label} *{colors {row_num}} 1 {offset}

        // MGBv inputs target y-coord range, not a row, and Inh cells have
        // twice the spacing of Ex cell.  Thus the row numbers of Inh inputs
        // increase at half the rate.
        cell_num = {round {row_num*Inh_NX/2.0}} + {round {(Inh_NX -1)/2.0}}
        addmsg /Inh_layer/{Inh_cell_name}[{cell_num}]/{Inh_ex_synpath} \
          /Isyndata/Inh_syncurrent \
            PLOTSCALE  Ik  *{label} *{colors {row_num}} 1 {offset}
        addmsg /Inh_layer/{Inh_cell_name}[{cell_num}]/{Inh_inh_synpath} \
           /Isyndata/Inh_syncurrent \
            PLOTSCALE  Ik  *"Inh_"{label} *{colors {row_num}} 1 {offset}
    end
end // function add_Ikplot


//==================================
//    Functions to set up the GUI
//==================================

function make_control
    create xform /control [0,0,270,530]
    pushe /control
    create xlabel label -hgeom 25 -bg cyan -label "CONTROL PANEL"
    create xbutton RESET -wgeom 25%       -script reset
    create xbutton RUN  -xgeom 0:RESET -ygeom 0:label -wgeom 25% \
         -script step_tmax
    create xbutton STOP  -xgeom 0:RUN -ygeom 0:label -wgeom 25% \
         -script stop
    create xbutton QUIT -xgeom 0:STOP -ygeom 0:label -wgeom 25% -script quit
    create xdialog RUNID -title "RUNID string:" -value {RUNID} \
                -script "change_RUNID <value>"
    create xdialog stepsize -title "dt (sec)" -value {dt} \
                -script "change_stepsize <widget>"
    create xdialog runtime -title "runtime (sec)" -value {tmax} \
                -script "change_runtime <widget>"
    create xtoggle overlay   -script "overlaytoggle <widget>"
    setfield overlay offlabel "Overlay OFF" onlabel "Overlay ON" state 0
    create xlabel connlabel -label "Connection Parameters"
    create xdialog Ex_ex_gmax -label "Ex_cell ex gmax (nS)" \
         -value {Ex_ex_gmax*1e9} -script "set_Ex_ex_gmax  <v>"
    create xdialog Ex_inh_gmax -label "Ex_cell inh gmax (nS)" \
          -value {Ex_inh_gmax*1e9} -script "set_Ex_inh_gmax  <v>"
    create xdialog Inh_ex_gmax -label "Inh_cell ex gmax (nS)" \
          -value {Inh_ex_gmax*1e9} -script "set_Inh_ex_gmax  <v>"
    create xdialog Inh_inh_gmax -label "Inh_cell inh gmax (nS)" \
          -value {Inh_inh_gmax*1e9} -script "set_Inh_inh_gmax  <v>"
    create xdialog weight -label "Weight"  \
	-value {syn_weight} -script "set_weights <v>"
    create xdialog propdelay -label "Prop delay (sec/m)" \
	-value {prop_delay}  -script "set_delays <v>"
    create xlabel randact -label "Random background activation"
    create xdialog randfreq -wgeom 50% -label "Freq" -value {frequency} \
	-script "set_frequency <v>"
    create xdialog Ex_bg_gmax -wgeom 50% -ygeom 0:randact -xgeom 0:randfreq \
        -label "gmax (nS)" -value {Ex_bg_gmax*1e9} -script "set_Ex_bg_gmax  <v>"
    create xlabel drive_input -label "Thalamic Drive Input"
    create xdialog Ex_dr_gmax -wgeom 50% -label "Ex gmax (nS)" \
         -value {Ex_drive_gmax*1e9} -script "set_Ex_drive_gmax  <v>"
    create xdialog Inh_dr_gmax -wgeom 50% -xgeom 0:Ex_dr_gmax \
         -ygeom 0:drive_input -label "Inh gmax (nS)" \
         -value {Inh_drive_gmax*1e9} -script "set_Inh_drive_gmax  <v>"

    create xdialog drive_weights -label "Default drive weights" \
         -value {drive_weight} -script "set_drive_weights <widget>"
    create xdialog show_params -label "Show params for input:" \
        -value 1  -script "show_params <v>"
    pope
    xshow /control
end

function make_Vmgraph
    str graph_form = "/data"
    str graphlabel = "Vm of center input targets"
    float vmin = -0.07
    float vmax = 0.65
    create xform {graph_form} [275,0,400,800]
    pushe {graph_form}
    create xlabel label -label {graphlabel}
    create xgraph voltage -hgeom 60% -title "Ex_cell Membrane Potential" !
    setfield ^ XUnits sec YUnits V
    setfield ^ xmax {tmax} ymin {vmin} ymax {vmax}
    makegraphscale {graph_form}/voltage
    useclock voltage 2 // the clock used to write the netview file
    create xgraph Inh_voltage -hgeom 30% -ygeom 0:voltage \
        -title "Inh_cell Membrane Potential" -bg white
    setfield ^ XUnits sec YUnits V
    setfield ^ xmax {tmax} ymin {vmin} ymax {vmax}
    makegraphscale {graph_form}/Inh_voltage
    pope
    xshow {graph_form}
end

function make_Ikgraph
    str graph_form = "/Isyndata"
    str graphlabel = "Syn cuurents of center input targets"
    float iscale = 100e-12 // 100 pA
    float imin = -5*iscale
    float imax = 80*iscale
    int xpos = 684; int ypos = 0
    create xform {graph_form} [{xpos}, {ypos},400,800]
    pushe {graph_form}
    create xlabel label -label {graphlabel}
    create xgraph syncurrent -hgeom 64% -title "Ex_cell synaptic currents" !
    setfield ^ XUnits sec YUnits I
    setfield ^ xmax {tmax} ymin {imin} ymax {imax}
    makegraphscale {graph_form}/syncurrent
    useclock voltage 2 // the clock used to write the netview file
    create xgraph Inh_syncurrent -hgeom 30% -ygeom 0:syncurrent \
        -title "Inh_cell synaptic currents" -bg white
    setfield ^ XUnits sec YUnits I
    setfield ^ xmax {tmax} ymin {imin} ymax {imax}
    makegraphscale {graph_form}/Inh_syncurrent
    create xbutton DISMISS -ygeom 0:Inh_syncurrent -script "xhide "{graph_form}
    pope
    xshow {graph_form}
end


function make_graph_messages
    /* Set up plotting messages, with offsets */

    add_Vmplot  8
    add_Vmplot  12
    add_Vmplot  18
    add_Vmplot  24
    add_Vmplot  30
    add_Vmplot  36

    add_Ikplot  18
    add_Ikplot  24
    add_Ikplot  30
    add_Ikplot  36

    str MGBv_graph = "/MGBv_Vm/voltage"
    if (input_type == "MGBv")
    // This needs to be generalized
        str src = "soma"
        addmsg /MGBv[1]/{src} {MGBv_graph} PLOTSCALE Vm *MGBv1_Vm *black 1 0
    elif (input_type == "pulsed_spiketrain" || input_type == "pulsed_randomspike")
        str src = "spikepulse/spike"
        setfield {MGBv_graph} ymin 0.0 ymax 6.0
        // should loop over Ninputs to see which are enabled with spiketoggle
        addmsg /MGBv[5]/{src} {MGBv_graph} PLOTSCALE state *MGBv5_Vm *black 1 0
        addmsg /MGBv[17]/{src} {MGBv_graph} PLOTSCALE state *MGBv17_Vm *blue 1 2
        addmsg /MGBv[29]/{src} {MGBv_graph} PLOTSCALE state *MGBv29_Vm *red 1 4
    end


end // function make_graph_messages

function make_netview  // sets up xview widget to display Vm of each cell
    // Adjust the aspect ratio for rectangular networks of width around 400
    // Make view for Ex_cell[]
    int npixels = 2*{round {180/Ex_NX}}
    int Ex_view_width = npixels*Ex_NX + 20
    int Ex_view_height = npixels*Ex_NY + 17
    if ({exists /Ex_netview})  // make a new one of the right size
        delete /Ex_netview
    end
    create xform /Ex_netview [680,0,{Ex_view_width}, {Ex_view_height}]
    create xdraw /Ex_netview/draw [0%,0%,100%, 100%]
    // Make the display region a little larger than the cell array
    setfield /Ex_netview/draw xmin {-Ex_SEP_X} xmax {Ex_NX*Ex_SEP_X} \
	ymin {-Ex_SEP_Y} ymax {Ex_NY*Ex_SEP_Y}
    create xview /Ex_netview/draw/view

    setfield /Ex_netview/draw/view value_min -0.08 value_max 0.03 \
        viewmode colorview sizescale {Ex_SEP_X}
/* GENESIS doesn't like the wildcard path "{Ex_cell_name}[]/solver"

    if({hflag} && {hsolve_chanmode > 1})
      setfield /Ex_netview/draw/view path /Ex_layer/{Ex_cell_name}[]/solver \
        field {findsolvefield /Ex_layer/{Ex_cell_name}[]/solver soma Vm}
    else
      setfield /Ex_netview/draw/view path /Ex_layer/{Ex_cell_name}[]/soma \
        field Vm
    end
*/
      setfield /Ex_netview/draw/view path /Ex_layer/{Ex_cell_name}[]/soma \
        field Vm

    xshow /Ex_netview
    int Inh_view_width = npixels*Inh_NX + 20
    int Inh_view_height = npixels*Inh_NY + 10
    if ({exists /Inh_netview})  // make a new one of the right size
        delete /Inh_netview
    end
    create xform /Inh_netview [680,{20 + Ex_view_height}, \
	{Inh_view_width + npixels}, {Inh_view_height}]
    create xdraw /Inh_netview/draw [0%,0%,100%, 100%]
    // Make the display region a little larger than the cell array
    setfield /Inh_netview/draw xmin {-Inh_SEP_X} xmax {Inh_NX*Inh_SEP_X} \
	ymin {-Inh_SEP_Y} ymax {Inh_NY*Inh_SEP_Y}

    create xview /Inh_netview/draw/view
    setfield /Inh_netview/draw/view value_min -0.08 value_max 0.03 \
        viewmode colorview sizescale {Inh_SEP_X}
/*
    if({hflag} && {hsolve_chanmode > 1})
      setfield /Inh_netview/draw/view path /Inh_layer/{Inh_cell_name}[]/solver \
        field {findsolvefield /Inh_layer/{Inh_cell_name}[]/solver soma Vm}
    else
      setfield /Inh_netview/draw/view path /Inh_layer/{Inh_cell_name}[]/soma \
        field Vm
    end
*/
      setfield /Inh_netview/draw/view path /Inh_layer/{Inh_cell_name}[]/soma \
        field Vm
    xshow /Inh_netview
end