// <summary>ソースコード：外部ＤＢ接続処理のマルチスレッド制御を行うクラス</summary>
// <author>CommonMP</author>

using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;

using CommonMP.HYSSOP.Interface.HSController;
using CommonMP.HYSSOP.Interface.HSDBAProc;
using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;
using CommonMP.HYSSOP.CoreImpl.HSData;

namespace CommonMP.HYSSOP.CoreImpl.HSController
{
    /// <summary><para>class outline:</para>
    /// <para>外部ＤＢ接続処理のマルチスレッド制御を行う</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2008/10/01][新規作成]</para>
    /// </remarks>
    public class HySDBAThreadControllerBase : HySDBAThreadCtl
    {
        /// <summary>DBアクセス処理</summary>
        protected HySDBAProcedure m_csDBAProc;

        /// <summary>業務制御</summary>
        protected HySControllerRoot m_csController = null;

        /// <summary>イベント待ちQueue </summary>
        protected HySQueue m_csQueue = new HySQueue(16);

        /// <summary>イベントコールバック動作排他</summary>
        protected HySMutex m_csEventCallBackLock = new HySMutex();
        /// <summary>スレッド動作移行過渡処理排他</summary>
        protected HySMutex m_csThreadTransitionLock = new HySMutex();
        /// <summary>スレッド動作状態</summary>
        protected bool m_bThreadStatus = THREAD_NOT_WORK;

        /// <summary>業務に転送するメッセージ</summary>
        protected HySString m_csSndMessage = new HySString("");

        // 常数定義
        /// <summary>スレッド動作せず</summary>
        static protected readonly bool THREAD_NOT_WORK = false;
        /// <summary>スレッド動作中</summary>
        static protected readonly bool THREAD_AT_WORK = true;



        /// <summary><para>method outline:</para>
        /// <para>デフォルトコンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> HySDBAThreadControllerBase csController = new HySDBAThreadControllerBase() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>生成インスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public HySDBAThreadControllerBase()
        {
        }

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> HySDBAThreadControllerBase csController = new HySDBAThreadControllerBase(csDBAProc) </para>
        /// </example>
        /// <param name="csDBAProc">DB接続業務</param>
        /// <returns>生成インスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public HySDBAThreadControllerBase(HySDBAProcedure csDBAProc)
        {
            m_csDBAProc = csDBAProc;
            m_csDBAProc.SetDBAThreadCtl(this);
            this.ThreadStart();
        }

        /// <summary><para>method outline:</para>
        /// <para>制御クラスを設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetController( csCtl ) </para>
        /// </example>
        /// <param name="csCtl">制御クラス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetController(HySControllerRoot csCtl)
        {
            m_csController = csCtl;
        }
        // ====================================
        // 演算実行
        // ====================================


