namespace eval calib {
  variable buf
}

proc calib::next_temp {T} {
  variable buf

clientput "next_temp $T"
  tt tolerance [expr $T * 0.01]
  tt settle [expr $T + 60]
  run tt $T
  hsetprop /res @crit 0
  set buf(1) [list]
  set buf(2) [list]
  set buf(3) [list]
  set buf(4) [list]
  set buf(5) [list]
  set buf(6) [list]
  hsetprop /res @chanidx 0
  foreach channel [hgetpropval /res @channels] {
    hsetprop /res/s$channel/raw dif 1
    hsetprop /res/s$channel/raw endtime 0
  }
}

proc calib::update_chan {value} {
  variable buf

  if {[sct @crit] == 0} {
    if {[listexe] ne "Machine Idle"} {
      if {[hval /res/autoscan] == 0} {
        res autoscan 1
      }
      # stabilizing
      return
    }
    if {[result tt set] < 1.3 && [result tt set] > 311} {
      hepump valve 1
      hepump running 0
      calib::stop
      return
    }
    sct @crit 1
    res autoscan 0
    return
  }
  set i [sct @chanidx]
  set c [lindex [sct @channels] $i]
  if {$c != [sct @channel]} {
    if {$c != [hval /res]} {
      res s$c/active 1
    }
    return
  }
  set time [format %.3f [expr [DoubleTime] - [sct @basetime]]]
  lappend buf($c) $value
  if {[llength $buf($c)] >= [sct count]} {
    set mean [expr [::tcl::mathop::+ {*}$buf($c)] / double([llength $buf($c)])]
    set sum2 0
    foreach r $buf($c) {
      set sum2 [expr $sum2 + pow($r - $mean, 2)]
    }
    sct sigma [expr sqrt($sum2) / double([llength $buf($c)])]
    set buf($c) [list]
    set lastmean [sct lastmean]
    sct lastmean $mean
    set endtime [silent 0 sct endtime]
    if {$endtime > 0} {
      set interval [expr abs($time - $endtime) / 60.0]
      sct dif [expr (($mean - $lastmean) / double($mean)) / $interval]
    } else {
      sct dif 1
    }
    sct endtime $time
clientput [format "time %.0f dif %.6f c %d interval %.2f R %.7g sigma %.7g" $time [sct dif] $c $interval $mean [sct sigma]]
    if {$c == [sct @calchan]} {
      set lastchan [lindex [sct @channels] [expr $i - 1]]
      hsetprop res/s$lastchan/raw refvalue [expr 0.5 * ($lastmean + $mean)]
      set maxdif 0
      foreach channel [sct @channels] {
        set dif [hgetpropval /res/s$channel/raw dif]
        if {abs($dif) > abs($maxdif)} {
          set maxdif $dif
        }
      }
clientput "maxdif$i $maxdif"
      set save [sct @crit]
      if {$save == 1} {
        if {abs($maxdif) <= [sct @crit1]} {
          sct @nextsave $i
          sct @crit 2
        } else {
          set save 0
        }
      } else {
        if {$i == [sct @nextsave]} {
          sct @crit [expr $save + 1]
        } else {
          set save 0
        }
      }
      if {$save > 0} {
        catch {
          foreach channel [sct @channels] {
            if {$channel != [sct @calchan]} {
              set v [hgetpropval res/s$channel/raw lastmean]
              set rv [hgetpropval res/s$channel/raw refvalue]
              set sigma [hgetpropval res/s$channel/raw sigma]
              set endtime [hgetpropval res/s$channel/raw endtime]
              set fil [open [format [sct @basename] $save $channel] a]
              puts $fil [format "%.2f	%.9g	%.9g	%.9g" $endtime $rv $v $sigma]
              close $fil
            }
          }
        } msg
clientput SAVE/$save/$msg
        if {$save >= 3} {
          # finish T
          # next_temp [format %.3g [expr [result tt set] * 0.8912]]
          next_temp [format %.3g [expr [result tt set] * 1.778]]
        }
      }
    }
    incr i
    if {$i >= [llength [sct @channels]]} {
      set i 0
    }
    sct @chanidx $i
    res s[lindex [sct @channels] $i]/active 1
  }
}

proc calib::set_chan {channel} {
  _res updatescript /res/s$channel/raw calib::update_chan
  hsetprop /res/s$channel/raw count 10
  hsetprop /res/s$channel/raw lastmean 0
  hsetprop /res/s$channel/raw dif 1
}

proc calib::set_calchan {channel} {
  _res updatescript /res/s$channel/raw calib::update_chan
  hsetprop /res/s$channel/raw count 5
  hsetprop /res/s$channel/raw lastmean 0
  hsetprop /res/s$channel/raw dif 1
}

proc calib::start {T args} {
  set calchan [lindex $args 0]

  hsetprop /res @basetime [expr int([DoubleTime]/10) * 10]
  hsetprop /res @calchan $calchan
  hsetprop /res @chanidx 0
  hsetprop /res @crit 0
  # rel change / minute
  hsetprop /res @crit1 0.0005
  hsetprop /res @nextsave 0
  set_calchan $calchan
  set chanlist [list]
  foreach channel $args {
    if {$channel != $calchan} {
      set_chan $channel
      lappend chanlist $channel
      lappend chanlist $calchan
    }
  }
  hsetprop /res @channels $chanlist
  res autoscan 0
  hsetprop /res @basename "calib[clock format [clock seconds] -format "%Y-%m-%d"]_c%s_chan%s.dat"
  res s$calchan/active 1
  next_temp $T
  nv autoflow/getTemp calib::tmts
}

proc calib::stop {} {
  foreach channel {1 2 3 4 5 6} {
    _res killupdatescript /res/s$channel/raw calib::update_chan
  }
}

proc calib::tmts {} {
  set tm [silent 1 result tt tm]
  set ts [silent $tm hval /res/s[hgetpropval /res @calchan]]
  if {$ts < $tm} {
    return $ts
  } else {
    return $tm
  }
}

