// <summary>ソースコード：>ＨＹＭＣＯログクラス</summary>
// <author>CommonMP</author>

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

using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;
using CommonMP.HYMCO.Interface;

namespace CommonMP.HYMCO.CoreImpl.Tool
{
    /// <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 McLog : McRoot
    {
        /// <summary> 演算ログデータＩＤ管理テーブル </summary>
        static private HySDataHashTable m_csActiveLogDataTbl = null;

        /// <summary> 演算ログデータ </summary>
        static private McModelLogData m_csActiveLogData = null;
      
        /// <summary>コンソール出力ON_OFFフラグ </summary>  
        static protected bool m_bSysCslDispFlg = true;

        /// <summary>ファイル出力ON_OFFフラグ</summary>
        static protected bool m_bFileOutFlg = false;

        /// <summary>ログ書きスレッド終了フラグ </summary>
        static protected bool m_bStopFlg = false;        // スレッド終了フラグ

        /// <summary>ログファイル名称</summary>
        static protected HySString m_csLogFileName = null;
        /// <summary>ログ出力先ファイル</summary>
        static protected HySFile m_csLogFile = null;
        /// <summary>イベントキュー（Wait有り）</summary>
        static protected HySQueue m_csLogEventQueue = new HySQueue(128);  // イベントキュー（Wait有り）

        /// <summary>ログ取得レベル</summary>
        static protected long m_lLogLvl = HySLog.ONLINE;       // ログ取得レベル

        /// <summary>環境ファイル名称</summary>
        static private HySString m_csEnvFileName = null;
        /// <summary>環境ファイル検索パス</summary>
        static private readonly HySString m_csEnvFilePath = new HySString("\\conf\\");

        /// <summary>ログ出力クラスリスト</summary>
        static protected List<string> m_csLogOutClassList = new List<string>();
        /// <summary> ログ出力クラス数 </summary>
        static protected int m_iOutClssNum;

        /// <summary> CUI ディバッグモード</summary>
        static bool m_bCUIDebugMode = false;
        /// <summary> リセット動作中フラグ </summary>
        static bool m_bResetFlg = false;
        
        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>McLog csLog = new McLog()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>McLog  生成したインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public McLog()
        {
            //ログ出力レベルを環境から取得
            HySString csLogLevel = HySEnvInf.GetEnvInf(new HySString("LOG_LEVEL"));
            m_lLogLvl = HySLog.TRIAL_RUN;
            if (csLogLevel.ToString() == "ONLINE")
            {
                m_lLogLvl = HySLog.ONLINE;
            }
            else if (csLogLevel.ToString() == "TRIAL_RUN")
            {
                m_lLogLvl = HySLog.TRIAL_RUN;
            }
            else if (csLogLevel.ToString() == "DEBUG")
            {
                m_lLogLvl = HySLog.DEBUG;
            }
            else if (csLogLevel.ToString() == "SYSTEM_DEBUG")
            {
                m_lLogLvl = HySLog.SYSTEM_DEBUG;
            }

            // ログ出力ファイル名称を環境から取得
            HySString csFileName = HySEnvInf.GetEnvInf(new HySString("HYMCO_DEBUG_LOG_FILENAME"));

            // csFileNameがnullの場合catchに入り、csFileNameにCommonMPDebugLogが設定される
            try
            {
                m_csLogFileName = HySEnvInf.GetHomeDirectory() + new HySString("\\log\\") + csFileName + new HySString(".txt");
            }
            catch (NullReferenceException)
            {
                csFileName = new HySString("CommonMPDebugLog");
                m_csLogFileName = HySEnvInf.GetHomeDirectory() + new HySString("\\log\\") + csFileName + new HySString(".txt");
            }

            bool bSetSysCslDisp = false;
            HySString csEnvRtn = HySEnvInf.GetEnvInf(new HySString("CONSOLE_LOG_OUT"));
            if ((object)csEnvRtn != null)
            {
                bSetSysCslDisp = csEnvRtn.Equal(new HySString("TRUE"));
            }
            this.SetSysCslDisp(bSetSysCslDisp);

            bool bSetFileOutFlg = false;
            csEnvRtn = HySEnvInf.GetEnvInf(new HySString("FILE_LOG_OUT"));
            if ((object)csEnvRtn != null)
            {
                bSetFileOutFlg = csEnvRtn.Equal(new HySString("TRUE"));
            }
            this.SetFileOutFlg(bSetFileOutFlg);

        }

        /// <summary><para>method outline:</para>
        /// <para>コンソール出力ON/OFF設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetSysCslDisp(bFlg) </para>
        /// </example>
        /// <param name="bFlg">=true:コンソール出力ON</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetSysCslDisp(bool bFlg)
        {
            m_bSysCslDispFlg = bFlg;
        }
        /// <summary><para>method outline:</para>
        /// <para>ファイル出力ON/OFF設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetFileOutFlg(bFlg) </para>
        /// </example>
        /// <param name="bFlg">=true:ファイル出力ON</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetFileOutFlg(bool bFlg)
        {
            m_bFileOutFlg = bFlg;
        }

        /// <summary><para>method outline:</para>
        /// <para>CUIディバッグモード設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetCUIDebugMode(bFlg) </para>
        /// </example>
        /// <param name="bFlg">=true:CUIディバッグモードON</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void SetCUIDebugMode(bool bFlg)
        {
            m_bCUIDebugMode = bFlg;
        }

        /// <summary><para>method outline:</para>
        /// <para>演算ログデータクラス設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetActiveModelLogData(csLogData) </para>
        /// </example>
        /// <param name="csLogData">演算ログデータ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void SetActiveModelLogData(McModelLogData csLogData)
        {
            int this_thread = System.Threading.Thread.CurrentThread.ManagedThreadId;
            HySString csThreadKey = new HySString(this_thread.ToString());
            if (m_csActiveLogDataTbl is HySDataHashTable)
            {  // 演算ログデータクラス管理テーブルが有効な場合
                if (m_csActiveLogDataTbl.GetObject(csThreadKey) is McModelLogData)
                {  // 演算ログデータクラスが既に有る場合
                    return;
                }
            }
            else
            {  // 演算ログデータクラス管理テーブルが無効な場合
                m_csActiveLogDataTbl = new HySDataHashTable();
            }
            m_csActiveLogData = csLogData;
            m_csActiveLogDataTbl.AddObject(csThreadKey, csLogData);
            csThreadKey = null;
        }

        /// <summary>ワーク変数：ハッシュキーの一時保管 </summary>
        static HySString[] m_csWorkThreadKey = new HySString[256];
        /// <summary>ワーク変数：ハッシュキーの一時保管書き込み位置 </summary>
        static int iWtPnt = 0;
        /// <summary>ワーク変数：ハッシュキーの一時保管読み出し位置 </summary>
        static int iRdPnt = 0;

        /// <summary><para>method outline:</para>
        /// <para>演算ログデータクラス管理テーブル解放</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> RemoveModelLogData() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void RemoveModelLogData()
        {
            if (m_csActiveLogDataTbl is HySDataHashTable)
            {  // 演算ログデータクラス管理テーブルが有効の場合
                int this_thread = System.Threading.Thread.CurrentThread.ManagedThreadId;
                HySString csThreadKey = new HySString(this_thread.ToString());
                if (m_csActiveLogDataTbl.GetObject(csThreadKey) is McModelLogData)
                {  // 演算ログデータクラスが有る場合
                    m_csWorkThreadKey[iWtPnt] = csThreadKey;
                    iWtPnt += 1;
                    if (iWtPnt >= 256) { iWtPnt = 0; }
                    // 別スレッドで　Removeさせる（この時、Removeまで少し時間を持つ）
                    ThreadStart ThSt = new ThreadStart(McLog.RemoveActiveLogData);
                    Thread t = new Thread(ThSt);
                    t.Start();
                    //m_csActiveLogDataTbl.DeleteData(csThreadKey);
                    csThreadKey = null;
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>演算ログデータクラス管理テーブル解放</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> RemoveActiveLogData() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>ST:009対応</para>
        /// </remarks>
        static public void RemoveActiveLogData()
        {
            // PT-004 計算に要した時間ログの出力不良修正
            for (int i = 0; i < 300; i++)
            {
                // ログ情報の破棄を遅らす
                 System.Threading.Thread.Sleep(10);
            }
            m_csActiveLogDataTbl.DeleteData(m_csWorkThreadKey[iRdPnt]);
            m_csWorkThreadKey[iRdPnt] = null;
            iRdPnt += 1;
            if (iRdPnt >= 256) { iRdPnt = 0; }
        }

        /// <summary><para>method outline:</para>
        /// <para>立ち上がり処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = WakeUp() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>bool　true:=正常, false:=異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        internal bool WakeUp()
        {
            ThreadStart ThSt = new ThreadStart(this.Run);

            // ログ出力クラス取得
            //m_csEnvFileName = new HySString("HymcoModelDebug.cfg");

            McLog.Load();

            // ログ出力ファイルの初期設定
            // ログ吐きスレッド立ち上げ
            Thread t = new Thread(ThSt);
            t.Start();

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>終了処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> ShutDown() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>bool true:=正常, false:=異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        internal bool ShutDown()
        {
            // ログ吐きスレッド終了指示 
            m_bStopFlg = true;

            McLogMessageData csMsgData = new McLogMessageData(new HySString("McLog"), new HySString((DateTime.Now).ToString() + "   >>>>  LogEnd  <<<< "));
            m_csLogEventQueue.PushObject(csMsgData);

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>デバックログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> DebugOut(csClassName, csMethodName, csMsg) </para>
        /// </example>
        /// <param name="csClassName">クラス名</param>
        /// <param name="csMethodName">メソッド名</param>
        /// <param name="csMsg">メッセージ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void DebugOut(HySString csClassName, HySString csMethodName, HySString csMsg)
        {
            if (HySLog.DEBUG <= m_lLogLvl || csClassName.Equals(McLog.SYSTEM)==true )
            {
                HySString msgStr = new HySString("r" + (DateTime.Now).ToString()) + new HySString(" <") + csClassName + new HySString("::") + csMethodName + new HySString("> ") + csMsg;

                McLogMessageData csMsgData = new McLogMessageData(csClassName, msgStr);
                if (m_bCUIDebugMode == true)
                {   
                    // CUI の場合はシングルスレッド
                    McLog.CUILogOut(csMsgData);
                }
                else
                {
                    m_csLogEventQueue.PushObject(csMsgData);
                }
            }
        }
        static public void DebugOut(string csClassName, string csMethodName, string csMsg)
        {
            if (HySLog.DEBUG <= m_lLogLvl || csClassName.Equals(McLog.SYSTEM) == true)
            {
                HySString msgStr = new HySString("r" + (DateTime.Now).ToString()) + new HySString(" <" + csClassName + "::" + csMethodName + ">  " + csMsg );

                McLogMessageData csMsgData = new McLogMessageData(new HySString( csClassName ), msgStr);
                if (m_bCUIDebugMode == true)
                {
                    // CUI の場合はシングルスレッド
                    McLog.CUILogOut(csMsgData);
                }
                else
                {
                    m_csLogEventQueue.PushObject(csMsgData);
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>デバックログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> DebugOut(csSimuTime, csElmID, csClassName, csMethodName, csMsg) </para>
        /// </example>
        /// <param name="csSimuTime">シミュレーション時刻</param>
        /// <param name="csElmID">要素ＩＤ</param>
        /// <param name="csClassName">クラス名</param>
        /// <param name="csMethodName">メソッド名</param>
        /// <param name="csMsg">メッセージ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void DebugOut(HySTime csSimuTime, HySIdentifier csElmID, String csClassName, String csMethodName, String csMsg)
        {
            if (HySLog.DEBUG <= m_lLogLvl || csClassName.Equals(McLog.SYSTEM)==true )
            {
                String msgStr = "";
                if (csSimuTime != null && csElmID != null)
                {
                    msgStr = "s"+HySCalendar.ToString(csSimuTime, HySCalendar.FORMAT.lSW_YEAR)
                     + " <" + csClassName + "[" + csElmID.ToString() + "]::" + csMethodName + "> " + csMsg;
                }
                else
                {
                    msgStr = " <" + csClassName + "::" + csMethodName + "> " + csMsg;
                }


                McLogMessageData csMsgData = new McLogMessageData(new HySString(csClassName), new HySString(msgStr));
                if (m_bCUIDebugMode == true)
                {   
                    // CUI の場合はシングルスレッド
                    McLog.CUILogOut(csMsgData);
                }
                else
                {
                    m_csLogEventQueue.PushObject(csMsgData);
                }

            }

        }

        /// <summary><para>method outline:</para>
        /// <para>ログ吐き出し処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Run() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        internal void Run()
        {
            try
            {
                McLogMessageData Msg = null;

                // ﾌｧｲﾙをオープンする
                m_csLogFile = new HySFile(m_csLogFileName);

                // 同じ名称のログファイルがあるか確認
                if (m_csLogFile.Exist() == true)
                {
                    // ある場合、そのログファイルを削除する
                    m_csLogFile.Delete();
                }
                // ログファイルを新規作成する
                m_csLogFile.Open(HySFile.OPEN_MODE.CREATE_NEW, HySFile.READ_WRITE_MODE.WRITE, HySFile.DIRECTORY_MODE.MK_DIR);

                // ログ出力クラスの要素数を取得
                m_iOutClssNum = m_csLogOutClassList.Count;

                // ログ書き込み処理（無限ループ）
                for (; ; )
                {
                    // ログデータ取得
                    Msg = (McLogMessageData)m_csLogEventQueue.PullObject();

                    if (m_bResetFlg == false)
                    {
                        // ログ出力クラスの要素数分、forで回す
                        for (int iLp = 0; iLp < m_iOutClssNum; iLp++)
                        {
                            // ログデータと登録済みオブジェクトの名称が一致していたら ログ出力を行う
                            if (m_csLogOutClassList[iLp].ToString().Equals(Msg.GetClassName().ToString()))
                            {
                                //if (m_csActiveLogData != null)
                                if (m_csActiveLogDataTbl is HySDataHashTable)
                                {
                                    // 終了処理ではない場合
                                    if (m_bStopFlg == false)
                                    {
                                        // ログをリストに追加する
                                        m_csActiveLogData = (McModelLogData)m_csActiveLogDataTbl.GetObject(Msg.GetMessageID());
                                        if (m_csActiveLogData is McModelLogData)
                                        {  // ログ管理ハッシュテーブルにリストが有る場合
                                            m_csActiveLogData.AddLogInfo(Msg);
                                        }
                                        //m_csActiveLogData.AddLogInfo(Msg);
                                    }
                                }
                                if (m_bSysCslDispFlg == true && m_bCUIDebugMode == true)
                                {
                                    // コンソール出力必要ならば
                                    Console.WriteLine("Msg = " + (Msg.GetMessage()).ToString());
                                }
                                if (m_bFileOutFlg == true)
                                {
                                    // ファイルに出力する
                                    m_csLogFile.WriteText(Msg.GetMessage());
                                }
                                break;
                            }
                        }
                    }
                    // 終了処理の場合
                    if (m_bStopFlg == true)
                    {
                        // 無限ループから抜ける
                        break;
                    }
                }
                // ファイルをクローズする
                m_csLogFile.Close();
            }
            catch (Exception ex)
            {
               // ver1.5 エラートレース日本語対応
                HySLog.LogOut(HySLog.ONLINE, "McLog", "Run", 
                    Properties.HymcoImplResources.STATEMENT_CATCH_EXCEPTION + ex.Message);
               // HySLog.LogOut(HySLog.ONLINE, "McLog", "Run", "Catch Exception : " + ex.Message);
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>ログ出力クラスファイルの読み込み処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Load() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static protected  void Load()
        {
            HySString csReadStr;            // 読み取りデータ
            HySString csFileName;           // ログ出力クラスファイル名称
            String csVarName;               // ログ出力クラス名称

            // ログ出力クラスリストをクリアする
            m_csLogOutClassList.Clear();

            m_csEnvFileName = HySEnvInf.GetEnvInf(new HySString("DEBUGOUT_MODEL_DEF_FILENAME"));

            csFileName = HySEnvInf.GetHomeDirectory() + m_csEnvFilePath + m_csEnvFileName;

            HySFile m_File = new HySFile(csFileName);

            if (m_File.Open(HySFile.OPEN_MODE.OPEN, HySFile.READ_WRITE_MODE.READ, HySFile.DIRECTORY_MODE.NOT_MK_DIR) != 0)  // ファイルが開けない
            {
                m_File = null;
            }
            else
            {
                csReadStr = new HySString("");

                while (m_File.ReadText(ref csReadStr) != 0)       // ファイルの最後まで
                {
                    if (csReadStr.ToString().IndexOf("#") == 0 || csReadStr.ToString() == String.Empty) // コメント文、空行読み飛ばし
                    {
                        continue;
                    }
                    // ログ出力クラス名称読み取り
                    csVarName = csReadStr.ToString().Substring(0, csReadStr.GetLength());

                    if (csVarName.Length > 0)   // ログ出力クラス名称取得確認
                    {
                        // リストに追加する
                        m_csLogOutClassList.Add(csVarName);
                    }
                }
                m_File.Close();
                m_File = null;
                csVarName = McLog.SYSTEM;// "SYSTEM"; 
                m_csLogOutClassList.Add(csVarName);
            }
            // ログ出力クラスの要素数を取得
            m_iOutClssNum = m_csLogOutClassList.Count;
        }


        /// <summary><para>method outline:</para>
        /// <para>CUIデバックログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> CUILogOut(csMsgData) </para>
        /// </example>
        /// <param name="csMsgData">演算ログメッセージ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static protected void CUILogOut(McLogMessageData csMsgData)
        {
            // ログ出力クラスの要素数を取得
            int count  = m_csLogOutClassList.Count;

            // ログ出力クラスの要素数分、forで回す
            for (int iLp = 0; iLp < count; iLp++)
            {
                // ログデータと登録済みオブジェクトの名称が一致していたら ログ出力を行う
                if (m_csLogOutClassList[iLp].ToString().Equals(csMsgData.GetClassName().ToString()))
                {
                    if (m_bSysCslDispFlg == true)
                    {   // コンソール出力必要ならば
                        Console.WriteLine("Msg = " + (csMsgData.GetMessage()).ToString());
                    }
                    if (m_bFileOutFlg == true)
                    {   // ファイルに出力する
                        m_csLogFile.WriteText(csMsgData.GetMessage());
                    }
                    break;
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>ログ出力ファイルのリセット</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Reset() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void Reset()
        {
            m_bResetFlg = true;
            // ファイル書き込みを制限
            //m_bFileOutFlg = false;

            McLog.Load();

            if (m_csLogFile == null)
            {
                // ファイルをオープンする
                m_csLogFile = new HySFile(m_csLogFileName);
            }
            else
            {
                // ファイルをクローズする
                m_csLogFile.Close();
            }

            if (m_bFileOutFlg == true)
            {
                // 同じ名称のログファイルがあるか確認
                if (m_csLogFile.Exist() == true)
                {   // ある場合、そのログファイルを削除する
                    m_csLogFile.Delete();
                }
                // ログファイルを新規作成する
                m_csLogFile.Open(HySFile.OPEN_MODE.CREATE_NEW, HySFile.READ_WRITE_MODE.WRITE, HySFile.DIRECTORY_MODE.MK_DIR);
            }
            // ファイル書き込みをＯＫとする
            //m_bFileOutFlg = true;

            m_bResetFlg = false; 
        }

        /// <summary>予約語</summary>
        static public readonly String SYSTEM = "@";
    }
}
