// <summary>ソースコード：収束演算制御基底クラス(水利収束演算制御)</summary>
// <author>CommonMP</author>

using System;
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;
using CommonMP.HYMCO.Interface.Controller;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.Interface.Model;
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreImpl.Data.TranInfo;
using CommonMP.HYMCO.CoreImpl.Controller;
using CommonMP.HYMCO.CoreImpl.Tool;

namespace CommonMP.HYMCO.CoreImpl.Model
{
    /// <summary><para>class outline:</para>
    /// <para>収束演算制御クラス(水理収束演算制御)</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.3.0][2012/12/01][新規作成]</para>
    /// <para>Remarks</para>
    /// <para>無し</para>
    /// </remarks>
    public class McHydraulicCnvrgncGrCtlBaseH24 : McCnvrgncIterationCtlBase
    {
        /// <summary> 水理収束演算使用：フィードバック結合クラス </summary>
        protected McHydraulicCnvgncMdlCnctBaseH24 m_csHydraulicFeedback;

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McHydraulicCnvrgncCtlH24 csObj = new McHydraulicCnvrgncCtlH24( )</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>生成したインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public McHydraulicCnvrgncGrCtlBaseH24()
        {
            //m_eDtFusionTiming = McDefine.DataFusionTiming.SYNCHRONOUS; // 同期をデフォルト化　←　親クラスで実施済み
            
            // 収束ループの都度に全初期は行わず、前回計算結果はそのまま残しておく（ 収束条件初期値等が前回結果に応じて修正されている）
            m_eInitializeLevel = McDefine.ElementMemoryLevel.ELEMENT_MEMORY_SNDPORT_ONLY;
        }



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

        /// <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;
            //  内部の McHydraulicFeedbackBaseH24 の個数を数え、１個の場合のみOKとする。
            //  また、McHydraulicFeedbackBaseH24 をリストの最後に持っていく
            if( ChangeCalOrder() != 1 )
            {   // McHydraulicFeedbackBaseH24要素の数が１個以上あるとき
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckErrorData(this.m_csElement.GetID(), new HySObjectKind("McHydraulicCnvrgncCtlH24"),
                    Properties.HymcoImplResources.STATEMENT_MUST_HAVE_ONLE_ELEMENT );
               // csErrorInf.AddCheckErrorData(this.m_csElement.GetID(), new HySObjectKind("McHydraulicCnvrgncCtlH24"), " McHydraulicCnvrgncCtlH24 must have only one McHydraulicFeedbackBaseH24 element.");

                bRtn = false;
            }

            if (m_csHydraulicFeedback != null)
            {
                m_lMaxIterationNum = m_csHydraulicFeedback.GetMaxConversionLoopNum();
            }

            // McHydraulicFeedbackBaseH24に対して、直接外から入力がある場合にはエラー
            if (CheckOuterConnection(ref csErrorInf) == false)
            {
                bRtn = false;
            }

            // 親クラスの演算可能性チェック(上記チェックが終わった後に親クラスのチェックを行う。＜＝＝重要)
            if (base.IsAbleToCalculate(ref csInputDataList, ref csOutputDataList, ref csErrorInf) == false)
            {
                bRtn = false;
            }

