namespace eval dilprep {
  array set score {dil2 0 dil3 0 dil4 0}
  array set curves {dil2 cx198 dil3 cx262 dil4 cx078}
}


proc stdConfig::dilprep {} {
  controller syncedprot

  obj DILPREP wr
  prop enum warm=0,warmup=1,undef=-1
  default -1
  prop read dilprep::poll
  prop check dilprep::check
  prop write stdSct::complete
  prop buffer ""
  # last time when sample was warm
  prop warmtime 0
  # last time when sample was cold
  prop coldtime 0
  # last time when sample warming up faster than slopelimit
  prop steeptime 0
  # last time when detection was undefined
  prop undeftime [DoubleTime]

  kids dilprep {
    node coldlimit par 280
    prop help "stick is detected cold when T < coldlimit"
    node warmlimit par 290
    prop help "stick is detected warm when T > warmlimit for more than window sec"
    node slopelimit par 0.1
    prop help "stick is detected warm when tslope < slopelimit for more than window sec"
    node window par 600
    prop help "time window (sec)"
    node dil out -int
    prop enum undef=0,dil2=2,dil3=3,dil4=4
    prop check dilprep::checktype
    prop write stdSct::complete
  }
}

proc dilprep::check {} {
  if {[sct target] == 1} {
    # reset slope
    tslope node /ts
  }
  sct update [sct target]
}

proc dilprep::checktype {} {
  variable score
  variable curves

  enum_decode [sct] [sct target] num dilname
  foreach {key value} [array get score] {
    set score($key) 0
  }
  if {$dilname ne "undef"} {
    set score($dilname) 12
  }
  set crv $curves($dilname)
  ts curve $crv
  sct update [sct target]
}

proc dilprep::poll {} {
  variable score
  variable curves

  if {[result _tmon status] eq "no response"} {
    sct connected 0
  } elseif {[silent 1 sct connected] == 0} {
    device name none
    device makeitem action plugged
    device makeitem newdevice dilprep
  }
  set now [DoubleTime]
  set onek [silent 0 result tmon onek/raw]
  set stillt [silent 0 result tmon stillt/raw]
  set mix [silent 0 result tmon mix/raw]
  if {$onek * $stillt * $mix == 0} {
    sct update -1
    return idle
  }
  # guess dilution type from typical resistivities
  # determine possible candidate
  set dilname undef
  if {abs($mix - 2200) < 50 && abs($onek - 2260) < 100 && abs($stillt - 2260) < 100} {
    if {$onek > 2260} {
      if {$stillt > 2260} {
        set dilname dil4
      }
    } elseif {$stillt < 2260} {
      set dilname dil2
    } else {
      set dilname dil3
    }
  }
  set maxscore 0
  # increase score for matching candidate, decrease for others (clamped within 0..12)
  foreach {key value} [array get score] {
    if {$key eq $dilname} {
      set value [expr min(12, $value + 1)]
    } else {
      set value [expr max(0, $value - 1)]
    }
    if {$value > $maxscore} {
      set maxscore $value
    }
    set score($key) $value
  }
  if {$dilname eq "undef"} {
    sct undeftime $now
    return idle
  }
  if {$maxscore eq 0} {
    # no max score
    enum_update [sct]/dil undef
  } elseif {$score($dilname) >= $maxscore} {
    if {$dilname ne [enum_txt [sct]/dil]} {
      clientput "detected $dilname"
      # highest score for $dilname
      enum_update [sct]/dil $dilname
      set crv $curves($dilname)
      ts curve $crv
    }
  }
  set mode [sctval [sct]]
  set lim [hval [sct]/warmlimit]
  set ts [silent 0 result ts]
  set window [hval [sct]/window]
  if {$mode == 1} {
    # warming up
    if {$ts < $lim} {
      sct coldtime $now
    }
    if {[silent 999 hval /tslope] > [hval [sct]/slopelimit]} {
      sct steeptime $now
    }
    if {$now > min([sct steeptime], [sct coldtime]) + $window} {
      # warm
      if {[sct steeptime] < [sct coldtime]} {
        clientput "stick is warm (slope < [hval [sct]/slopelimit] for more than $window sec)"
      } else {
        clientput "stick is warm (T > [hval [sct]/warmlimit] for more than $window sec)"
      }
      sct target 0
      check
      return idle
    }
  } elseif {$mode < 0} {
    # undef
    if {$ts != 0} {
      if {$now > [sct undeftime] + 120} {
        if {$ts > [hval [sct]/warmlimit]} {
          set mode 0
          clientput "stick is warm"
        } else {
          set mode 1
          clientput "stick is warming up"
        }
      }
      sct target $mode
      check
      return idle
    }
  } else {
    # warm or undef
    if {$ts > [hval [sct]/coldlimit]} {
      sct warmtime $now
    }
    if {[hval [sct]/dil] != 0 && $now > [sct warmtime] + $window} {
      # warmup
      sct target 1
      check
      return idle
    }
  }
  sct update $mode
  return idle
}