        /// <summary><para>method outline:</para>
        /// <para>イベントを受け取った時に動作するメソッド</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Boolean bRtn = EventCallback( csEvent ) </para>
        /// </example>
        /// <param name="csEvent">送られたイベント</param>
        /// <returns>true:=正常, false:=異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>各実装クラスは受け取ったイベント毎に処理を行う</para>
        /// </remarks>
        public virtual Boolean EventCallback(HySSysEvent csEvent)
        {
            m_csEventCallBackLock.Wait();   // <-- EventCallBack() の二重起動防止　Ｍｕｔｅｘが必要ではないか？
            Boolean bRtn = true;
            long lEventNo = ((HySEventObject)csEvent).GetEventNo();

            m_csQueue.PushObject(csEvent);

            m_csEventCallBackLock.Release();
            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>イベントを送る</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Boolean bRtn = PutEvent( csEvent ) </para>
        /// </example>
        /// <param name="csEvent">送るイベント</param>
        /// <returns>true:=正常, false:=異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>自分からイベントを送信する時に使用する</para>
        /// </remarks>
        /// 
        public virtual Boolean PutEvent(HySSysEvent csEvent)
        {
            //((HySEventObject)csEvent).SetFromSimKind(m_csDBAProc.GetSimKind());
            //((HySEventObject)csEvent).SetToSimKind(m_csDBAProc.GetSimKind());

            // 送信元シミュレータ種別設定
            ((HySEventObject)csEvent).SetFromSimKind(m_csDBAProc.GetSimKind());
            return m_csController.PutEvent(csEvent);
        }

        /// <summary><para>method outline:</para>
        /// <para>システム終了準備完了判別</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Boolean bRtn = ExitOK( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true : システムExit準備OK　、false : システムExit準備NG</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public virtual Boolean ExitOK()
        {
            if (m_bThreadStatus == THREAD_NOT_WORK)
            {   return true;   }
            else
            { return false; }
        }

        

        // ====================================
        // スレッド制御
        // ====================================

        /// <summary><para>method outline:</para>
        /// <para>スレッド起動（別スレッドで this.ThreadRun()が動作を開始する）</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> ThreadStart() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected virtual void ThreadStart()
        {
            if (m_bThreadStatus == THREAD_NOT_WORK)
            {   // 現在　「スレッド動作せず」状態の場合
                m_csThreadTransitionLock.Wait(); // スレッド動作移行開始
                if (m_bThreadStatus == THREAD_NOT_WORK)
                {   //再チェック(ウエイト中にスレッドが既に起動されていた場合)
                    ThreadStart ThSt = new ThreadStart(this.ThreadRun);
                    Thread t = new Thread(ThSt);
                    t.Start();
                }
                else
                {   // 結局起動しなければ　ロックは自分で解除する
                    m_csThreadTransitionLock.Release();
                }
            }
            else
            {
              HySLog.LogOut(HySLog.SYSTEM_DEBUG, "HySDBAThreadController::ThreadStart", " thread is now working!");
            }
        }
        /// <summary><para>method outline:</para>
        /// <para>スレッド処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> スレッド起動時に呼ばれる </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected virtual void ThreadRun()
        {
            m_bThreadStatus = THREAD_AT_WORK; // スレッド動作中 真っ先にスレッド動作中を上げる

            HySLog.LogOut(HySLog.SYSTEM_DEBUG, "HySDBAThreadController::ThreadRun", "** start **");
            HySEventObject csEvent; // イベント
            long lEventNo; // イベント番号

            
            m_csThreadTransitionLock.Release(); // スレッド動作移行解除
            
            for (; ; )
            {// ∞ループ
                csEvent = (HySEventObject)m_csQueue.PullObject();  // イベント待ち
                lEventNo = csEvent.GetEventNo();

                if (lEventNo == HySEventObject.CMND_STOP_SIMULATION)
                {   // シミュレーション終了の場合
                    break;
                }
                m_csDBAProc.EventCallback(csEvent);
            }
            HySLog.LogOut(HySLog.SYSTEM_DEBUG, "HySDBAThreadController::ThreadRun", "** end **");

            m_bThreadStatus = THREAD_NOT_WORK; // スレッド動作せず　一番最後にスレッド終了を立てる
        }
        /// <summary><para>method outline:</para>
        /// <para>スレッドを終了させる</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> ThreadStop() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public virtual void ThreadStop()
        {
            HySLog.LogOut(HySLog.SYSTEM_DEBUG, "HySDBAThreadController::ThreadStop", "start");
            if (m_bThreadStatus == THREAD_AT_WORK)
            {   // スレッドが動作していれば
                HySEventObject csStopEvent = new HySEventObject(HySSysEvent.OBJID_SIMULATOR, HySEventObject.CMND_STOP_SIMULATION);

                m_csQueue.PushObject(csStopEvent); // 演算を終了させる

                System.Threading.Thread.Sleep(0);   // スレッドの隙間を空けるため
            } 
        }

    } // end of class
} // end of namespace
