// <summary>ソースコード：業務処理クラス</summary>
// <author>CommonMP</author>

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

using System.Runtime.InteropServices;
using System.Diagnostics;

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


using CommonMP.HYMCO.Interface;
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreImpl.Data.ProjectCtl;
using CommonMP.HYMCO.CoreImpl.Data.StructInfo;
using CommonMP.HYMCO.CoreImpl.Tool;
using CommonMP.HYMCO.CoreImpl.BusiProc;

using CommonMP.HYMCO.CoreOption.McSTGSystemBase;

namespace CommonMP.HYMCO.AddInSysOptions.CordingSampleSys
{
    /// <summary><para>class outline:</para>
    /// <para>サンプルTGC業務クラス</para>
    /// </summary>
    /// <remarks>
    /// <para>history:</para>
    /// <para>[CommonMP][ver 1.2.0][2011/12/01][新規作成]</para>
    /// </remarks>
    public class SampleMySysBusiProc : McSTGSysBusiProcedureBase
    {
        /// <summary>サンプルコード用：ユーザーが設定するタイマー指定ＩＤ</summary>
        protected HySID m_csTimerID = new HySID("SampleTimer");

        // ------------------------------------------------
        //  派生側で実装すべきメソッド
        // ------------------------------------------------

        /// <summary><para>method outline:</para>
        /// <para>システム固有のフィードバック情報生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McSTGSysFeedbackDataBase csFeedbackData = CreateFeedbackData( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override public McSTGSysFeedbackDataBase CreateFeedbackData()
        {
            return new SampleMyFeedbakData();
        }

