// <summary>ソースコード：制御用モデル基底クラス</summary>
// <author>CommonMP</author>

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

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

using CommonMP.HYMCO.Interface;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.Interface.Controller;


namespace CommonMP.HYMCO.Interface.Model
{
    /// <summary><para>class outline:</para>
    /// <para>制御用モデル基底クラス（抽象クラス）</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>
    /// [CommonMP][ver 1.0.0][2008/10/01][新規作成]
    /// [CommonMP][ver 1.4.0][2013/12/10][メソッド追加]
    /// </para>
    /// <para>Remarks:</para>
    /// <para>無し</para>
    /// </remarks>
    public abstract class McIOCtlModlBase : McCalModelEssential
    {
        /// <summary>要素内演算中データ</summary>
        protected McCalInfo m_csCalInfo = null;

        /// <summary> Calculate()メソッドコールフラグ DataFusion()メソッドコール前 </summary>
        protected long m_lCalculate_Call_Before_DataFution_Call = 0;

        //// <summary>保存演算時刻</summary>
        //protected HySTime m_csMemorySimTime = null;
        /// <summary>保存目標時刻</summary>
        protected HySTime m_csMemoryTgtTime = HySTime.DEFAULT_TIME.Clone();
        //★★★★★★★★★★★★★★★★★★
        // Ver1.4で追加(マージ出力要素モデル)
        //★★★★★★★★★★★★★★★★★★
        /// <summary>入出力要素モデル独自のタイムステップ設定済み確認フラグ</summary>
        protected bool m_bDltTimeSetFlg = false;


        //=========================
        // 演算実行前処理関連メソッド
        //=========================

        /// <summary><para>method outline:</para>
        /// <para>モデル演算可能かをチェックする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = IsAbleToCalculate(ref csInputDataList, ref csOutputDataList, ref csErrorInf)</para>
        /// </example>
        /// <param name="csInputDataList">前段接続要素からの伝送情報リスト</param>
        /// <param name="csOutputDataList">前段接続要素への伝送情報リスト</param>
        /// <param name="csErrorInf">エラー出力</param>
        /// <returns>=true:演算可能、=false:演算不能</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool IsAbleToCalculate(ref HySDataLinkedList csInputDataList, ref HySDataLinkedList csOutputDataList, ref McStructErrorInfo csErrorInf)
        {
            bool bRtn = true;
            if (this.ReceiveConnectionCheck(ref csInputDataList, ref csErrorInf) == false)
            {   // 入力情報チェック
                bRtn = false;
            }
            if (this.SendConnectionCheck(ref csOutputDataList, ref csErrorInf) == false)
            {   // 出力情報チェック
                bRtn = false;
            }
            return bRtn;
        }

        //=======================
        // 演算実行処理関連メソッド
        //=======================
        /*
        /// <summary><para>method outline:</para>
        /// <para>接続線のみ初期化する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>InputConnectionInitialize(ref csInitialData, ref csInputDataList)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <param name="csInputDataList">前段接続要素からの伝送情報リスト</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>Initialize()はモデル内部まで初期化するが、本メソッドはモデルに接続されている接続線情報を初期化する</para>
        /// </remarks>
        public override bool InputConnectionInitialize(ref McPropertyInfoRoot csInitialData, ref HySDataLinkedList csInputDataList)
        {
            return true;
        }
        **/

