require "rover"
require "rover_thread"

#
# May07 - Modified to operate two rack assemblies, one at a time
#
#

class Measure < Monitor
  include LogHelper
  
  $DEFAULT_RECORD_TIME = 1  		# Time to record data from optode, in minutes
  $DEFAULT_RECORD_INTERVAL = 14	# Time in minutes to wait between optode reads
  $SHORT_RECORD_INTERVAL = 1	  # Time to wait on "short" mission cycle
  
  attr_reader :action, :thr

  def initialize (iterations=1)
    @thr   = 0
    @pct   = 0
    @abort = false
    @action = "Measure:Initialized"
    if iterations < 1
      syslog("! Measure: Iterations must be at least 1, not #{iterations}")
      @iterations = 1
    else
      @iterations = iterations
    end
  end

  def incrPercentage(inc)
    newPct = inc + @pct
    if (newPct < 100)
      @pct = newPct
    end
    syslog("_ Measure #{newPct} percent complete")
  end
  
  # Perform the incubation iterations and collect the data
  # 
  def acquireOptodeData
    ref_optode = Rover.instance.ref_optode
    s_optode = Rover.instance.starboard_optode
    p_optode = Rover.instance.port_optode
    relay  = Rover.instance.relay
    
    #Begin stirring
    relay.s_stirOn
    relay.p_stirOn

    # Do one or more recording sessions
    #
    iter = @iterations
    syslog("_ commencing #{iter} iterations")
    while (true)
      currentIter = 1 + (@iterations - iter)
      @action = "Measure:Acquiring Data (#{currentIter} of #{@iterations})"
      
      # Start recording
      #
      syslog("_ turning optodes on and recording data")
      relay.s_optodeOn      # turns on both starboard and reference optodes
      relay.p_optodeOn
      
      sleep(1)
      s_optode.run
      p_optode.run
      ref_optode.run
      sleep($DEFAULT_RECORD_TIME*60)
      
      # Stop
      #
      syslog("_ turning optodes off")
      s_optode.stop
      p_optode.stop
      ref_optode.stop
      relay.s_optodeOff    # turns off both starboard and reference optodes
      relay.p_optodeOff

      syslog("_ Finished recording #{currentIter} of #{@iterations}")

      iterPct = (70 / @iterations)
      puts "iterPct = #{iterPct}"      
      incrPercentage(iterPct)
      
      # Are we done now?
      #
      iter -= 1
      if (iter == 0 || self.abort?)
        syslog("_ We're done")
        break
      end
      
      if(Rover::TEST)
        syslog("_ Sleeping #{$SHORT_RECORD_INTERVAL} minutes until next recording session")
        sleep($SHORT_RECORD_INTERVAL*60)
      else
        syslog("_ Sleeping #{$DEFAULT_RECORD_INTERVAL} minutes until next recording session")
        sleep($DEFAULT_RECORD_INTERVAL*60)
      end
    end

    # Stop stirring
    relay.s_stirOff
    relay.p_stirOff
  end
  
  def reinit_optodes
    Rover.instance.starboard_optode = Aanderaa.new nil, "/dev/starboard_optode"
    Rover.instance.port_optode = Aanderaa.new nil, "/dev/port_optode"
    Rover.instance.ref_optode = Aanderaa.new nil, "/dev/ref_optode"
  end

  def imageCapture name = "test"
      # Turn on video server and capture an image of the measurement site
      #
      syslog("_ turning on video, waiting 30 sec")
      Rover.instance.relay.videoOn
      Rover.instance.relay.camerasOn
      sleep(30)               # Wait for server to boot
      
      sname = "star_" + name
      unless (Rover.instance.video.captureImage($STBD_CAMERA, name))
        syslog ("! Unable to capture starboard image of sediment")
      end
      
      sname = "port_" + name
      unless (Rover.instance.video.captureImage($PORT_CAMERA, name))
        syslog ("! Unable to capture port image of sediment")
      end
      
      syslog("_ turning off video")
      Rover.instance.relay.camerasOff
      Rover.instance.relay.videoOff
  end

  # Run the measure process
  # If abort signal is received we simply jump down to raising the rack
  # and 100% complete
  #
  def run
    @abort = false
    @thr = RoverThread.new do
    
      @pct = 0
      
      relay = Rover.instance.relay
      rack  = Rover.instance.rack
      
        
      # Take image before measurement
      @action = "Measure:Taking First Image"
      self.imageCapture("before")

      # Open chamber valves and lower chamber into sediment
      #
      unless abort?
        @action = "Measure:Lowering Starboard Chamber"
        syslog("_ Inserting Starboard chamber")
        rack.reinit($STBD_RACK)
        relay.s_valveOn
        result = rack.move_to_insert($STBD_RACK)
          
        unless (result)
          syslog ("! Unable to insert starboard chamber in sediment")
          self.abort
        end

        relay.s_valveOff
        relay.s_rackOff
        incrPercentage(5)
      end

      # Now port chamber
      unless abort?
        @action = "Measure:Lowering Port Chamber"
        syslog("_ Inserting port chamber")
        rack.reinit($PORT_RACK)
        relay.p_valveOn
        result = rack.move_to_insert($PORT_RACK)
          
        unless (result)
          syslog ("! Unable to insert port chamber in sediment")
          self.abort
        end

        relay.p_valveOff
        relay.p_rackOff
        incrPercentage(5)
      end

      unless abort?
        # Take another image of the measurement site
        #
        @action = "Measure:Taking Second Image"
        self.imageCapture("inserted")

      end
      
      unless abort?
     
        # Measure the oxygen in the chamber
        acquireOptodeData
        self.imageCapture("after")
     
      end
      
      if abort?
        @action = "Measure:Aborting - Homing Chambers"
      else
        @action = "Measure:Homing Chambers"
      end

      ###############################################################
      #        Move chambers back to home position
      ###############################################################
  
      # Move starboard chamber out of sediment
      #
      rack.reinit($STBD_RACK)
      relay.s_valveOn
      sleep(3)          # Allow the valves to open fully before lifting
      relay.s_stirOn