        /// <summary><para>method outline:</para>
        /// <para>システム起動直後の処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = StartBusiProc( csHySEvent ) </para>
        /// </example>
        /// <param name="csHySEvent">送られたイベント</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool StartBusiProc(HySEventObject csHySEvent)
        {
            // ★ 計算のモードを指定する（モデルの計算モードが　個別制御の場合は必須）
            //m_csSTGMngData.SetSTGCalMode(McSTGSysManageData.STGCalMode.SYNCHRONOUS_CAL);  // 全てのプロジェクトが一斉に計算を行う場合
            m_csSTGMngData.SetSTGCalMode(McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL);  // 各プロジェクトのモデル生成、計算開始を　プログラムで制御する場合


            // ★ 最初から画面を立ち上げておきたい場合等は、下記により画面を表示しておく（コーディング例）
            // 一般評価グラフ表示画面を表示
            this.RedrawLineGraph();

            // 独自画面を表示する場合
            //HySDataRoot csDispData = null;
            //this.RedrawSysScreen(SampleFloodPrdctSysDefine.MY_SCREEN_KIND, SampleFloodPrdctSysDefine.MY_SCREEN_ID, csDispData);

            // ★ コーディング例
            // 独自タイマー設定の例：(現在時刻から２分後に設定する)
            long lYear = 0; long lMonth = 0; long lDay = 0; long lHour = 0; long lMin = 0; long lSec = 0;
            HySCalendar.GetNowTime(ref lYear, ref lMonth, ref lDay, ref lHour, ref lMin, ref lSec);
            HySTime csTimeOut = HySCalendar.CreateTime(lYear, lMonth, lDay, lHour, lMin + 2, 0);
            this.SetTimer(m_csTimerID, csTimeOut);

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>ＳＴＧ計算指定時刻になったが、今だ計算続行中等により計算開始出来ない事を通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = CannotCalStart(csSetTime) </para>
        /// </example>
        /// <param name="csSetTime">ＳＴＧ計算に設定されていた時刻</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool CannotCalStart(HySTime csSetTime)
        {
            // 処理例：計算の継続が不能なため、１分間後に再度計算を開始するようにタイマーセット
            HySTime csWaitTime = new HySTime(1, 0); // 1分
            this.WaitCalculation(csSetTime, csWaitTime);  // 1分間待つ（１分後、計算開始が行われる）
            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>ＳＴＧ計算指定時刻になったことを通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> CalculationTimerOut( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// this.m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL　の時
        /// コールされる
        /// （this.m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.SYNCHRONOUS_CAL　の時はコールされない）
        /// </para>
        /// </remarks>
        override protected void CalculationTimerOut()
        {
            // ★：コーディング例
            if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
            {   // モデルの計算モードが　個別制御の場合
                // 指定プロジェクトのモデル構築を指示する(此処では、Prj01のも出る生成を指示する)
                this.CmndModelConstruction(new HySID("Prj01"));
            }
            else
            {   // モデルの計算モードが　一斉計算の場合
                // この時には　本メソッドはコールされないため、何もする必要がない。
            }

        }

        /// <summary><para>method outline:</para>
        /// <para>モデル構築通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = NoticeModelConstruction(csPrjID,csDtCnt) </para>
        /// </example>
        /// <param name="csPrjID">構築されたプロジェクトＩＤ</param>
        /// <param name="csDtCnt">プロジェクトが保持するデータコンテナ</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool NoticeModelConstruction(HySID csPrjID, HySSimulationDataContainer csDtCnt)
        {
            // ★：コーディング例

            // モデル構築が正常終了か異常終了か判断して、必要な処理を実施する
            McSimulationStatus csSimSta = (McSimulationStatus)csDtCnt.GetData(McDefine.HYM_DATA_SIMULATION_INFO);
            if (csSimSta.GetModelConStatus() == McSimulationStatus.ModelConstructionStatus.CONSTRUCTED)
            {   // モデル構築OKの場合
                if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
                {   // モデルの計算モードが　個別制御の場合
                    // モデル構築が終了したので初期化を指示する
                    this.CmndCalInitialize(csPrjID);
                }
                else
                {   // モデルの計算モードが　一斉計算の場合
                    // この時には　特に重要な処理は無し。
                }
            }
            else
            {
                // モデル構築異常終了通知を受け必要な処理を行なう。
                // 画面に通知
                HySEventObject csEventObject = new HySEventObject(HySSysEvent.OBJID_VIEWER, HySEventObject.NOTICE_NG_MODEL_CONSTRUCTION);
                csEventObject.SetToSimKind(m_csSimKindID);
                csEventObject.SetSuppID(csPrjID);
                this.PutEvent(csEventObject);
            }

            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル初期化完了通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = NoticeCalInitialize(csPrjID,csFeedBackData,csDtCnt) </para>
        /// </example>
        /// <param name="csPrjID">初期化されたプロジェクトＩＤ</param>
        /// <param name="csFeedBackData">プロジェクトが保持するフィードバック情報</param>
        /// <param name="csDtCnt">プロジェクトが保持するデータコンテナ</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool NoticeCalInitialize(HySID csPrjID, McSTGSysFeedbackDataBase csFeedBackData, HySSimulationDataContainer csDtCnt)
        {
            // ★：コーディング例
            if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
            {   // モデルの計算モードが　個別制御の場合
                if (m_csCmndSTGStartFlg == McSTGSysCtlInfo.CALCULATION_STATE)
                {   // 計算中の時のみ
                    // 初期化が終了したので計算開始を指示する
                    this.CmndCalStart(csPrjID);
                }
            }
            else
            {   // モデルの計算モードが　一斉計算の場合
                // この時には　特に重要な処理は無し。。
            }
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para> 計算完了通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = NoticeCalComplete(csPrjID,csFeedBackData,csDtCnt) </para>
        /// </example>
        /// <param name="csPrjID">計算が完了したプロジェクトＩＤ</param>
        /// <param name="csFeedBackData">プロジェクトが保持するフィードバック情報</param>
        /// <param name="csDtCnt">プロジェクトが保持するデータコンテナ</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool NoticeCalComplete(HySID csPrjID, McSTGSysFeedbackDataBase csFeedBackData, HySSimulationDataContainer csDtCnt)
        {
            // ★：コーディング例
            if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
            {   // モデルの計算モードが　個別制御の場合

                if (csPrjID.Equals(new HySID("Prj01")) == true)
                {   // Prj01が計算完了ならば

                    // 例：Prj03はPrj01 のフィードバック情報を元に指定要素モデルのプロパティ値を変更する
                    if (m_csCmndSTGStartFlg == McSTGSysCtlInfo.CALCULATION_STATE)
                    {   // 計算中の時のみ
                        SampleMyFeedbakData csFdbkDt = csFeedBackData as SampleMyFeedbakData;
                        if (csFdbkDt != null)
                        {
                            HySID csModPrjID = new HySID("Prj03"); // モデルを修正するプロジェクト

                            double dDlt = csFdbkDt.GetSimuData() - csFdbkDt.GetObservedData();
                            // ①指定モデルのプロパティ情報を取得する
                            HySString csMdlName = new HySString("パラメーター修正要素");
                            McCellModelPropertyInfo csPrpty = this.GetPropertyInfo(csModPrjID, csMdlName) as McCellModelPropertyInfo;
                            if (csPrpty != null)
                            {
                                // コーディングサンプルである為、物理的に意味は有りません
                                double dRough = 0.01;
                                csPrpty.GetInfo("m_dRough", ref dRough);
                                csPrpty.SetInfo("m_dRough", dRough - 0.001 * dDlt);

                                // ②指定モデルのプロパティ情報を更新する
                                this.SetPropertyInfo(csModPrjID, csMdlName, csPrpty); // <-- GetPropertyInfo() したcsPrpty と必ず同じインスタンスを設定する
                            }

                            // ③モデルの情報更新を確定する
                            this.CommitModelPropertyInfoSet(csModPrjID);
                        }

                        // 例：指定プロジェクトのモデル構築を指示する
                        this.CmndModelConstruction(new HySID("Prj02"));
                        this.CmndModelConstruction(new HySID("Prj03"));
                    }
                }
                else
                {   // Prj02,Prj03が計算完了ならば
                    // 画面に通知
                    this.RedrawCtlScreen(McSTGSysDefine.EVNO_REDRAW_STG_CTL_SCREEN);

                    // Prj02,Prj03 の終了状態をチェック
                    bool bEndFlg = true;  // 全プロジェクト計算完了チェックフラグ
                    McSTGSysCtlInfo csCtlInfo = m_csSTGMngData.GetCtlInfo(new HySID("Prj02"));
                    if (csCtlInfo != null)
                    {
                        if (csCtlInfo.GetCalStatus() != McSTGSysCtlInfo.END_STATE)
                        {   // Prj02は未だ計算完了ではないならば
                            bEndFlg = false;    // 系全体での計算も完了していない
                        }
                    }
                    else { bEndFlg = false; }
                    csCtlInfo = m_csSTGMngData.GetCtlInfo(new HySID("Prj03"));
                    if (csCtlInfo != null)
                    {
                        if (csCtlInfo.GetCalStatus() != McSTGSysCtlInfo.END_STATE)
                        {   // Prj03は未だ計算完了ではないならば
                            bEndFlg = false;    // 系全体での計算も完了していない
                        }
                    }
                    else { bEndFlg = false; }


                    if (bEndFlg == true)
                    {   // 全てのモデルの計算が完了したならば
                        if (m_csCmndSTGStartFlg == McSTGSysCtlInfo.CALCULATION_STATE)
                        {   // 計算中の時のみ
                            //【★重要】全計算終了を完了したことをシステムに通知する
                            this.SetSTGCalCompleteState();
                        }
                    }
                }
            }
            else
            {   // モデルの計算モードが　一斉計算の場合
                // 通常はなにもしない
            }

            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para> ＳＴＧを構成する全プロジェクトの計算完了通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = NoticeSTGCalComplete( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool NoticeSTGCalComplete()
        {
            // ★１．グラフの更新を指示する(コーディング例)
            this.RedrawLineGraph();


            // ★２．自作画面を表示を更新するコーディングサンプル(コーディング例)
            SampleMyDispData csDispData = new SampleMyDispData();// 表示データ
            HySSimulationDataContainer csCnt = m_csSTGMngData.GetDataContainer(new HySID("Prj01"));// Prj01のデータコンテナクラスを取得する
            if (csCnt != null)
            {   // コンテナ内部の情報を元に、表示データを設定する
                csDispData.SetCalStartTime((HySTime)csCnt.GetStartTime());
                csDispData.SetCalStopTime((HySTime)csCnt.GetGoalTime());
            }
            // 自作画面の表示更新指示
            this.RedrawSysScreen(SampleMySysDefine.MY_SCREEN_KIND, SampleMySysDefine.MY_SCREEN_ID, csDispData);



            // ★３．計算モードによる処理の変更（コーディング例）
            if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
            {   // モデルの計算モードが　個別制御の場合
                // 個別制御の特別なコーディングを此処に入れる Do something
            }
            else
            {   // モデルの計算モードが　一斉計算の場合
                // コーディング例
                // 例：Prj05はPrj05 のフィードバック情報を元に指定要素モデルのプロパティ値を変更する
                SampleMyFeedbakData csFdbkDt = this.GetFeedbackData(new HySID("Prj05")) as SampleMyFeedbakData;
                if (csFdbkDt != null)
                {
                    HySID csModPrjID = new HySID("Prj06"); // モデルを修正するプロジェクト

                    // 特定モデルのプロパティ情報を変更する場合の例

                    // ①指定モデルのプロパティ情報を取得する
                    HySString csMdlName = new HySString("シミュレーターモデル");
                    McCellModelPropertyInfo csPrpty = this.GetPropertyInfo(csModPrjID, csMdlName) as McCellModelPropertyInfo;
                    if (csPrpty != null)
                    {
                        // コーディングサンプルである為、物理的に意味は有りません
                        double dDlt = csFdbkDt.GetSimuData() - csFdbkDt.GetObservedData();
                        double dRough = 0.01;
                        csPrpty.GetInfo("m_dRough", ref dRough);
                        csPrpty.SetInfo("m_dRough", dRough - 0.001 * dDlt);

                        // ②指定モデルのプロパティ情報を更新する
                        this.SetPropertyInfo(csModPrjID, csMdlName, csPrpty); // <-- GetPropertyInfo() したcsPrpty と必ず同じインスタンスを設定する
                    }
                    // ①’指定モデルのプロパティ情報を取得する
                    csMdlName = new HySString("観測データ取得モデル");
                    csPrpty = this.GetPropertyInfo(csModPrjID, csMdlName) as McCellModelPropertyInfo;
                    if (csPrpty != null)
                    {
                        //double dDlt = csFdbkDt.GetSimuData() - csFdbkDt.GetObservedData();
                        //double dRough = 0.01;
                        //csPrpty.GetInfo("m_dRough", ref dRough);
                        //csPrpty.SetInfo("m_dRough", dRough - 0.001 * dDlt);

                        // ②’指定モデルのプロパティ情報を更新する
                        //this.SetPropertyInfo(csModPrjID, csMdlName, csPrpty); // <-- GetPropertyInfo() したcsPrpty と必ず同じインスタンスを設定する
                    }

                    // ③各要素モデルのプロパティを設定した後、情報更新を確定する
                    // ★プロパティ情報を設定した後は本メソッドコールが必須
                    this.CommitModelPropertyInfoSet(csModPrjID);
                }
                
            }

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>システム固有ヘルプ表示</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = DispSysHelp( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        override protected bool DispSysHelp()
        {
            // コーディング例（PDFファイルを表示する）
            HySString csPDFFile = HySEnvInf.GetHomeDirectory() + new HySString("\\help\\UserSys\\SampleTGCManual.pdf");
            return this.ShowManual(csPDFFile);
        }

        /// <summary><para>method outline:</para>
        /// <para>SetTimer()で設定した時刻のタイムアウト検出通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = TimeOut(csKeyID,csSetTime) </para>
        /// </example>
        /// <param name="csKeyID">SetTimer() で　指定したタイマーＩＤ</param>
        /// <param name="csSetTime">SetTimer() で指定した時刻</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// 特別な処理がなければオーバーライドメソッドをコーディングする必要なし。
        /// 精度：　PC内のシステム時刻に対して 約＋－１秒
        /// </para>
        /// </remarks>
        override protected bool TimeOut(HySID csKeyID, HySTime csSetTime)
        {
            // コーディング例
            // 特別な処理がなければ本メソッドをコーディングする必要なし

            // 繰り返しタイマーを設定したい場合には、タイマーを次時間に設定して　再度登録する必要がある
            // タイマーの再設定の例
            HySTime csNextTimeOut = csSetTime + new HySTime(5,0); // 先の設定時刻から、５分後を設定する
            this.SetTimer(csKeyID, csNextTimeOut);

            return true;
        }
 
        /*
        /// <summary><para>method outline:</para>
        /// <para>計算開始通知</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> bool bRtn = NoticeCalStart(csPrjID,csDtCnt) </para>
        /// </example>
        /// <param name="csPrjID">計算開始したプロジェクトＩＤ</param>
        /// <param name="csDtCnt">プロジェクトが保持するデータコンテナ</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>特別な処理がなければオーバーライドメソッドをコーディングする必要なし</para>
        /// </remarks>
        override protected bool NoticeCalStart(HySID csPrjID, HySSimulationDataContainer csDtCnt)
        {
            // 通常は何もしなくても良い
            // 特別な処理がなければ本メソッドをコーディングする必要なし
            return true;
        }
        */


    }
}