        /// <summary><para>method outline:</para>
        /// <para>モデル演算</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = Calculate(ref csInputDataList)</para>
        /// </example>
        /// <param name="csInputDataList">演算に必要な入力情報リスト</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override long Calculate(ref HySDataLinkedList csInputDataList)
        {
            m_lCalculate_Call_Before_DataFution_Call += 1; // Calculate Call 回数カウントアップ
            return 0;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = IsConverged(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>=true:正常、=false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool IsConverged()
        {
            bool bRtn = false;
            if (m_csSimTime.Before(m_csTgtTime) != true)
            {   // 計算時刻が、目標時刻を超えたならば
                bRtn = true;
            }
            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算結果を外部のエレメントに対して公開する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = DataFusion(ref csOutputDataList)</para>
        /// </example>
        /// <param name="csOutputDataList">演算結果を公開する出力情報リスト</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override long DataFusion(ref HySDataLinkedList csOutputDataList)
        {
            long lRtn = 0;
            if (m_lCalculate_Call_Before_DataFution_Call > 0)
            {
                lRtn = DataFusion();
                m_lCalculate_Call_Before_DataFution_Call = 0;
            }
            return lRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算結果を外部のエレメントに対して公開する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = DataFusion( )</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected abstract long DataFusion();

        /// <summary><para>method outline:</para>
        /// <para>計算開始時に動作する処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = ReadyCalculation( )</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true :正常 , false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>計算開始の　最初に１回だけコールされるメソッドです。不要ならば、本メソッドをオーバーライドする必要はありません。</para>
        /// </remarks>
        public override bool ReadyCalculation()
        {
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>計算終了時に動作する処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = CompleteCalculation( )</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true :正常 , false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>計算終了時　最後の最初に１回だけコールされるメソッドです。不要ならば、本メソッドをオーバーライドする必要はありません。</para>
        /// </remarks>
        public override bool CompleteCalculation()
        {
            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>計算中断時に動作する処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = SuspendCalculation( )</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>true :正常 , false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>計算中断時　最初に１回だけコールされるメソッドです。不要ならば、本メソッドをオーバーライドする必要はありません。</para>
        /// </remarks>
        public override bool SuspendCalculation()
        {
            return true;
        }

        /*
        /// <summary><para>method outline:</para>
        /// <para>シミュレーションデータコンテナの内容を設定する処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetSimDataContainerInfo( csDataContainer )</para>
        /// </example>
        /// <param name="csDataContainer">シミュレーションデータコンテナ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public abstract void SetSimDataContainer(HySSimulationDataContainer csDataContainer);
        */

        /// <summary><para>method outline:</para>
        /// <para>モデル内部の時刻を進める</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>GainSimulationTime()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void GainSimulationTime()
        {
            ////m_csSimTime = m_csTgtTime;
            //m_csSimTime.SetTime(m_csTgtTime.GetTime());
            //m_csSimTime.SetGeologicalYear(m_csTgtTime.GetGeologicalYear());
            //★★★★★★★★★★★★★★★★★★
            // Ver1.4で追加(マージ出力要素モデル)
            //★★★★★★★★★★★★★★★★★★
            m_csSimTime.Add(m_csDltTime); 
        }

        /// <summary><para>method outline:</para>
        /// <para>演算用刻み時間を自動的に変更する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ChangeDeltaTimeAutomatically()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void ChangeDeltaTimeAutomatically()
        {
            // Do Nothing
        }

        //================
        // 各種設定メソッド
        //================

        /// <summary><para>method outline:</para>
        /// <para>モデル演算中の情報格納クラスを設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetCalInfo(csCalInfo)</para>
        /// </example>
        /// <param name="csCalInfo">演算結果格納するクラス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetCalInfo(McCalInfo csCalInfo)
        {
            m_csCalInfo = csCalInfo;
            if (m_csCalInfo != null)
            {
                if (m_csElement != null)
                {
                    csCalInfo.SetID(m_csElement.GetID());
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算中の情報格納クラスを取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>McCalInfo csCalInfo = GetCalInfo()</para>
        /// </example>
        /// <param name=""></param>
        /// <returns>モデル演算中の情報格納クラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override McCalInfo GetCalInfo()
        { return m_csCalInfo; }


        /// <summary><para>method outline:</para>
        /// <para>演算時刻を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetSimulationTime(csCalTime)</para>
        /// </example>
        /// <param name="csCalTime">演算時刻</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetSimulationTime(HySTime csCalTime)
        {
            m_csSimTime.SetTime(csCalTime);
            m_csSimTime.SetGeologicalYear(csCalTime.GetGeologicalYear());
        }


        /// <summary><para>method outline:</para>
        /// <para>演算時刻を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySTime csSimuTime = GetSimulationTime()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>演算時刻</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override HySTime GetSimulationTime()
        {
            return m_csSimTime;
        }
        /// <summary><para>method outline:</para>
        /// <para>演算済みのシミュレーション時刻を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySTime csSimuTime = GetCalDoneTime()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>HySTime 演算済みのシミュレーション時刻</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>演算済みのシミュレーション時刻と内部のシミュレーション時刻が一致しないモデルの場合に必要</para>
        /// </remarks>
        public override HySTime GetCalDoneTime()
        {
            return m_csSimTime;
        }
        /// <summary><para>method outline:</para>
        /// <para>演算開始時刻を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetStartTime(csStartTime)</para>
        /// </example>
        /// <param name="csStartTime">演算開始時刻</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetStartTime(HySTime csStartTime)
        {
            //Do Nothing;
        }

        /// <summary><para>method outline:</para>
        /// <para>演算目標時刻を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetTargetTime(csTgtTime)</para>
        /// </example>
        /// <param name="csTgtTime">目標時刻</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetTargetTime(HySTime csTgtTime)
        {
            m_csTgtTime.SetTime(csTgtTime);
            m_csTgtTime.SetGeologicalYear(csTgtTime.GetGeologicalYear());
        }
        /// <summary><para>method outline:</para>
        /// <para>演算目標時刻を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySTime csTgtT = GetTargetTime()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>演算目標時刻</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override HySTime GetTargetTime()
        {
            return m_csTgtTime;
        }
        /// <summary><para>method outline:</para>
        /// <para>演算中に次の演算目標時刻を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetNextTargetTime(ref csCalTime, ref csDltTime)</para>
        /// </example>
        /// <param name="csCalTime">現在時刻</param>
        /// <param name="csDltTime">増加時間</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetNextTargetTime(ref HySTime csCalTime, ref HySTime csDltTime)
        {
            m_csTgtTime.SetTime(csCalTime.GetTime() + csDltTime.GetTime());
            //★★★★★★★★★★★★★★★★★★
            // Ver1.4で追加(マージ出力要素モデル)
            //★★★★★★★★★★★★★★★★★★
            if (m_bDltTimeSetFlg == false)
            {
                m_csDltTime.SetTime(csDltTime.GetTime());
                m_csDltTime.SetGeologicalYear(csDltTime.GetGeologicalYear());
            }
        }
        /// <summary><para>method outline:</para>
        /// <para>演算刻み時間を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetDeltaTime(csDltTime)</para>
        /// </example>
        /// <param name="csDltTime">演算刻み時間</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetDeltaTime(HySTime csDltTime)
        {
            //Do Nothing;
        }

        /// <summary><para>method outline:</para>
        /// <para>演算刻み時間を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySTime csDtlT = GetDeltaTime()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>演算刻み時間</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override HySTime GetDeltaTime()
        {
            return m_csDltTime;
        }

        /// <summary><para>method outline:</para>
        /// <para>解法を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetSolutionType(elType)</para>
        /// </example>
        /// <param name="elType">解法（通常計算／収束計算）</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override void SetSolutionType(McDefine.SolutionType elType)
        {
            // Do Nothing
        }
        /// <summary><para>method outline:</para>
        /// <para>モデルの解法を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>McDefine.SolutionType eType = GetSolutionType()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>McDefine.SolutionType　解法（McCalculateModelBase.NORMAL_TYPE/CONVERGENCE_TYPE）</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override McDefine.SolutionType GetSolutionType()
        { return McDefine.SolutionType.NORMAL_TYPE; }


        //====================
        // その他必要なメソッド
        //====================

        /// <summary><para>method outline:</para>
        /// <para>プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetProperty(csPropertyInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool SetProperty(McPropertyInfoRoot csPropertyInfo)
        {
            bool bRtn = false;
            McModelPropertyIF csModelPropertyInfo = csPropertyInfo as McModelPropertyIF;
            if (csModelPropertyInfo != null)
            {
                //this.m_eInterpolateType = csModelPropertyInfo.GetInterpolateType();

                bRtn = this.SetProperty(csModelPropertyInfo);
            }
            return bRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetProperty(csPropertyInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public virtual bool SetProperty(McModelPropertyIF csPropertyInfo)
        {
            return true;
        }

        //★★★★★★★★★★★★★★★★★★★★★★★★★★★
        // Ver1.4で追加(プロパティ情報設定時のメッセージスロー)
        //★★★★★★★★★★★★★★★★★★★★★★★★★★★
        /// <summary><para>method outline:</para>
        /// <para>モデル構築時にプロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetProperty(csPropertyInfo, ref csErrorInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <param name="csErrorInfo">エラー情報</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool SetProperty(McPropertyInfoRoot csPropertyInfo, ref McStructErrorInfo csErrorInfo)
        {
            // 此処は仮。GISファイル出力の派生元クラスはMcBasicIOCtlModelBaseが正しいか？
            // 引数はMcCellModelPropertyIFかどうかも含め。
            bool bRtn = false;
            McModelPropertyIF csModelPropertyInfo = csPropertyInfo as McModelPropertyIF;
            if (csPropertyInfo != null)
            {
                //this.m_eInterpolateType = csModelPropertyInfo.GetInterpolateType();

                bRtn = this.SetProperty(csModelPropertyInfo, ref csErrorInfo);
            }
            return bRtn;
        }

        //★★★★★★★★★★★★★★★★★★★★★★★★★★★
        // Ver1.4で追加(プロパティ情報設定時のメッセージスロー)
        //★★★★★★★★★★★★★★★★★★★★★★★★★★★
        /// <summary><para>method outline:</para>
        /// <para>プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetProperty(csPropertyInfo, ref csErrorInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <param name="csErrorInfo">エラー情報</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public virtual bool SetProperty(McModelPropertyIF csPropertyInfo, ref McStructErrorInfo csErrorInfo)
        {
            bool bRtn = false;
            bRtn = this.SetProperty((McPropertyInfoRoot)csPropertyInfo);
            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>現在状態の一時記憶（但し計算途中状態は除く）</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Memorize() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>Memorize()とRemember()は対で使用する</para>
        /// </remarks>
        public override void Memorize()
        {
            m_csMemorySimTime.SetTime(m_csSimTime);
            m_csMemoryTgtTime.SetTime(m_csTgtTime);
        }

        /// <summary><para>method outline:</para>
        /// <para>Memorize()した情報の復元</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Remember() </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>Memorize()とRemember()は対で使用する</para>
        /// </remarks>
        public override void Remember()
        {
            m_csSimTime.SetTime(m_csMemorySimTime);
            m_csTgtTime.SetTime(m_csMemoryTgtTime);
        }
    }
}
