using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHI.Premium.System;

namespace Logger
{
    [Serializable]
    public class LogEntry : ICloneable
    {
        public enum             LogEntryTypes { Event, Comment, TBA };
        private BitArray        _fieldValid;
        private enum            _members { TimeStamp, MessageType, Comment, Y1, Y2, Pid_I, V_SetPoint, P_SetPoint, 
                                           Current_P, Previous_P, Platform_V, Unclipped_PID, Clipped_PID, Elmo_CPS, 
                                           Bellows_MM };
        private DateTime        _timeStamp;
        private LogEntryTypes   _logEntryType;
        private double          _y1;
        private double          _y2;
        private double          _pid_I;
        private double          _velocitySetpoint;
        private double          _pressureSetpoint;
        private double          _currentPressure;
        private double          _previousPressure;
        private double          _platformVelocity;
        private double          _unclipped_PID_Output_V;
        private double          _clipped_PID_Output_U;
        private double          _elmoSpeed_CPS;
        private double          _bellowsPosition;
        private byte[]          _comment;

        private static StringBuilder _sb;

        public LogEntry()
        {
            _fieldValid = new BitArray();
            _comment = new byte[152];
            _sb = new StringBuilder(256);
            Init();
        }

        public void Init()
        {
            _fieldValid.ClearAll();
            _timeStamp = DateTime.Now;
            _fieldValid.Set((int) _members.TimeStamp);
            _y1 = Double.NaN;
            _y2 = Double.NaN;
            _pid_I = Double.NaN;
            _velocitySetpoint = Double.NaN;
            _pressureSetpoint = Double.NaN;
            _currentPressure = Double.NaN;
            _previousPressure = Double.NaN;
            _platformVelocity = Double.NaN;
            _unclipped_PID_Output_V = Double.NaN;
            _clipped_PID_Output_U = Double.NaN;
            _elmoSpeed_CPS = Double.NaN;
            _bellowsPosition = Double.NaN;
        }

        public object Clone()
        {
            return this.MemberwiseClone();
        }

        public void Serialize(ref byte[] data)
        {
            // Utility.InsertValueIntoArray(data, 0, 8, (long) _y1);// at offset 0
            Util.InsertValueIntoArray((long) _y1, data, 4);// at offset 4
        }

        public override string ToString()
        {
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.TimeStamp))
                _sb.Append(_timeStamp.ToString());
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.MessageType))
                _sb.Append(EventToString(_logEntryType));
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Comment))
                _sb.Append(new String(System.Text.Encoding.UTF8.GetChars(_comment)));
            _sb.Append("\t");
            if (_fieldValid.IsSet((int) _members.V_SetPoint))
                _sb.AppendFormat("1) {0}", _velocitySetpoint);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.P_SetPoint))
                _sb.AppendFormat("1) {0}", _pressureSetpoint);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Current_P))
                _sb.AppendFormat("1) {0}", _currentPressure);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Platform_V))
                _sb.AppendFormat("1) {0}", _platformVelocity);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Y1))
                _sb.AppendFormat("1) {0}", _y1);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Y2))
                _sb.AppendFormat("1) {0}", _y2);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Unclipped_PID))
                _sb.AppendFormat("1) {0}", _unclipped_PID_Output_V);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Clipped_PID))
                _sb.AppendFormat("1) {0}", _clipped_PID_Output_U);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Elmo_CPS))
                _sb.AppendFormat("1) {0}", _elmoSpeed_CPS);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Pid_I))
                _sb.AppendFormat("1) {0}", _pid_I);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Previous_P))
                _sb.AppendFormat("1) {0}", _previousPressure);
            _sb.Append("\t");
            if (_fieldValid.IsSet((int)_members.Bellows_MM))
                _sb.AppendFormat("1) {0}", _bellowsPosition);
            _sb.Append("\r\n");
            return _sb.ToString();
        }

        public DateTime TimeStamp
        {
            get { return _timeStamp; }
            set { _fieldValid.Set((int) _members.TimeStamp);  _timeStamp = value; }
        }

        public LogEntryTypes LogEvent
        {
            get { return _logEntryType; }
            set { _fieldValid.Set((int)_members.MessageType); _logEntryType = value; }
        }

        public double Y1
        {
            get { return _y1; }
            set { _fieldValid.Set((int) _members.Y1); _y1 = value; }
        }

        public double Y2
        {
            get { return _y2; }
            set { _fieldValid.Set((int)_members.Y2); _y2 = value; }
        }
        
        public double PID_I
        {
            get { return _pid_I; }
            set { _fieldValid.Set((int)_members.Pid_I); _pid_I = value; }
        }

        public double VelocitySetpoint
        {
            get { return _velocitySetpoint; }
            set { _fieldValid.Set((int)_members.V_SetPoint); _velocitySetpoint = value; }
        }

        public double PressureSetpoint
        {
            get { return _pressureSetpoint; }
            set { _fieldValid.Set((int)_members.P_SetPoint); _pressureSetpoint = value; }
        }

        public double CurrentPressure
        {
            get { return _currentPressure; }
            set { _fieldValid.Set((int)_members.Current_P); _currentPressure = value; }
        }

        public double PreviousPressure
        {
            get { return _previousPressure; }
            set { _fieldValid.Set((int)_members.Previous_P); _previousPressure = value; }
        }

        public double PlatformVelocity
        {
            get { return _platformVelocity; }
            set { _fieldValid.Set((int)_members.Platform_V); _platformVelocity = value; }
        }

        public double Unclipped_PID_Output_V
        {
            get { return _unclipped_PID_Output_V; }
            set { _fieldValid.Set((int)_members.Unclipped_PID); _unclipped_PID_Output_V = value; }
        }

        public double Clipped_PID_Output_U
        {
            get { return _clipped_PID_Output_U; }
            set { _fieldValid.Set((int)_members.Clipped_PID); _clipped_PID_Output_U = value; }
        }

        public double ElmoSpeed_CPS
        {
            get { return _elmoSpeed_CPS; }
            set { _fieldValid.Set((int)_members.Elmo_CPS); _elmoSpeed_CPS = value; }
        }

        public double BellowsPosition
        {
            get { return _bellowsPosition; }
            set { _fieldValid.Set((int)_members.Bellows_MM); _bellowsPosition = value; }
        }

        public String Comment
        {
            get { return _comment.ToString(); }
            set { _fieldValid.Set((int)_members.Comment); _comment = System.Text.Encoding.UTF8.GetBytes(value); }
        }
        
        private string EventToString(LogEntryTypes ev)
        {
            switch (ev)
            { 
                case LogEntryTypes.Event:
                    return "Event";

                case LogEntryTypes.Comment:
                    return "Comment";

                case LogEntryTypes.TBA:
                    return "TBA";

                default:
                    return "WTF";
            }
        }
    }
}