            return bRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>計算リスト上の順序を変更する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = ChangeCalOrder()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>long : McHydraulicFeedbackBaseH24要素の数</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>McHydraulicFeedbackBaseH24要素を最後に持ってくると共にMcHydraulicFeedbackBaseH24要素の数を返す</para>
        /// </remarks>
        protected virtual long ChangeCalOrder()
        {
            long lRtn = 0;
            m_csHydraulicFeedback = null;
            LinkedListNode<McElement> csElmNode = null;
            McElement csElm;
            McHydraulicCnvgncMdlCnctBaseH24 csFeedbackElm = null;
            long lElmNum = m_csElementList.Count;

            // McHydraulicFeedbackBaseH24 要素の個数をカウント
            csElmNode = m_csElementList.First;
            for (long lEp = 0; lEp < lElmNum; lEp++)
            {
                csElm = csElmNode.Value;
                csFeedbackElm = csElm.GetCalModel() as McHydraulicCnvgncMdlCnctBaseH24;
                if (csFeedbackElm != null)
                {
                    m_csHydraulicFeedback = csFeedbackElm; 
                    lRtn += 1;
                }
                // 次の演算要素取得
                csElmNode = csElmNode.Next;
            }

            // // McHydraulicFeedbackBaseH24 要素の順番を最後に持ってくる
            for (long lLp = 0; lLp < lElmNum; lLp++)
            {
                bool bChngFlg= false;
                csElmNode = m_csElementList.First;
                for (long lEp = 0; lEp < lElmNum-lRtn; lEp++)
                {
                    csElm = csElmNode.Value;
                    csFeedbackElm = csElm.GetCalModel() as McHydraulicCnvgncMdlCnctBaseH24;
                    if (csFeedbackElm != null)
                    {   // フィードバック要素ならば

                        // 現在のエレメントを外し、最後に入れる
                        m_csElementList.Remove(csElm);
                        m_csElementList.AddLast(csElm);
                        bChngFlg = true;
                        break;
                    }
                    // 次の演算要素取得
                    csElmNode = csElmNode.Next;
                }
                if (bChngFlg == false)
                {
                    break;
                }
            }
            //csElmNode = m_csElementList.Last;
            //m_csHydraulicFeedback = csElmNode.Value as McHydraulicFeedbackBaseH24;

            return lRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算可能かをチェックする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = CheckOuterConnection(ref csErrorInf)</para>
        /// </example>
        /// <param name="csErrorInf">エラー出力</param>
        /// <returns>=true:演算可能、=false:演算不能</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>必要ならば派生クラス側でオーバーライドする</para>
        /// </remarks>
        protected virtual bool CheckOuterConnection(ref McStructErrorInfo csErrorInf)
        {
            bool bRtn = true;
            return bRtn;
        }
        
        /// <summary><para>method outline:</para>
        /// <para>グループ内の要素が自分が期待している要素か否かをチェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = InnerElementCheck(ref csErrorInf)</para>
        /// </example>
        /// <param name="csErrorInf">エラー出力</param>
        /// <returns>=true:正常、=false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>ループ内の要素に指定がある場合、収束演算を行う処理は本チェックにおいて、
        /// 予定外要素が　グループ内に存在しないことを確認する。</para>
        /// </remarks>
        public override bool InnerElementCheck(ref McStructErrorInfo csErrorInf)
        {
            if (m_csHydraulicFeedback != null)
            {
                return m_csHydraulicFeedback.InnerElementCheck(ref csErrorInf, ref m_csCnvItrInfo);
            }
            else
            {
                return false;
            }
        }

        /*
        /// <summary><para>method outline:</para>
        /// <para>演算順序のチェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = CheckCalculationOrder( )</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns> long
        /// 正常時：McDefine.CALCULATION_NORMAL_RETURN
        /// 異常時：McDefine.CALCULATION_ABEND_RETURN_BECAUSE_OF_STRUCT_ERROR
        /// </returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// 非同期演算の時有効
        /// 演算順序を上流から下流に並び替える。
        /// もし、ループ等があればエラーを返す
        /// </para>
        /// </remarks>
        public override long CheckCalculationOrder()
        {
            return McDefine.CALCULATION_NORMAL_RETURN;
        }
        */

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

        /// <summary><para>method outline:</para>
        /// <para>モデルを初期化する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>Initialize(ref csInitialData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool Initialize(ref McPropertyInfoRoot csInitialData)
        {
            return true;
        }
   
        /*
        /// <summary><para>method outline:</para>
        /// <para>演算実行中断中のモデルを初期化</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>Initialize(ref csInitialData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>演算中断中にプロパティ、初期値等を変更して動作させ場合等に使用する</para>
        /// </remarks>
        //protected override bool OnlineInitialize(ref McPropertyInfoRoot csInitialData)
        //{ return true; }
        **/




        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = IsConverged(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>=true:収束完了 =false:未収束</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool IsConverged(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            return m_csHydraulicFeedback.CheckConvergence(ref csConvergeCondInfo);
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetUpConvergenceInf(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>系全体で次の計算を行う場合に呼ばれる</para>
        /// </remarks>
        protected override void SetUpConvergenceInf(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            m_csHydraulicFeedback.SetUpConvergenceInf(ref csConvergeCondInfo);
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別変更</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ModifyConvergenceInf(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>系全体で次の計算を行う場合に呼ばれる</para>
        /// </remarks>
        protected override void ModifyConvergenceInf(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            m_csHydraulicFeedback.ModifyConvergenceInf(ref csConvergeCondInfo);
        }
        /// <summary><para>method outline:</para>
        /// <para>計算前状態復帰直後処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>PostRemenber(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>収束演算中に計算前状態へ戻された直後に呼ばれる</para>
        /// </remarks>
        protected override void PostRemenber(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            m_csHydraulicFeedback.PostRemenber(ref csConvergeCondInfo);
        }
        /// <summary><para>method outline:</para>
        /// <para>非収束時の処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = NotConvergedOperation(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>long </returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>規定回数トライしたものの結局収束できなかった場合に　行うベキ処理を記述</para>
        /// </remarks>
        protected override long NotConvergedOperation(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            return m_csHydraulicFeedback.NotConvergedOperation(ref csConvergeCondInfo);
        }

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

        /// <summary><para>method outline:</para>
        /// <para>収束演算用：プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetCnvrgncProperty(csPropertyInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool SetCnvrgncProperty(McPropertyInfoRoot csPropertyInfo)
        {
            McGroupPropertyInfo csGrPrptyInf = csPropertyInfo as McGroupPropertyInfo;
            if (csGrPrptyInf != null)
            {
                this.SetDataFusionTiming(csGrPrptyInf.GetDataFusionTiming());
            }
            return true;
        }


    }
}


