# miscelleneous utilities
require "sampler"

class Shaft
  def connect another, selfDir=nil, otherDir=nil
  #connect one shaft (valve) to another
    cThread = Thread :connect do
      dial another.intern, selfDir
    end
    another.dial intern, otherDir
    cThread.join
    self
  end
end


module Arm
#complete manipulator arm assembly (Hand, Forearm, and Elbow)

  def Arm.to destination
    unless Elbow.position == Elbow.at(destination)
      Forearm.to :retract, MFretract
      Elbow.to destination
    end
    move = Thread :moveArm do
      Forearm.to destination, MFretract
    end
    Delay.sleep .05
    Forearm.configure ForearmConfig
    move.join
    self
  end
  
  def Arm.grab start, destination=nil
    to start
    Hand.close
    to destination if destination
    self
  end
  
  def Arm.retract
    Hand.open
    Forearm.to :retract, MFretract
    self
  end

  def Arm.releaseAt destination
    to destination
    retract
  end
  
  def Arm.extend
    Forearm.to Elbow.position.base
    self
  end
  
  def Arm.ready!
    Forearm.home.retract
    Elbow.home.to :home
    self
  end
  
  def Arm.extended? elbowPosition=Elbow.position, forearmPosition=Forearm.position
  #return true if Arm is extended properly for current Elbow position
    elbowBase = elbowPosition.base
    return false unless Elbow[elbowBase] == elbowPosition  #Elbow out of position
    (Forearm[elbowBase].raw - forearmPosition.raw).abs <= Forearm.slop
  end
  
  def Arm.retracted? forearmPosition=Forearm.position
    forearmPosition == Forearm[:retracted]
  end
  
  def Arm.at? station
  #return true iff Arm is extended at the specified processing station
    elbowPosition=Elbow.position
    elbowPosition==Elbow[station] and Arm.extended? elbowPosition
  end
  
  def Arm.ready?
    not (Forearm.status.lost or Elbow.status.lost)
  end
  
  def Arm.asIRBtext
    elbowPosition = Elbow.position
    forearmPosition = Forearm.position
    forearmTxt = "Forearm retracted"
    unless retracted? forearmPosition
      if extended? elbowPosition, forearmPosition
        return "Arm at #{elbowPosition}, #{Hand.asIRBtext}"
      else
        forearmTxt = forearmPosition.asIRBtext
      end
    end   
    "#{elbowPosition.asIRBtext}, #{forearmTxt}, #{Hand.asIRBtext}"
  end
  
end  #module Arm


class << SE  #up and down are reversed from moveUp and moveDown
  def up puckCount=nil, tmpCfg=nil, maxDuration=@maxDuration
    if puckCount.is_a? Numeric
      moveDown(puckCount, tmpCfg, maxDuration)
    else  #if puckCount not Numeric, assume it is actually tmpCfg
      # effectively -- SE.up tmpCfg=nil, maxDuration=@maxDuration
      tmpCfg = maxDuration unless tmpCfg
      moveTo(:up, puckCount, tmpCfg)
    end   
  end
  def down puckCount=nil, tmpCfg=nil, maxDuration=@maxDuration
    if puckCount.is_a? Numeric
      moveUp(puckCount, tmpCfg, maxDuration)
    else  #if puckCount not Numeric, assume it is actually tmpCfg
      # effectively -- SE.down tmpCfg=nil, maxDuration=@maxDuration
      tmpCfg = maxDuration unless tmpCfg
      moveTo(:down, puckCount, tmpCfg)
    end   
  end
  
  def rawId counts, slop=@slop
  #given raw position in counts, return
  # corresponding position
    if counts > SE.raw(:bottom)-slop or (counts-SE.raw(:top)).abs <= slop
      baseRawId counts, slop #report down as :down, not x.yy pucks
    else
      super
    end
  end

  def position slop=@slop
  #return the named position if top or botom, else pucks below top plate
    rawId rawPosition, slop
  end

end


class << CC
  def close (*args)
  #closing the collection clamp causes the next sampling
  #to recalibrate pressure sensors and reset sampling speed
    result = to (:close, *args)
    Sampler.forgetCalibration.inhaleConfig = SSinhale
    result
  end
end  


module FlushPuck

  def self.load
    Log.record "Loading FlushPuck"
    raise "Collection Clamp is already closed!" if CC.closed?
    Arm.grab :flush, :collection
    CC.close
    Arm.retract
  end
  
  def self.unload
    Log.record "Unloading FlushPuck"
    Arm.grab :collection
    CC.open
    Arm.releaseAt :flush
  end
  
  def self.ready?
    Arm.ready? and not CC.status.lost
  end
  def self.ready!
    Arm.ready! unless Arm.ready?
    CC.home.open
  end
          
end

Flush = FlushPuck

    
