// <summary>ソースコード：>ＨＹＳＳＯＰログ管理クラス</summary>
// <author>CommonMP</author>

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

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

namespace CommonMP.HYSSOP.CoreImpl.HSTools
{
    /// <summary>
    /// ログ管理クラス
    /// ★★★　本クラスは、プロトタイプでは、スタンドアローン方式のみに対応している
    /// サーバー処理、（２４時間連続運転）に対しては、将来処理を拡張する。
    /// </summary>
    public class HySLog : HySRoot
    {
        /// <summary>コンソール出力ON＿OFFフラグ </summary>  
        static protected bool m_bSysCslDispFlg = false; // コンソール出力ON＿OFFフラグ(必要か？)

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

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

        /// <summary>シングルスレッドモード</summary>
        static protected bool m_bSingleThreadMode = 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 public readonly long SYSTEM_DEBUG = 6;
        /// <summary>モデル開発者デバッグモード</summary>
        static public readonly long DEBUG = 4;
        /// <summary>試運用モード</summary>
        static public readonly long TRIAL_RUN = 2;
        /// <summary>オンラインモード(本運用)</summary>
        static public readonly long ONLINE = 0;

        /// <summary>ログ吐きスレッド</summary>
        static private Thread m_csLogThread = null;

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> HySLog csLog = new HySLog(lLogLvl) </para>
        /// </example>
        /// <param name="lLogLvl">ログ取得レベル</param>
        /// <returns>HySLog  生成したインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public HySLog(long lLogLvl)
        {
            m_lLogLvl = lLogLvl;

            // 現在の日にちを取得
            // 日にちが１桁の場合"0"をつける
            int iDay = DateTime.Now.Day;

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

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

        /// <summary><para>method outline:</para>
        /// <para>コンソール出力ON/OFF設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetSysCslDisp(bFlg) </para>
        /// </example>
        /// <param name="bFlg">=true:コンソール出力ＯＮ，=false:コンソール出力ＯＦＦ</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:ファイル出力ＯＮ，=false:ファイル出力ＯＦＦ</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>シングルスレッド動作ON/OFF設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> SetSingleThreadMode(bFlg) </para>
        /// </example>
        /// <param name="bFlg">bool  =true:シングルスレッド動作、=false:マルチスレッド動作</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public static void SetSingleThreadMode(bool bFlg)
        {
            m_bSingleThreadMode = bFlg;
        }


        /// <summary><para>method outline:</para>
        /// <para>立ち上がり処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bWork = WakeUp() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>bool  true:=正常, false:=異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        internal bool WakeUp()
        {
            if (m_bFileOutFlg == true)
            {
                // ログ出力ファイルの初期設定
                // ログ吐きスレッド立ち上げ
                ThreadStart ThSt = new ThreadStart(this.Run);
                Thread t = new Thread(ThSt);
                t.Start();
                m_csLogThread = t;
            }
            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>終了処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bWork = ShutDown() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>bool  true:=正常, false:=異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        internal bool ShutDown()
        {
            if (m_bFileOutFlg == true)
            {
                // ログ吐きスレッド終了指示
                DateTime csNowtime = DateTime.Now;
                m_bStopFlg = true;
                while (m_bStopFlg == true)
                {
                    Thread.Sleep(100);
                    LogOut(ONLINE, (csNowtime.ToString() + "   >>>>  End of Log <<<<"));
                    if (m_csLogThread == null || m_csLogThread.ThreadState != ThreadState.Running)
                    {
                        m_csLogThread = null;
                        break;
                    }
                }
                m_bStopFlg = true;
            }
            return true;
        }


        /// <summary><para>method outline:</para>
        /// <para>ログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> LogOut(lLogLvl, csClassName, csMethodName, csMsg) </para>
        /// </example>
        /// <param name="lLogLvl">ログレベル</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 LogOut(long lLogLvl, HySString csClassName, HySString csMethodName, HySString csMsg)
        {
            if (lLogLvl <= m_lLogLvl)
            {   // new 文を使用したく無い為、余分に判断を入れる
                // 現在の時刻取得
                DateTime csDatatime = DateTime.Now;
                LogOut(lLogLvl, new HySString(csDatatime.ToString()) + new HySString(" <") + csClassName + new HySString("::") + csMethodName + new HySString(">  ") + csMsg);
            }
        }
        /// <summary><para>method outline:</para>
        /// <para>ログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> LogOut(lLogLvl, csMsg) </para>
        /// </example>
        /// <param name="lLogLvl">ログレベル</param>
        /// <param name="csMsg">メッセージ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void LogOut(long lLogLvl, HySString csMsg)
        {
            // ログレベルLogLvlに従って　出力するしないを判断：DEBUGモード=DEBUG、、本運用モード=ONLINE等
            if (lLogLvl <= m_lLogLvl)
            {
                if (m_bSysCslDispFlg == true)
                {   // コンソール出力必要ならば
                    Console.WriteLine( csMsg.ToString() );
                }
                if (m_bFileOutFlg == true)
                {   // ファイル出力必要ならば
                    m_csLogEventQueue.PushObject(new HySLogMessageData(csMsg));
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>ログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> LogOut(lLogLvl, csClassName, csMethodName, csMsg) </para>
        /// </example>
        /// <param name="lLogLvl">ログレベル</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 LogOut(long lLogLvl, String csClassName, String csMethodName, String csMsg)
        {
            String csClassNameAndMethodName = csClassName + "::" + csMethodName;
            LogOut(lLogLvl, csClassNameAndMethodName, csMsg);
        }
        /// <summary><para>method outline:</para>
        /// <para>ログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> LogOut(lLogLvl, csClassNameAndMethodName, csMsg) </para>
        /// </example>
        /// <param name="lLogLvl">ログレベル</param>
        /// <param name="csClassNameAndMethodName">ログを書いているクラス名とメソッド名</param>
        /// <param name="csMsg">メッセージ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void LogOut(long lLogLvl, String csClassNameAndMethodName, String csMsg)
        {
            DateTime csDatatime = DateTime.Now;
            LogOut(lLogLvl, csDatatime.ToString() + " <" + csClassNameAndMethodName + ">  " + csMsg);
        }
        /// <summary><para>method outline:</para>
        /// <para>ログ出力</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> LogOut(lLogLvl, csMsg) </para>
        /// </example>
        /// <param name="lLogLvl">ログレベル</param>
        /// <param name="csMsg">メッセージ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        static public void LogOut(long lLogLvl, String csMsg)
        {
            if (lLogLvl <= m_lLogLvl)
            {   // new 文を使用したく無い為、余分に判断を入れる
                if (m_bSysCslDispFlg == true)
                {   // コンソール出力必要ならば
                    Console.WriteLine(csMsg);
                }
                if (m_bFileOutFlg == true)
                {   // ファイル出力必要ならば
                    m_csLogEventQueue.PushObject(new HySLogMessageData(new HySString(csMsg)));
                }
            }
        }

        /// <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
            {
                // ログファイルをオープンする
                m_csLogFile = new HySFile(m_csLogFileName);

                HySLogMessageData Msg;
                DateTime CreateTime;
                DateTime NowTime;

                // 同じ名称のログファイルがあるか確認する
                bool bExist = m_csLogFile.Exist();
                if (bExist != true)
                {
                    // 同じ名称のログファイルがない場合
                    // ファイルオープン処理（新規）
                    m_csLogFile.Open(HySFile.OPEN_MODE.CREATE_NEW, HySFile.READ_WRITE_MODE.WRITE, HySFile.DIRECTORY_MODE.MK_DIR);
                    CreateTime = File.GetLastWriteTime(m_csLogFileName.ToString());
                }
                else
                {
                    // 現在の日付と同じログファイルがある場合
                    // ファイルの作成日時と現在の日時を取得
                    CreateTime = File.GetLastWriteTime(m_csLogFileName.ToString());
                    NowTime = DateTime.Now;

                    // ファイルの作成した月と現在の月を比較
                    if (CreateTime.Month != NowTime.Month)
                    {
                        // 一致の場合
                        // 存在する同じ名称のログファイルを削除して新規作成する
                        m_csLogFile.Delete();
                        m_csLogFile.Open(HySFile.OPEN_MODE.CREATE_NEW, HySFile.READ_WRITE_MODE.WRITE, HySFile.DIRECTORY_MODE.MK_DIR);
                        CreateTime = File.GetLastWriteTime(m_csLogFileName.ToString());
                    }
                    else
                    {
                        // 不一致の場合
                        // 追記モードでファイルをオープンする
                        long lRtn = m_csLogFile.Open(HySFile.OPEN_MODE.APPEND, HySFile.READ_WRITE_MODE.WRITE, HySFile.DIRECTORY_MODE.NOT_MK_DIR);
                        if (lRtn != 0)
                        {
                            m_bFileOutFlg = false;
                        }
                    }
                }
                LogOut(ONLINE, (DateTime.Now.ToString() + "   >>>>  Start of Log <<<<"));
                // ログ書き込み処理（無限ループ）
                for (; ; )
                {
                    // ログデータ取得
                    Msg = (HySLogMessageData)m_csLogEventQueue.PullObject();

                    if (m_bFileOutFlg == true)
                    {
                        NowTime = DateTime.Now;

                        // ログ出力中の日付の変更を判定
                        if (CreateTime.Day != NowTime.Day)
                        {
                            // 現在のファイルクローズし、新規ファイルを生成する
                            m_csLogFile.Close();
                            HySString csFileName = null;
                            csFileName = HySEnvInf.GetEnvInf(new HySString("SYS_LOGFILENAME"));
                            m_csLogFileName = HySEnvInf.GetHomeDirectory() + new HySString("\\log\\") + csFileName + new HySString(NowTime.Day.ToString("00")) + new HySString(".txt");
                            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);
                            CreateTime = File.GetLastWriteTime(m_csLogFileName.ToString());
                        }
                        m_csLogFile.WriteText(Msg.GetMessage());
                    }
                    // 終了処理の場合
                    if (m_bStopFlg == true)
                    {
                        m_bStopFlg = false;
                        break;
                    }
                }
                // ファイルをクローズする
                m_csLogFile.Close();
            }
            catch (Exception ex)
            {
                HySFile csErrFile = new HySFile(HySEnvInf.sErorrFileName);
                csErrFile.Open(HySFile.OPEN_MODE.APPEND, HySFile.READ_WRITE_MODE.WRITE, HySFile.DIRECTORY_MODE.NOT_MK_DIR);
                csErrFile.WriteText("LogFile Out Error in HySLog.Run() ");
                csErrFile.WriteText(" catch exception : "+ex.Message );
                csErrFile.Close();
            }
        }
        //
    }
    // end of HySLog
}
