#region << Using Directives >>
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Volpe.Cafe.Data;
using Volpe.Cafe.Model;
using Volpe.Cafe.Settings;
using Volpe.Cafe.Utils;
#endregion
namespace Volpe.Cafe.UI.Panels
{
    public class SessionPanel : UserControl
    {
        #region 
        sealed class SessionMessages
        {
            public const string CAFEModelError = "CAFE Model Error";
            public const string CAFEModel      = "CAFE Model";
            public const string NEW_STATUS_SessionCreated = "New session created.";
            public const string OPEN_FileNotFound = "Error opening session file.\n\nThe specified file cannot be found on disk.";
            public const string OPEN_SessionNotValid = "Error opening session file.\n\nThe specified file may not represent a valid session, or the session format is no longer supported.";
            public const string OPEN_STATUS_SelectSessionFile = "Please select the session file you would like to open ...";
            public const string OPEN_STATUS_LoadingSession = "Loading session ...";
            public const string OPEN_STATUS_SessionLoadingFailed = "Session loading failed.";
            public const string OPEN_STATUS_SessionNotLoaded = "Session not loaded.";
            public const string OPEN_STATUS_SessionLoaded = "Session loaded.";
            public const string OPEN_STATUS_SessionLoadedReadOnly = "Session loaded as read-only.";
            public const string SAVE_SessionRunning = "The session is currently running.\n\nPlease wait for modeling to complete, or stop the session before saving again.";
            public const string SAVE_STATUS_SavingSession = "Saving session ...";
            public const string SAVE_STATUS_SessionSaved = "Session saved.";
            public const string CLOSE_SessionRunning = "The session is currently running.\n\nPlease wait for modeling to complete, or stop the session before closing.";
            public const string CLOSE_SessionNotSaved = "The session has not been saved yet.\n\nWould you like to save the changes before closing?";
            public const string CLOSE_CloseSession = "A CAFE Model session is currently open and will be closed.\n\nAre you sure you would like to proceed?";
            public const string CLOSE_STATUS_SessionClosed = "Session closed.";
            public const string START_SessionRunning = "The session is already running.";
            public const string START_NoComplianceModel = "The session cannot be run since no valid compliance model has been selected.\n\nPlease open the Modeling Settings window to select a compliance model you wish to run.";
            public const string START_SessionReadOnly = "The session cannot be run because it was opened as read-only.";
            public const string STOP_SessionNotRunning = "The session is not currently running.";
            public const string COMPLIANCE_STATUS_StartRequested = "Starting the Modeling Process ...";
            public const string COMPLIANCE_STATUS_Running        = "Model Running ...";
            public const string COMPLIANCE_STATUS_StopRequested  = "Stopping the Modeling Process ...";
            public const string COMPLIANCE_STATUS_Stopped        = "Modeling Stopped.";
            public const string COMPLIANCE_STATUS_Completed      = "Modeling Completed!";
            public const string COMPLIANCE_STATUS_Unstarted      = "The Modeling Process has not Started.";
        }
        #endregion
        #region 
        [Browsable(true)]
        [Category("Behavior")]
        public event EventHandler SessionUpdating;
        [Browsable(true)]
        [Category("Behavior")]
        public event EventHandler SessionNameChanged;
        #endregion
        #region 
        public SessionPanel()
        {
            this.InitializeComponent();
        }
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
        #endregion
        #region 
        #region 
        void InitializeComponent()
        {
            this.ux_splitter = new System.Windows.Forms.Splitter();
            this.ux_progress = new System.Windows.Forms.RichTextBox();
            this.ux_statusPanel = new System.Windows.Forms.Panel();
            this.ux_additionalInfo = new System.Windows.Forms.RichTextBox();
            this.ux_runtime = new System.Windows.Forms.Label();
            this.ux_progressPanel = new System.Windows.Forms.Panel();
            this.ux_statusPanel.SuspendLayout();
            this.ux_progressPanel.SuspendLayout();
            this.SuspendLayout();
            this.ux_splitter.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ux_splitter.Location = new System.Drawing.Point(0, 211);
            this.ux_splitter.Name = "ux_splitter";
            this.ux_splitter.Size = new System.Drawing.Size(472, 2);
            this.ux_splitter.TabIndex = 5;
            this.ux_splitter.TabStop = false;
            this.ux_progress.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_progress.BackColor = System.Drawing.SystemColors.Window;
            this.ux_progress.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.ux_progress.DetectUrls = false;
            this.ux_progress.Font = new System.Drawing.Font("Lucida Console", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.ux_progress.Location = new System.Drawing.Point(8, 8);
            this.ux_progress.Name = "ux_progress";
            this.ux_progress.ReadOnly = true;
            this.ux_progress.Size = new System.Drawing.Size(456, 192);
            this.ux_progress.TabIndex = 1;
            this.ux_progress.Text = "Ready";
            this.ux_progress.WordWrap = false;
            this.ux_statusPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.ux_statusPanel.Controls.Add(this.ux_additionalInfo);
            this.ux_statusPanel.Controls.Add(this.ux_runtime);
            this.ux_statusPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ux_statusPanel.Location = new System.Drawing.Point(0, 213);
            this.ux_statusPanel.Name = "ux_statusPanel";
            this.ux_statusPanel.Size = new System.Drawing.Size(472, 80);
            this.ux_statusPanel.TabIndex = 2;
            this.ux_additionalInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.ux_additionalInfo.BackColor = System.Drawing.SystemColors.Control;
            this.ux_additionalInfo.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.ux_additionalInfo.Location = new System.Drawing.Point(8, 32);
            this.ux_additionalInfo.Name = "ux_additionalInfo";
            this.ux_additionalInfo.ReadOnly = true;
            this.ux_additionalInfo.Size = new System.Drawing.Size(456, 40);
            this.ux_additionalInfo.TabIndex = 1;
            this.ux_additionalInfo.TabStop = false;
            this.ux_additionalInfo.Text = "";
            this.ux_additionalInfo.WordWrap = false;
            this.ux_runtime.AutoSize = true;
            this.ux_runtime.Location = new System.Drawing.Point(8, 8);
            this.ux_runtime.Name = "ux_runtime";
            this.ux_runtime.Size = new System.Drawing.Size(58, 13);
            this.ux_runtime.TabIndex = 0;
            this.ux_runtime.Text = "Runtime: 0";
            this.ux_progressPanel.BackColor = System.Drawing.Color.White;
            this.ux_progressPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.ux_progressPanel.Controls.Add(this.ux_progress);
            this.ux_progressPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.ux_progressPanel.Location = new System.Drawing.Point(0, 0);
            this.ux_progressPanel.Name = "ux_progressPanel";
            this.ux_progressPanel.Size = new System.Drawing.Size(472, 211);
            this.ux_progressPanel.TabIndex = 6;
            this.Controls.Add(this.ux_progressPanel);
            this.Controls.Add(this.ux_splitter);
            this.Controls.Add(this.ux_statusPanel);
            this.Name = "SessionPanel";
            this.Size = new System.Drawing.Size(472, 293);
            this.ux_statusPanel.ResumeLayout(false);
            this.ux_statusPanel.PerformLayout();
            this.ux_progressPanel.ResumeLayout(false);
            this.ResumeLayout(false);
        }
        #endregion
        #region 
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
        }
        #endregion
        #region 
        protected virtual void OnSessionUpdating()
        {
            if (this.SessionUpdating != null) { this.SessionUpdating(this, EventArgs.Empty); }
        }
        protected virtual void OnSessionNameChanged()
        {
            if (this.SessionNameChanged != null) { this.SessionNameChanged(this, EventArgs.Empty); }
        }
        #endregion
        public void CreateNewSession()
        {
            this.CreateNewSession(true);
        }
        public void CreateNewSession(bool makeVisible)
        {
            if (this._isOpen && !this.CloseSession(true)) { return; }
            this._compliance      = null;
            this._data            = null;
            this._settings        = new ModelingSettings();
            this._index           = SessionCount++;
            this._path            = null;
            this._name            = null;
            this._status          = null;
            this._refreshInterval = RefreshIntervalNormal;
            this._isOpen          = true;
            this._readOnly        = false;
            this._saveRequired    = true;
            this._stopRequested   = false;
            this.UpdateSessionName();
            this.RefreshSession();
            if (makeVisible) { this.Visible = true; }
            this.UpdateStatus(SessionMessages.NEW_STATUS_SessionCreated);
        }
        public bool OpenSession()
        {
            return this.OpenSession(false);
        }
        public bool OpenSession(bool silent)
        {
            return this.OpenSession_Internal(null, true, silent);
        }
        public bool OpenSession(string path)
        {
            return this.OpenSession(path, false);
        }
        public bool OpenSession(string path, bool silent)
        {
            return this.OpenSession_Internal(path, false, silent);
        }
        bool OpenSession_Internal(string path, bool displayOpen, bool silent)
        {
            if (this._isOpen && !this.CloseSession(true)) { return false; }
            if (displayOpen)
            {   
                this.UpdateStatus(SessionMessages.OPEN_STATUS_SelectSessionFile);
                OpenFileDialog dlg = new OpenFileDialog();
                dlg.Filter = "All Files (*.*)|*.*|CAFE Model Session Data (*.cmsd)|*.cmsd";
                dlg.FilterIndex = 2;
                dlg.Title = "Please select the session file you would like to open:";
                if (dlg.ShowDialog() == DialogResult.OK) { this._path = dlg.FileName; }
                else { this.UpdateStatus(SessionMessages.OPEN_STATUS_SessionNotLoaded); return false; }
            }
            else
            {   
                this._path = path;
            }
            if (!File.Exists(this._path))
            {
                this.UpdateStatus(SessionMessages.OPEN_STATUS_SessionLoadingFailed);
                if (!silent) { this.ShowErrorPrompt(SessionMessages.OPEN_FileNotFound); }
                return false;
            }
            this.UpdateStatus(SessionMessages.OPEN_STATUS_LoadingSession);
            BinaryFormatter bf = new BinaryFormatter();
            Stream dataStream = null;
            GZipStream gzip = null;
            try
            {   
                dataStream = new MemoryStream();
                gzip = new GZipStream(new FileStream(this._path, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress);
                byte[] gzipBuf = new byte[4096];
                int gzipBufCount = 0;
                do
                {
                    dataStream.Write(gzipBuf, 0, gzipBufCount);
                    gzipBufCount = gzip.Read(gzipBuf, 0, gzipBuf.Length);
                } while (gzipBufCount > 0);
                dataStream.Seek(0, SeekOrigin.Begin);
                object[] sessionData = (object[])bf.Deserialize(dataStream);
                this._compliance      = (ICompliance     )sessionData[0];
                this._data            = (Industry        )sessionData[1];
                this._settings        = (ModelingSettings)sessionData[2];
                this._refreshInterval = (int             )sessionData[3];
                FileInfo fileInfo   = new FileInfo(this._path);
                this._isOpen        = true;
                this._readOnly      = fileInfo.IsReadOnly;
                this._saveRequired  = this._readOnly;
                this._stopRequested = false;
                if (!this._readOnly) { fileInfo.IsReadOnly = true; }
                this.UpdateSessionName();
                this.RefreshSession();
                this.UpdateStatus((this._readOnly) ?
                    SessionMessages.OPEN_STATUS_SessionLoadedReadOnly :
                    SessionMessages.OPEN_STATUS_SessionLoaded);
                RecentItems.AddEntry(this._path);
                return true;
            }
            catch (Exception ex)
            {   
                this.UpdateStatus(SessionMessages.OPEN_STATUS_SessionLoadingFailed);
                Console.WriteLine(ex.ToString());
                if (!silent) { this.ShowErrorPrompt(SessionMessages.OPEN_SessionNotValid); }
                return false;
            }
            finally
            {   
                if (dataStream != null) { dataStream.Close(); }
                if (gzip       != null) { gzip      .Close(); }
            }
        }
        public bool CloseSession()
        {
            return this.CloseSession(false);
        }
        public bool CloseSession(bool confirmClose)
        {
            if (!this._isOpen) { return true; }
            if (this.Running)
            {   
                MessageBox.Show(SessionMessages.CLOSE_SessionRunning, SessionMessages.CAFEModel, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return false;
            }
            if (this._saveRequired || confirmClose)
            {   
                DialogResult dr;
                if (this._saveRequired)
                {   
                    dr = MessageBox.Show(SessionMessages.CLOSE_SessionNotSaved, SessionMessages.CAFEModel,
                        MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3);
                }
                else
                {   
                    dr = MessageBox.Show(SessionMessages.CLOSE_CloseSession, SessionMessages.CAFEModel,
                        MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                }
                if (dr == DialogResult.Cancel || (!this._saveRequired && dr == DialogResult.No))
                {   
                    return false;
                }
                else if (this._saveRequired && dr == DialogResult.Yes)
                {   
                    if (!this.SaveSession()) { return false; }
                }
            }
            if (!this._readOnly && File.Exists(this._path))
            {
                (new FileInfo(this._path)).IsReadOnly = false;
            }
            this._compliance      = null;
            this._data            = null;
            this._settings        = null;
            this._index           = -1;
            this._path            = null;
            this._name            = null;
            this._status          = null;
            this._refreshInterval = -1;
            this._isOpen          = false;
            this._readOnly        = false;
            this._saveRequired    = false;
            this._stopRequested   = false;
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            this.UpdateSessionName();
            this.UpdateStatus(SessionMessages.CLOSE_STATUS_SessionClosed);
            return true;
        }
        public bool SaveSession()
        {
            return this.SaveSession_Internal(false, null);
        }
        public bool SaveSession(string name)
        {
            if (name != null && name.Trim() != string.Empty && name != this.SessionName)
            {
                this._saveRequired = true;
            }
            return this.SaveSession_Internal(false, name);
        }
        public bool SaveSessionAs()
        {
            return this.SaveSession_Internal(true, null);
        }
        bool SaveSession_Internal(bool displaySaveAs, string name)
        {
            if (!this._isOpen || (!displaySaveAs && !this._saveRequired)) { return false; }
            if (this.Running)
            {
                MessageBox.Show(SessionMessages.SAVE_SessionRunning, SessionMessages.CAFEModel, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return false;
            }
            bool silent = false;
            if (name != null)
            {
                name = name.Trim();
                if (File.Exists(this._path) && name != string.Empty)
                {
                    this._path = Path.GetDirectoryName(this._path) + "\\" + name + ".cmsd";
                    silent = true;
                }
            }
            if (File.Exists(this._path) && !this._readOnly)
            {
                (new FileInfo(this._path)).IsReadOnly = false;
            }
            if (displaySaveAs || this._path == null || (!silent && (!File.Exists(this._path) ||
                (File.GetAttributes(this._path) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)))
            {
                SaveFileDialog dlg = new SaveFileDialog();
                dlg.FileName = File.Exists(this._path) ? this._path : (name != null) ? name + ".cmsd" : this.SessionName + ".cmsd";
                dlg.Filter = "CAFE Model Session Data (*.cmsd)|*.cmsd";
                dlg.Title = "Please specify the location where you would like to save the '" +
                    ((name != null) ? name : this.SessionName) + "' session:";
                if (dlg.ShowDialog() == DialogResult.OK)
                {   
                    this._path = dlg.FileName;
                }
                else
                {   
                    if (File.Exists(this._path) && !this._readOnly)
                    {
                        File.SetAttributes(this._path, FileAttributes.ReadOnly);
                    }
                    return false;
                }
            }
            this.UpdateStatus(SessionMessages.SAVE_STATUS_SavingSession);
            object[] sessionData = new object[4];
            ICompliance complianceModel = null;
            if (this._compliance != null)
            {
                complianceModel              = this._compliance.CreateNew();
                complianceModel.UserNotes    = this._compliance.UserNotes;
                complianceModel.UserKeywords = this._compliance.UserKeywords;
            }
            sessionData[0] = complianceModel;
            sessionData[1] = this._data;
            sessionData[2] = this._settings;
            sessionData[3] = this._refreshInterval;
            MemoryStream dataStream = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(dataStream, sessionData);
            dataStream.Seek(0, SeekOrigin.Begin);
            GZipStream gzip = new GZipStream(new FileStream(this._path, FileMode.Create, FileAccess.ReadWrite, FileShare.None), CompressionMode.Compress);
            byte[] gzipBuf = new byte[4096];
            int gzipBufCount = 0;
            do
            {
                gzip.Write(gzipBuf, 0, gzipBufCount);
                gzipBufCount = dataStream.Read(gzipBuf, 0, gzipBuf.Length);
            } while (gzipBufCount > 0);
            gzip.Close();
            dataStream.Close();
            File.SetAttributes(this._path, FileAttributes.ReadOnly);
            this._saveRequired = false;
            this._readOnly     = false;
            this.UpdateSessionName();
            this.RefreshSession();
            this.UpdateStatus(SessionMessages.SAVE_STATUS_SessionSaved);
            RecentItems.AddEntry(this._path);
            return true;
        }
        public void StartModeling()
        {
            if (!this._isOpen) { return; }
            if (this.Running)
            {
                MessageBox.Show(SessionMessages.START_SessionRunning, SessionMessages.CAFEModel, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (this.ReadOnly)
            {
                MessageBox.Show(SessionMessages.START_SessionReadOnly, SessionMessages.CAFEModel, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (this._compliance == null)
            {
                MessageBox.Show(SessionMessages.START_NoComplianceModel, SessionMessages.CAFEModelError, MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);
                return;
            }
            this._stopRequested = false;
            this._compliance.ModelingChanged += new ModelingEventHandler(this.Compliance_ModelingChanged);
            this._compliance.Prompt          += new PromptEventHandler  (this.Compliance_Prompt);
            Industry         complianceData     = (this._data     == null) ? null : this._data    .Clone();
            ModelingSettings complianceSettings = (this._settings == null) ? null : this._settings.Clone();
            if (complianceSettings != null) { complianceSettings.OutputSettings.OutputPath += ("\\" + this.SessionName); }
            this._compliance.Start(complianceData, complianceSettings);
            this.RefreshSession();
            this.InitRefreshSessionThread();
        }
        public void StopModeling()
        {
            if (!this._isOpen) { return; }
            if (!this.Running)
            {
                MessageBox.Show(SessionMessages.STOP_SessionNotRunning, SessionMessages.CAFEModel, MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
                return;
            }
            if (this._stopRequested)
            {
                this._compliance.Abort(false);
                this._stopRequested = false;
            }
            else
            {
                this._compliance.Abort(true);
                this._stopRequested = true;
                this.InitWaitToStopThread();
            }
        }
        void Compliance_ModelingChanged(object sender, ModelingEventArgs e)
        {
            ModelingState state = e.State;
            string status = string.Empty;
            if      (state == ModelingState.StartRequested) { status = SessionMessages.COMPLIANCE_STATUS_StartRequested; }
            else if (state == ModelingState.Running       ) { status = SessionMessages.COMPLIANCE_STATUS_Running;        }
            else if (state == ModelingState.StopRequested ) { status = SessionMessages.COMPLIANCE_STATUS_StopRequested;  }
            else if (state == ModelingState.Stopped       ) { status = SessionMessages.COMPLIANCE_STATUS_Stopped;        }
            else if (state == ModelingState.Completed     ) { status = SessionMessages.COMPLIANCE_STATUS_Completed;      }
            else if (state == ModelingState.Unstarted     ) { status = SessionMessages.COMPLIANCE_STATUS_Unstarted;      }
            if (state == ModelingState.Stopped || state == ModelingState.Completed)
            {   
                this._compliance.ModelingChanged -= new ModelingEventHandler(this.Compliance_ModelingChanged);
                this._compliance.Prompt          -= new PromptEventHandler  (this.Compliance_Prompt);
            }
            this.RefreshSession();
            this.UpdateStatus(status);
        }
        void Compliance_Prompt(object sender, PromptEventArgs e)
        {
            MessageBoxButtons buttons =
                (e.PromptOption == PromptOption.OkCancel   ) ? MessageBoxButtons.OKCancel    :
                (e.PromptOption == PromptOption.YesNoCancel) ? MessageBoxButtons.YesNoCancel :
                (e.PromptOption == PromptOption.YesNo      ) ? MessageBoxButtons.YesNo       : MessageBoxButtons.OK;
            MessageBoxDefaultButton defaultButton =
                (e.PromptOption == PromptOption.YesNoCancel) ? MessageBoxDefaultButton.Button3 :
                (e.PromptOption == PromptOption.YesNo ||
                 e.PromptOption == PromptOption.OkCancel   ) ? MessageBoxDefaultButton.Button2 : MessageBoxDefaultButton.Button1;
            DialogResult dr =  MessageBox.Show(e.Message, e.Title, buttons, MessageBoxIcon.Information, defaultButton);
            e.PromptResult =
                (dr == DialogResult.OK    ) ? PromptResult.Ok     :
                (dr == DialogResult.Cancel) ? PromptResult.Cancel :
                (dr == DialogResult.Yes   ) ? PromptResult.Yes    :
                (dr == DialogResult.No    ) ? PromptResult.No     : PromptResult.None;
        }
        void InitRefreshSessionThread()
        {
            Thread refreshThread = new Thread(new ThreadStart(this.RefreshSessionThread));
            refreshThread.Name = "Session-" + this.SessionName + "::SessionRefreshThread";
            refreshThread.Start();
        }
        void RefreshSessionThread()
        {
            while (this.Running)
            {
                for (int i = 0; i < this._refreshInterval / SessionPanel.MinRefreshInterval; i++)
                {
                    Thread.Sleep(SessionPanel.MinRefreshInterval);
                    if (!this.Running) { break; }
                }
                if (this._refreshInterval == -1) { Thread.Sleep(500); } else { this.RefreshSession(); }
            }
            this.RefreshSession();
        }
        void InitWaitToStopThread()
        {
            Thread waitToStopThread = new Thread(new ThreadStart(this.WaitToStopThread));
            waitToStopThread.Name = "Session-" + this.SessionName + "::WaitToStopThread";
            waitToStopThread.Start();
        }
        void WaitToStopThread()
        {
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(500);
                if (!this._stopRequested || !this.Running) { return; }
            }
            this._stopRequested = false;
        }
        public void RefreshSession()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EmptyEventHandler(this.RefreshSession));
                return;
            }
            if (this.Running)
            {   
                IModelingProgress progress = this._compliance.Progress;
                StringBuilder sb = new StringBuilder();
                if (this._refreshInterval == -1)
                {
                    sb.Append("Automatic refreshing is currently paused.\n(Press F5 to refresh manually.)\n\n");
                }
                if (progress == null || (progress.ProgressString == null && progress.Scenario == null))
                {
                    if (this._refreshInterval != -1) { sb.Append("Refreshing compliance model progress ..."); }
                }
                else
                {
                    if (this._stopRequested) { sb.Append("Waiting to stop ...\n(Press stop again to terminate immediately.)\n\n"); }
                    if (progress.ProgressString != null)
                    {
                        sb.Append(progress.ProgressString);
                    }
                    else
                    {
                        sb.Append("Scenario: "); sb.Append(Interaction.GetTitleCase(progress.Scenario.ToString())); sb.Append("\n");
                        if (progress.ModelYear == null) { sb.Append("Model Year: N/A\n"); }
                        else { sb.Append("Model Year: "); sb.Append(progress.ModelYear); sb.Append("\n"); }
                        Manufacturer mfr = progress.Manufacturer;
                        if (mfr == null)
                        {
                            sb.Append("Manufacturer: N/A\n");
                        }
                        else
                        {
                            Manufacturer.CModelData mmd = progress.Manufacturer.ModelData;
                            sb.Append("Manufacturer: "); sb.Append(Interaction.GetTitleCase(progress.Manufacturer.Description.Name, 4));
                            sb.Append("\n");
                            sb.Append("         pSTND  STND  CAFE  Credits  Fines  Costs\n");
                            sb.Append("    PC :  "); this.RefreshSession_Helper_UpdateRC(sb, mmd, RegulatoryClass.PassengerCar );
                            sb.Append("    LT :  "); this.RefreshSession_Helper_UpdateRC(sb, mmd, RegulatoryClass.LightTruck   );
                            sb.Append("    2b3:  "); this.RefreshSession_Helper_UpdateRC(sb, mmd, RegulatoryClass.LightTruck2b3);
                        }
                    }
                }
                string progressString = sb.ToString();
                if (this.ux_progress.Text != progressString)
                {
                    this.ux_progress.Text = progressString;
                }
                string additionalInfoString = (progress == null || progress.AdditionalInfo == null) ? string.Empty : progress.AdditionalInfo.ToString();
                if (this.ux_additionalInfo.Text != additionalInfoString)
                {
                    this.ux_additionalInfo.Text = additionalInfoString;
                }
                this.ux_runtime.Text = Interaction.GetTimeString(this._compliance.Runtime);
            }
            else
            {
                this.ux_additionalInfo.Clear();
            }
        }
        void RefreshSession_Helper_UpdateRC(StringBuilder sb, Manufacturer.CModelData mmd, RegulatoryClass regClass)
        {
            if (double.IsNaN(mmd.CAFE[regClass]))
            {
                sb.Append(" -     -     -        -      -      -\n");
            }
            else
            {
                double d;
                d = mmd.PreliminaryStandard[regClass];
                if (d < 10 || (d >= 100 && d < 1000)) { sb.Append(" "); }
                sb.Append((d < 100) ? d.ToString("0.0") : d.ToString("0")); sb.Append("  ");
                d = mmd.Standard[regClass];
                if (d < 10 || (d >= 100 && d < 1000)) { sb.Append(" "); }
                sb.Append((d < 100) ? d.ToString("0.0") : d.ToString("0")); sb.Append("  ");
                d = mmd.CAFE[regClass];
                if (d < 10 || (d >= 100 && d < 1000)) { sb.Append(" "); }
                sb.Append((d < 100) ? d.ToString("0.0") : d.ToString("0")); sb.Append("   ");
                this.RefreshSession_Helper_FormatValue(sb, mmd.Credits [regClass]);
                this.RefreshSession_Helper_FormatValue(sb, mmd.Fines   [regClass]);
                this.RefreshSession_Helper_FormatValue(sb, mmd.TechCost[regClass]);
                sb.Append("\n");
            }
        }
        void RefreshSession_Helper_FormatValue(StringBuilder sb, double d)
        {
            double abs_d = Math.Abs(d);
            string unit = "  ";
            if      (abs_d > 1000000000) { d /= 1000000000; unit = " b"; }
            else if (abs_d >    1000000) { d /=    1000000; unit = " m"; }
            else if (abs_d >       1000) { d /=       1000; unit = " k"; }
            if      (d < -100) {                   }
            else if (d <  -10) { sb.Append(  " "); }
            else if (d <    0) { sb.Append( "  "); }
            else if (d <   10) { sb.Append("   "); }
            else if (d <  100) { sb.Append( "  "); }
            else               { sb.Append(  " "); }
            sb.Append(d.ToString("0"));
            sb.Append(unit);
            sb.Append(' ');
        }
        void UpdateStatus(string value)
        {
            this._status = value;
            this.OnSessionUpdating();
        }
        void UpdateSessionName()
        {
            if (this._isOpen)
            {
                this._name = (this._path == null) ? this.GetGenericSessionName() : Path.GetFileNameWithoutExtension(this._path);
                this.Text = this._name + ((this._readOnly) ? " [Read Only]" : string.Empty);
            }
            else { this.Text = this._name = string.Empty; }
            this.OnSessionNameChanged();
        }
        string GetGenericSessionName()
        {
            return "Session " + this._index.ToString();
        }
        void ShowErrorPrompt(string message)
        {
            MessageBox.Show(message, SessionMessages.CAFEModelError, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        #endregion
        #region 
        [Browsable(false)]
        public string SessionName { get { return this._name; } }
        [Browsable(false)]
        public string SessionPath { get { return this._path; } }
        [Browsable(false)]
        public ICompliance Compliance { get { return this._compliance; } set { this._compliance = value; this.SaveRequired = true; } }
        [Browsable(false)]
        public Industry Data { get { return this._data; } set { this._data = value; this.SaveRequired = true; } }
        [Browsable(false)]
        public ModelingSettings Settings { get { return this._settings; }  }
        [Browsable(false)]
        public bool Running { get { return (this._compliance != null && this._compliance.Running); } }
        [Browsable(false)]
        public string Status { get { return this._status; } }
        [Browsable(false)]
        public int RefreshInterval
        {
            get { return this._refreshInterval; }
            set
            {
                if (value == -1) { this._refreshInterval = -1; }    
                else
                {
                    this._refreshInterval = (value < MinRefreshInterval) ? MinRefreshInterval :
                        value - (value % MinRefreshInterval);       
                }
                this.SaveRequired = true;
            }
        }
        [Browsable(false)]
        public bool IsOpen { get { return this._isOpen; } }
        [Browsable(false)]
        public bool IsClosed { get { return !this._isOpen; } }
        [Browsable(false)]
        public bool ReadOnly { get { return this._readOnly; } }
        [Browsable(false)]
        public bool SaveRequired { get { return this._saveRequired; } set { this._saveRequired = value; this.RefreshSession(); } }
        #endregion
        #region 
        #region 
        Panel       ux_progressPanel;
        RichTextBox ux_progress;
        Splitter    ux_splitter;
        Panel       ux_statusPanel;
        Label       ux_runtime;
        RichTextBox ux_additionalInfo;
        #endregion
        public const int RefreshIntervalRealtime = 125;
        public const int RefreshIntervalHigh = 500;
        public const int RefreshIntervalNormal = 2000;
        public const int RefreshIntervalLow = 4000;
        public const int RefreshIntervalPaused = -1;
        public const int MinRefreshInterval = 125;
        static int SessionCount = 1;
        int    _index;
        string _path;
        string _name;   
        ICompliance      _compliance;
        Industry         _data;
        ModelingSettings _settings;
        string _status;
        int    _refreshInterval;    
        bool   _isOpen;
        bool   _readOnly;           
        bool   _saveRequired;
        bool   _stopRequested;
        #endregion
    }
}

