//                           UNCLASSIFIED
/*-------------------------------------------------------------------------
RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS
AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO
UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO
RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS
CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS
OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON
COMPANY.

THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S.
GOVERNMENT.

UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
-------------------------------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.Threading;
using Raytheon.Common;
using System.IO;
using Raytheon.Instruments;
using Raytheon.Instruments.PowerSupply;

namespace MeasurementManagerLib
{
   /// <summary>
   /// A worker for iterating through each supply in the system, querying its' data, logging it out, and issuing callbacks to the host
   /// </summary>
   internal class PowerSupplyDataLogWorker : IWorkerInterface
   {
      #region PrivateClassMembers

      private bool _threadQuitControl;
      private AutoResetEvent _quitEvent;
      private StreamWriter _fileWriter;
      private readonly string _logFilePath;
      private readonly int _threadRestTimeMs;
      private readonly PowerSupplyMeasurementManager.PowerMonitorDelegate _callback;
      private readonly PowerSupplyMeasurementManager _controller;

      #endregion

      #region PrivateFunctions

      /// <summary>
      /// Finalizer
      /// </summary>
      ~PowerSupplyDataLogWorker()
      {
         Dispose(false);
      }

      /// <summary>
      /// Release of resources
      /// </summary>
      /// <param name="disposing"></param>
      protected virtual void Dispose(bool disposing)
      {
         try
         {
            if (disposing)
            {
               _fileWriter.Dispose();

               _quitEvent.Dispose();
            }
         }
         catch (Exception err)
         {
            try
            {
               ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
            }
            catch (Exception)
            {
               //Do not rethrow. Exception from error logger that has already been garbage collected
            }
         }
      }
      #endregion

      #region PublicFuctions

      /// <summary>
      /// The constructor
      /// </summary>
      /// <param name="controller">The controller for the power supplies</param>
      /// <param name="fileName">The file name to log the data to</param>
      /// <param name="threadRestTimeMs">The number os ms to rest after each iteration through the loop</param>
      /// <param name="callback">The host callback function. If null, no callback is issued</param>
      public PowerSupplyDataLogWorker(PowerSupplyMeasurementManager controller, string fileName, int threadRestTimeMs, PowerSupplyMeasurementManager.PowerMonitorDelegate callback)
      {
         _controller = controller;

         // these gets set in SetControlParams
         _logFilePath = fileName;
         _callback = callback;
         _threadRestTimeMs = threadRestTimeMs;

         _fileWriter = new StreamWriter(_logFilePath, true);

         _threadQuitControl = false;
         _quitEvent = new AutoResetEvent(false);
      }

      /// <summary>
      /// Dispose of this object. Needed for releasing thread/comm resources
      /// </summary>
      public void Dispose()
      {
         try
         {
            Dispose(true);

            GC.SuppressFinalize(this);
         }
         catch (Exception err)
         {
            try
            {
               ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
            }
            catch (Exception)
            {
               //Do not rethrow. Exception from error logger that has already been garbage collected
            }
         }
      }

      /// <summary>
      /// Loops thorugh each supply in the system, queries the status, logs it out and calls the host callback
      /// </summary>
      public void DoWork()
      {
         try
         {
            //Used to handle the labels at the top of the CSV log file generated
            const string LOG_PREFIX = "DateTime,Module,Voltage,VoltageSetpoint,Current,IsOutputOn,fault status";

            // callback error codes
            const int NO_ERROR = 0;
            const int ERROR = -1;

            List<string> powerModules = _controller.GetPowerModuleList();

            _fileWriter.WriteLine(LOG_PREFIX);

            while (_threadQuitControl == false)
            {
               try
               {
                  if (_quitEvent.WaitOne(_threadRestTimeMs))
                  {
                     _threadQuitControl = true;
                  }
                  else
                  {
                     //string callbackData = CALLBACK_PREFIX;
                     List<PowerMonitorCallbackData> callBackDataList = new List<PowerMonitorCallbackData>();

                     //get data from each supply
                     foreach (string powerModule in powerModules)
                     {
                        // check for quit event and exit if needed
                        if (_quitEvent.WaitOne(1) == true)
                        {
                           _threadQuitControl = true;

                           break;
                        }

                        PowerData data = _controller.ReadPowerData(powerModule);

                        PowerMonitorCallbackData callbackData;
                        callbackData.powerModule = powerModule;
                        callbackData.voltage = data.Voltage;
                        callbackData.voltageSetpoint = data.VoltageSetpoint;
                        callbackData.current = data.Current;
                        callbackData.outputStatus = data.OutputStatus;
                        callbackData.ovpocpStatus = data.FaultStatus;
                        callbackData.overVoltageProtectionValue = data.OverVoltageProtection;
                        callbackData.overCurrentProtectionValue = data.OverCurrentProtection;

                        callBackDataList.Add(callbackData);

                        string log = Util.GetTimeString() + "," + powerModule + "," + Convert.ToString(data.Voltage) + "," + Convert.ToString(data.VoltageSetpoint) + "," + Convert.ToString(data.Current) + "," + Convert.ToString(data.OutputStatus) + "," + Convert.ToString(data.FaultStatus);

                        // log out the data
                        _fileWriter.WriteLine(log);
                        _fileWriter.Flush();

                        // check for quit event and exit if needed
                        if (_quitEvent.WaitOne(1) == true)
                        {
                           _threadQuitControl = true;

                           break;
                        }
                     }

                     // At this point our return and log strings are both built, so return back the data string on the callback
                     if (_callback != null && _threadQuitControl == false && callBackDataList.Count != 0)
                     {
                        _callback(callBackDataList, NO_ERROR);
                     }
                  }
               }
               catch (Exception e)
               {
                  string msg = e.Message;

                  ErrorLogger.Instance().Write(msg + "\r\n" + e.StackTrace, ErrorLogger.LogLevel.ERROR);

                  _fileWriter.WriteLine(Util.GetTimeString() + ", " + msg);

                  // if callbacks are enabled, alert the host to the error
                  if (_callback != null && _threadQuitControl == false)
                  {
                     _callback(null, ERROR);
                  }
               }
            }

            ErrorLogger.Instance().Write("PowerSupplyDataLogWorker::DoWork() - exiting", ErrorLogger.LogLevel.INFO);
         }
         catch (Exception err)
         {
            ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace);
         }
      }

      /// <summary>
      /// Stops the thread, closes the datalogger and calls move file
      /// </summary>
      public void QuitWork()
      {
         _threadQuitControl = true;

         _quitEvent.Set();
      }

      #endregion
   }
}