#      rack.forward(1)
#      rack.encoder_position=1100
#      syslog("_ Backing out stbd chamber")
#      rack.back(1000)

      if ($CLEAN_FIRST)
        relay.s_cleanOn
        syslog("_ Cleaning stbd chamber before lift")
      end
      
      # Now home the chamber
      #
      syslog("_ Home stbd chamber")
      rack.move_home($STBD_RACK)

      unless ($CLEAN_FIRST)
        relay.s_cleanOn
        syslog("_ Cleaning stbd chamber after lift")
        sleep(60)
      end
      
      # Turn off starboard equipment
      #
      relay.s_cleanOff
      relay.s_valveOff
      relay.s_rackOff
      relay.s_stirOff
      incrPercentage(5)
        
      # Move port rack out of sediment
      #
      rack.reinit($PORT_RACK)
      relay.p_valveOn
      sleep(3)          # Allow the valves to open fully before lifting
      relay.p_stirOn

#      rack.forward(1)
#      rack.encoder_position=1100
#      syslog("_ Backing out port chamber")
#      rack.back(1000)

      if ($CLEAN_FIRST)
        relay.p_cleanOn
        syslog("_ Cleaning port chamber before lift")
      end
      
      # Now home the chamber
      #
      syslog("_ Home port chamber")
      rack.move_home($PORT_RACK)

      unless ($CLEAN_FIRST)
        relay.p_cleanOn
        syslog("_ Cleaning port chamber after lift")
        sleep(60)
      end
      
      # Turn off port equipment
      #
      relay.p_cleanOff
      relay.p_valveOff
      relay.p_rackOff
      relay.p_stirOff
      incrPercentage(5)

      if abort?
        @action = "Measure:Aborted"
      else
        @action = "Measure:Initialized"
      end
      @pct = 100

    end      # thread
  end        # run

  def abort?
    return @abort
  end

  def abort
    syslog("! Measure: Received abort command")
    @abort = true
    @action = "Measure:Aborting"
    @thr.kill if @thr.alive?

    Rover.instance.motors.halt
        
    Rover.instance.relay.allOff
    
    Rover.instance.relay.s_valveOn
    Rover.instance.relay.s_rackOn
    sleep(2)
    Rover.instance.rack.reinit($STBD_RACK)
    Rover.instance.rack.move_home($STBD_RACK)
    Rover.instance.relay.s_valveOff
    Rover.instance.relay.s_rackOff

    Rover.instance.relay.p_valveOn
    Rover.instance.relay.p_rackOn
    sleep(2)
    Rover.instance.rack.reinit($PORT_RACK)
    Rover.instance.rack.move_home($PORT_RACK)
    Rover.instance.relay.p_valveOff
    Rover.instance.relay.p_rackOff

    return
  end
    
  def percentComplete
  #  self.synchronize do
      return @pct
   # end
  end

  def currentAction
    return @action
  end
  
private 
  
  def percentComplete=p
#    self.synchronize do
      op = @pct
      @pct = p
      return op
 #   end
  end
  
end        # class Measure
