// <summary>ソースコード：>デフォルトのデバッガエージェント</summary>
// <author>CommonMP</author>

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using CommonMP.HYSSOP.CoreImpl.HSTools;
using CommonMP.HYSSOP.OptionImpl.HSCommunicationTool.HyssopDotNetIpcTool;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace CommonMP.HYSSOP.OptionImpl.HSDebug.HyssopVSAddinAgent
{
    /// <summary><para>class outline:</para>
    /// <para>デフォルトのデバッガエージェント</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2009/12/28][新規作成]</para>
    /// <para>CommonMPからデバッガに情報を送信するためのエージェント。</para>
    /// <para>Visual Studioアドインとの通信処理を提供するデフォルトの実装。</para>
    /// <para><see cref="HySDebugAgent.SetDebugAgent"/>で本クラスのインスタンスを登録することで通信機能が利用可能となる。</para>
    /// </remarks>
    public class HySDebugDefaultAgent : HySDebugAgentIF
    {
        /// <summary>
        /// モニターデータコンテナ
        /// </summary>
        object m_csDataContainer;

        /// <summary>
        /// モニターデータ送信スレッド
        /// </summary>
        Thread m_csDataSendThread;

        /// <summary>
        /// モニターデータコンテナのロック用オブジェクト
        /// </summary>
        object m_csLock = new object();

        /// <summary><para>method outline:</para>
        /// <para>デバッグ開始</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Startup()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>IPCのクライアントポートを作成し、通信の準備処理を行う。</para>
        /// </remarks>
        public void Startup()
        {
            try
            {
                // デバッグIPCセットアップ
                HySIpcServiceRegister.CreateClientPort("addin", typeof(HySIpcRemoteService));
            }
            catch { }
        }

        /// <summary><para>method outline:</para>
        /// <para>デバッグ終了</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Terminate()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>IPCのクライアントポートを削除し、通信の終了処理を行う。</para>
        /// </remarks>
        public void Terminate()
        {
            try
            {
                if (m_csDataSendThread != null)
                {
                    Thread t = m_csDataSendThread;
                    lock (m_csLock)
                    {
                        m_csDataContainer = null;
                    }
                    t.Join();
                }
            }
            catch { }
        }

        #region HySDebugAgentIF メンバ

        /// <summary><para>method outline:</para>
        /// <para>環境情報通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> EnvironmentInfoNotify(csEnvironmentInfo)</para>
        /// </example>
        /// <param name="csEnvironmentInfo">環境情報。実際の型は<see cref="CommonMP.HYSSOP.CoreImpl.HSData.HySDataHashTable"/></param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>デバッガプロセスのリモートメソッド呼び出しにより環境情報データを送信する。</para>
        /// </remarks>
        public void EnvironmentInfoNotify(object csEnvironmentInfo)
        {
            try
            {
                if (csEnvironmentInfo != null)
                {
                    HySIpcRemoteService service = new HySIpcRemoteService();
                    service.SendData("environment_info", SerializeObject(csEnvironmentInfo));
                }
            }
            catch { }
        }

        /// <summary><para>method outline:</para>
        /// <para>モニター表示データ通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> MonitorDataNotify(csDataContainer)</para>
        /// </example>
        /// <param name="csDataContainer">モニター表示データコンテナ。実際の型は<see cref="CommonMP.HYSSOP.CoreImpl.HSData.HySDataContainer"/></param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>モニターデータの定期送信処理を開始する。</para>
        /// </remarks>
        public void MonitorDataNotify(object csDataContainer)
        {
            try
            {
                lock (m_csLock)
                {
                    m_csDataContainer = csDataContainer;

                    if (m_csDataSendThread == null)
                    {
                        ThreadStart ts = new ThreadStart(DataSendThreadMethod);
                        Thread t = new Thread(ts);
                        t.Name = "HySDebugAgent.DataSendThreadMethod";
                        m_csDataSendThread = t;

                        m_csDataSendThread.Start();
                    }
                }
            }
            catch { }
        }

        #endregion

        /// <summary><para>method outline:</para>
        /// <para>データ送信スレッド</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> new Thread(new ThreadStart(DataSendThreadMethod)).Start()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>モニターデータの定期送信処理を実行する。</para>
        /// </remarks>
        private void DataSendThreadMethod()
        {
            while (true)
            {
                try
                {
                    object csDataContainer = null;
                    lock (m_csLock)
                    {
                        if (m_csDataContainer == null)
                        {
                            m_csDataSendThread = null;
                            break;
                        }
                        csDataContainer = m_csDataContainer;
                    }
                    HySIpcRemoteService service = new HySIpcRemoteService();
                    service.SendData("monitor_data", SerializeObject(csDataContainer));
                }
                catch { }

                Thread.Sleep(2000);
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>オブジェクトをシリアライズする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>byte[] csSerializedObject = SerializeObject(csSourceObject)</para>
        /// </example>
        /// <param name="csSourceObject">シリアライズ元のオブジェクト</param>
        /// <returns>送信用バイトデータ</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>送信データをバイト配列にシリアライズする。</para>
        /// </remarks>
        private byte[] SerializeObject(object csSourceObject)
        {
            byte[] csSerializedObject = null;
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, csSourceObject);
                csSerializedObject = ms.ToArray();
                ms.Close();
            }
            return csSerializedObject;
        }
    }
}
