// <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.SampleFloodPrediction
{
    /// <summary><para>class outline:</para>
    /// <para>業務処理クラス</para>
    /// </summary>
    /// <remarks><para>remarks:</para>
    /// <para>無し</para>
    /// </remarks>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.2.0][2011/10/01][新規作成]</para>
    /// </remarks>
    public class SampleFloodPrdctBusiProc : McSTGSysBusiProcedureBase
    {
        /// <summary>ユーザーが設定するタイマー指定ＩＤ</summary>
        protected HySID m_csTimerID = new HySID("SampleTimer");
        /// <summary>フィードバック情報</summary>
        protected SampleFloodPrdctFeedbakData csFdbkDt = null;
        /// <summary>時刻文字列</summary>
        protected string Str_date = null;

        /// <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 SampleFloodPrdctFeedbakData();
        }

        /// <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 StartBusiProc(HySEventObject csHySEvent)
        {
            // 計算のモードを指定する
            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, lMin, 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)
            {   // モデルの計算モードが　個別制御の場合
                // 指定プロジェクトのモデル構築を指示する
                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 csCnt)
        {
            // モデル構築が正常終了か異常終了か判断して、必要な処理を実施する
            McSimulationStatus csSimSta = (McSimulationStatus)csCnt.GetData(McDefine.HYM_DATA_SIMULATION_INFO);
            if (csSimSta.GetModelConStatus() == McSimulationStatus.ModelConstructionStatus.CONSTRUCTED)
            {
                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 csCnt)
        {
            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 csCnt)
        {
            if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
            {//モデルの計算モードが個別制御の場合
                if (csPrjID.Equals(new HySID("Prj01")) == true)
                {   // Prj01が計算完了ならば
                    this.CmndModelConstruction(new HySID("Prj06"));
                    this.CmndModelConstruction(new HySID("Prj07"));
                    this.CmndModelConstruction(new HySID("Prj08"));
                    this.CmndModelConstruction(new HySID("Prj09"));
                    this.CmndModelConstruction(new HySID("Prj10"));
                }
                else if (csPrjID.Equals(new HySID("Prj11")) == true)
                {
                    csFdbkDt = csFeedBackData as SampleFloodPrdctFeedbakData;

                    //Prj12に重み反映
                    if (m_csCmndSTGStartFlg == McSTGSysCtlInfo.CALCULATION_STATE)
                    {// 計算中の時のみ
                        if (csFdbkDt != null)
                        {
                            HySID csModPrjID = new HySID("Prj12");
                            HySString csMdlName = new HySString("MultiplyWeight");

                            McCellModelPropertyInfo csPrpty =
                                this.GetPropertyInfo(csModPrjID, csMdlName) as McCellModelPropertyInfo;
                            if (csPrpty != null)
                            {
                                for (long lLp = 0; lLp < 5; lLp++)
                                {
                                    double aaa = 0.0D;
                                    string csKey = string.Format("m_dWeight{0:D2}", lLp);
                                    csPrpty.GetInfo(csKey, ref aaa);
                                    csPrpty.SetInfo(csKey, csFdbkDt.GetWeight(lLp));
                                }
                                // ②指定モデルのプロパティ情報を更新する
                                this.SetPropertyInfo(csModPrjID, csMdlName, csPrpty); // <-- GetPropertyInfo() したcsPrpty と必ず同じインスタンスを設定する
                            }
                            // ③モデルの情報更新を確定する
                            this.CommitModelPropertyInfoSet(csModPrjID);
                        }
                    }

                    this.CmndModelConstruction(new HySID("Prj12"));
                }
                else if (csPrjID.Equals(new HySID("Prj12")) == true)
                {
                    if (m_csCmndSTGStartFlg == McSTGSysCtlInfo.CALCULATION_STATE)
                    {   // 計算中の時のみ
                        // 全計算終了を完了したことをシステムに通知する
                        this.SetSTGCalCompleteState();
                    }
                }
                else
                {
                    // 画面に通知
                    this.RedrawCtlScreen(McSTGSysDefine.EVNO_REDRAW_STG_CTL_SCREEN);

                    const int PrjNum = 5;
                    string[] projNAME = new string[PrjNum] { "Prj06", "Prj07", "Prj08", "Prj09", "Prj10" };

                    bool bEndFlg = true;  // 全プロジェクト計算完了チェックフラグ
                    for (long i = 0; i < PrjNum; i++)
                    {
                        //終了状態をチェック
                        McSTGSysCtlInfo csCtlInfo = m_csSTGMngData.GetCtlInfo(new HySID(projNAME[i]));
                        if (csCtlInfo != null)
                        {
                            if (csCtlInfo.GetCalStatus() != McSTGSysCtlInfo.END_STATE) { bEndFlg = false; }
                        }
                        else { bEndFlg = false; }
                    }
                    if (bEndFlg == true)
                    {// 全てのモデルの計算が完了したならば
                        if (m_csCmndSTGStartFlg == McSTGSysCtlInfo.CALCULATION_STATE)
                        {// 計算中の時のみ
                            SampleFloodPrdctFeedbakData csFdbkDt = csFeedBackData as SampleFloodPrdctFeedbakData;
                            if (csFdbkDt != null)
                            {
                                HySID csModPrjID = new HySID("Prj11");
                                HySString csMdlName = new HySString("フィードバック要素");

                                McCellModelPropertyInfo csPrpty =
                                    this.GetPropertyInfo(csModPrjID, csMdlName) as McCellModelPropertyInfo;
                                if (csPrpty != null)
                                {
                                    string aaa = null;
                                    csPrpty.GetInfo("m_sNowTime", ref aaa);
                                    csPrpty.SetInfo("m_sNowTime", Str_date);

                                    // ②指定モデルのプロパティ情報を更新する
                                    this.SetPropertyInfo(csModPrjID, csMdlName, csPrpty);
                                }
                                // ③モデルの情報更新を確定する
                                this.CommitModelPropertyInfoSet(csModPrjID);
                            }
                        }
                        this.CmndModelConstruction(new HySID("Prj11"));
                    }
                }
            }
            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();

            //画面表示用のデータクラス
            SampleFloodPrdctDispData csDispData = new SampleFloodPrdctDispData();
            // Prj01のデータコンテナクラスを取得する
            HySSimulationDataContainer csCnt = m_csSTGMngData.GetDataContainer(new HySID("Prj01"));
            if (csCnt != null)
            {   // コンテナ内部の情報を元に、表示データを設定する
                csDispData.SetCalStartTime((HySTime)csCnt.GetStartTime());
                csDispData.SetCalStopTime((HySTime)csCnt.GetGoalTime());
            }
            //計算結果と重み
            for (long lP = 0; lP < 5; lP++)
            {
                csDispData.SetSimuData(csFdbkDt.GetSimuData(lP), lP);
                csDispData.SetWeight(csFdbkDt.GetWeight(lP), lP);
            }
            csDispData.SetObservedData(csFdbkDt.GetObservedData());
            //画面の表示更新
            this.RedrawSysScreen(SampleFloodPrdctSysDefine.MY_SCREEN_KIND, SampleFloodPrdctSysDefine.MY_SCREEN_ID, csDispData);
            
            // 計算モードによる処理の変更
            if (m_csSTGMngData.GetSTGCalMode() == McSTGSysManageData.STGCalMode.ASYNCHRONOUS_CAL)
            {   // モデルの計算モードが　個別制御の場合
            }
            else
            {   // モデルの計算モードが　一斉計算の場合                
            }

            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()
        {
            HySString csPDFFile = HySEnvInf.GetHomeDirectory() + new HySString("\\help\\UserSys\\SampleFloodPredictionManual.pdf");
            HySFile csFile = new HySFile(csPDFFile);
            if (csFile.Exist() == true)
            {
                //Process.Start(csPDFFile.ToString());
                this.ShowManual(csPDFFile);
            }
            return true;
        }

        /// <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 csCnt)
        {
            Str_date = HySCalendar.ToString(this.m_csNowTime.AddTime(1800), HySCalendar.FORMAT.lSW_YEAR);

            return true;
        }
    }
}
