=begin
 ******************************************************************************
 * Copyright 1990-2024 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Event detection logic including image processing
 * Filename : event_detection.rb
 * Author   : Henthorn
 * Project  : Sedimentation Event Sensor
 * Version  : 1
 * Created  : Nov 2024
 * Modified : 
 ******************************************************************************
=end

##
# Refer to Rover-code home directory as base
#
require "#{ENV['ROVER_HOME']}/utils/rover_environment"
#

require "utils/misc"
require "control/supervisor"

class EventDetection
  include SyslogWriter
  attr_reader :num_bg, :num_rm, :lo_lim, :hi_lim, :lim_ratio
  attr_reader :num_samples, :samples_used

  DEFAULT_SAMPLES = 11     # number of available bottles on the trigger trap
  DEFAULT_BG = 20          # number of images to use as background to calculate attenuation
  DEFAULT_RM = 150         # number of image attn values to use as rolling mean for event detection
  DEFAULT_SED_LIM = 0.0111 # attenuation change to trigger event

  def initialize(lo, hi, lim_ratio, bg, rm, samples)
    @num_samples = samples
    @num_bg = bg
    @num_rm = rm
    @lo_lim = lo
    @hi_lim = hi
    @lim_ratio = lim_ratio
    # Setup defaults
    @samples_used = 0
    puts("_ sed instantiated: #{@lo_lim} #{@hi_lim} #{@num_bg} #{@num_rm}")

  end

  def samples_used?
    @samples_used
  end

  def samples_used=(used)
    @samples_used = used
  end

  # Return the %mission remaining / %samples remaining
  def calc_ratio()

    # Calculate %samples remaining. Use 100% if either
    # samples used or number of samples is 0 (also avoids div by zero)
    denominator = (@samples_used > 0 && @num_samples > 0) ? 1.0 - (@samples_used.to_f / @num_samples.to_f) : 1.0
    syslog("_ calc_ratio(): used:#{@samples_used} start:#{@num_samples} %samples: #{denominator}")

    # Calculate %mission remaining after removing @num_rm sites for rolling mean
    plan = Supervisor.instance.deployment.current_plan
    site_num = plan.site_num - @num_rm
    sites = plan.sites - @num_rm

    if (sites < 0)
      syslog("_ calc_ratio(): WARNING - the number of sites is less than rolling mean")
    end
    if (sites < 0 || site_num < 0)
      syslog("_ calc_ratio(): site_num:#{site_num} sites:#{sites}")
      return 1.0
    end

    numerator = (site_num > 0 && sites > 0) ? 1.0 - (site_num.to_f / sites.to_f) : 1.0
    syslog("_ calc_ratio(): site_num:#{site_num} sites:#{sites} % mission: #{numerator}")

    ratio = numerator.to_f / denominator.to_f
    syslog("_ calc_ratio(): #{ratio}")
    ratio
  end

  # Update the sed limit based ratio of remaining mission and remaining samples
  def update_sed_limit()
    # When we're out of samples use the lo_lim
    if (@samples_used >= @num_samples)
      syslog("_ update_sed_limit() out of samples, use lo_lim #{@lo_lim}")
      return @lo_lim
    end

    # Get the current ratio and return the appropriate limit
    use_lim = @lo_lim
    ratio = calc_ratio()
    syslog("_ update_sed_limit() mission ratio:#{ratio} limit ratio:#{@lim_ratio}")
    if (ratio >= @lim_ratio)
      use_lim = @hi_lim
    else
      use_lim = @lo_lim
    end
    syslog("_ update_sed_limit(): updated limit: #{use_lim}")
    return use_lim
    
    syslog("_ update_sed_limit() always use lo_lim for now #{@lo_lim}")
    return @lo_lim
  end

  def detect_with_image(image_filename)
    fake_atn = "2024-11-26 21:38:22.123640, /home/ses/barbo/logs/dep-2024.11.26-09-SED-AT-MARS-DECK2024/plan-01-1-per-hour-31-2024.11.26/data-08-fluoro_camera//SED_DECK2024_5min_Ext_241126-213718.jpg , 1.449833592213841 , 20"
    # TODO: Create a separate class for image processing
    # atn = sip.attenuation(image_filename)
    # For now perform the image processing here ...

    # First, convert B16 format to tiff then to jpg
    b2j = `bayer2sesjpg.sh #{image_filename}*.b16`
    tif = "#{image_filename}*.tiff"
    syslog(b2j)

    # Then, calculate the attenutation for the jpg while caching
    # the last @num_bg backgrounds in the sip database pickle file
    sip_db_file = DataLog.log_home + "sip_db_file.p"
    syslog("sip_attenuation.py -n #{@num_bg} -d #{sip_db_file} #{image_filename}*.jpg")
    atn = `sip_attenuation.py -n #{@num_bg} -d #{sip_db_file} #{image_filename}*.jpg`

    # If the attenuation result is good, add it to the CSV file and run detection.
    # No result just means there are not @num_bg backgrounds collected yet.
    if (atn != nil and atn.length > 0)
      site_num = Supervisor.instance.deployment.current_plan.site_num
      atn = fake_atn if (false) # (site_num % 32 == 0)  # for testing TODO: make this an option
      syslog(atn.strip!)

      # Create the CSV file if necessary
      csv_name = DataLog.deployment_data_home + "sip_results.csv"
      `echo \"Datetime,Filename,atn,Number in background\" >> #{csv_name}` unless (File.file?(csv_name))

      # Append the latest attenuation record to the CSV file for detection
      syslog("_, \"#{atn}\" >> #{csv_name}")
      `echo \"#{atn}\" >> #{csv_name}`

      # Perform variable threshold logic here ...
      # e.g., if (events detected too often) use_lim = hi_lim
      sed_lim = update_sed_limit()
      syslog("_ using sed limit #{sed_lim}")

      # Run the detection algorithm on the result records in the CSV file.
      syslog("_, Trigger_code_2024B_MARS.py #{csv_name} #{@num_rm}")
      newevent = `Trigger_code_2024B_MARS.py #{csv_name} #{@num_rm}`
      syslog("_, Detection, #{newevent.strip!}")
      syslog("_, sip_detection.py #{csv_name} #{@num_rm} #{sed_lim}")
      event = `sip_detection.py #{csv_name} #{@num_rm} #{sed_lim}`
      syslog("_, Detection, #{event.strip!}")

      # Report event if detected.
      # event == -1? Number of records is less than @num_rm
      # event == 0?  Latest image does not indicate an event
      # event == "Event detected"? Boom.
      Supervisor.instance.deployment.current_plan.sed_event() if (event.include?("Event detected"))
    else
      syslog("\n_, Still populating the image background cache...")
    end
    return Supervisor.instance.deployment.sed_event?
  end
end
