// <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;


namespace CommonMP.HYMCO.CoreImpl.Model
{
    /// <summary><para>class outline:</para>
    /// <para>ＨＹＭＣＯ収束演算制御クラス(一般的収束演算制御)</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2008/10/01][新規作成]</para>
    /// <para>Remarks</para>
    /// <para>本クラスは、プロトタイプ開発では、スタブとして提供する。実装の確認は、本番開発にて行う</para>
    /// </remarks>
    public class McTypicalConvergenceCtl : McConvergenceCtl
    {
        //=======================
        // 演算実行処理関連メソッド
        //=======================

        /// <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)
        {
            long lRtn = 0; // リターンコード

            long lLclRtn = 0;// ローカル変数
            int iElmCnt = m_csElementList.Count;  // グループ内のエレメント数取得

            if (McGrElementCtl.RESTART_STATE != this.m_lStatus)
            {   // 再開段階でなければ
                this.m_lStatus = McGrElementCtl.CALCULATION_STATE; // 計算モード
            }

            // 1)前準備として、csInputDataList の内容を　内部の要素に反映させる
            //  この処理は必要ない
            //long lInputDataNum = csInputDataList.GetRecordNum();
            //for (long lDtLp = 0; lDtLp < lInputDataNum; lDtLp++)
            //{
            //}
            
            // 2)エレメントに計算目標時刻設定
            if (McGrElementCtl.RESTART_STATE == this.m_lStatus)
            {   // 再開段階ならば

                // 再開時の演算要素を求める
                m_csElmNode = m_csElementList.First;
                for (int iLp = 0; iLp < m_iNodeItemNo; iLp++)
                {   // 個数分繰り返す
                    m_csElmNode = m_csElmNode.Next;
                }
                this.m_lStatus = McGrElementCtl.CALCULATION_STATE; // 計算モードへ移行
            }
            else
            {   // 再開段階ではなければ
                // 最初の要素から計算を進める
                m_csElmNode = m_csElementList.First;
                m_iNodeItemNo = 0;

                // 計算の目標時刻設定
                for (int iLp = 0; iLp < iElmCnt; iLp++)
                {   // 個数分繰り返す
                    m_csElementWork = m_csElmNode.Value;    // エレメント取得
                    m_csElementWork.SetTargetTime(m_csTgtTime);   // 各要素に演算時刻を設定する
                    //m_csElement.SetTargetTime(m_csSimTime + m_csDltTime);   // 各要素に演算時刻を設定する
                    //m_csElementWork.SetNextTargetTime(m_csSimTime, m_csDltTime);
                    // モノによっては、δTを変更する場合がある。
                }
            }


            // 3)グループ内の　演算のイテレーション開始  <-- このイテレーションは外部から制御を行う
            //for (int iTime = 0; iTime < 10000; iTime++)
            //{   // 実質的に∞繰り返し

            // 3-1 要素数分内部エレメントに計算を行わせる
            for (int iLp = m_iNodeItemNo; iLp < iElmCnt; iLp++)
            {   // 個数分繰り返す

                // 3-1-1 演算中断／終了時の処理
                if (McGrElementCtl.PAUSE_STATE == this.m_lStatus)
                {   // 計算中断モードならば　計算したところまでのノードを覚える
                    m_iNodeItemNo = iLp;
                    break;
                }
                else if (McGrElementCtl.STOP_STATE == this.m_lStatus)
                {   // 計算終了モードならば
                    break;
                }

                // 3-1-2 演算エレメント本体
                m_csElementWork = m_csElmNode.Value;    // エレメント取得

                // 3-1-3 個別要素の演算計算
                lLclRtn = m_csElementWork.Calculate(); // 内部の此処の要素に対して計算を行わせる
                if (lLclRtn != 0)
                {   // エラー有りならば
                    lRtn = -1;  // 全体の戻り値もエラー
                        // エラーログ等吐き出し
                }

                // 3-1-4 次の演算要素取得
                m_csElmNode = m_csElmNode.Next;

            } // end of for(要素数)

            // 3-2)計算中断判定
            //if ((McGrElementCtl.PAUSE_STATE == this.m_lStatus) ||
            //    (McGrElementCtl.STOP_STATE == this.m_lStatus))
            //{   // 計算中断または終了モードならば
            //    break;
            //    // 演算イテレーション終了
            //}

            // 3-3 内部エレメント同士ののデータ交換
            m_csElmNode = m_csElementList.First;
            for (int iLp = m_iNodeItemNo; iLp < iElmCnt; iLp++)
            {   // 個数分繰り返す
                m_csElementWork = m_csElmNode.Value;    // エレメント取得

                m_csElementWork.DataFusion(  );   // グループ内で演算結果交換

                m_csElmNode = m_csElmNode.Next;
            } // end of for(要素数)
            
            // 3-4)収束条件取得
            //bool bIsConvergedFlg = true;
            // 要素数分内部エレメント収束判別
            //for (int iLp = 0; iLp < iElmCnt; iLp++)
            //{   // 個数分繰り返す
            //    // 3-2-1 演算エレメント本体
            //    m_csElement = m_csElmNode.Value;    // エレメント取得
            //    // 3-2-2 個別要素の収束条件判断
            //    if (m_csElement.IsConverged(m_csConvergeCondInfo) == false)
            //    {
            //        bIsConvergedFlg = false;
            //    }
            //}

            // 3-5)グループとしての収束判別
            //if (bIsConvergedFlg == true)
            //{   // 全て収束したならば
            //    break;
            //}

            //} // end of for(∞)

            // 4) グループ内の時刻を進める <-- これば外部で行う
            //m_csCalTime += m_csDltTime;

            return lRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = IsConverged(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">（ダミー : null ）</param>
        /// <returns>=true:収束完了 =false:未収束</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool IsConverged(ref McConvergenceInfo csConvergeCondInfo)
        {
            bool bRtn = true;

            int iElmCnt = m_csElementList.Count;  // グループ内のエレメント数取得
            m_csElmNode = m_csElementList.First;
            // 要素数分内部エレメント収束判別
            for (int iLp = 0; iLp < iElmCnt; iLp++)
            {   // 個数分繰り返す
                // 3-2-1 演算エレメント本体
                m_csElementWork = m_csElmNode.Value;    // エレメント取得

                // 3-2-2 個別要素の収束条件判断
                if (m_csElementWork.IsConverged(ref m_csConvergeCondInfo) == false)
                {
                    bRtn = false;
                    // 全ての要素に対して　IsConverged をコールさせる為に　break させない
                }

                m_csElmNode = m_csElmNode.Next;
            }

            return bRtn;
        }
        /// <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()
        {
            // Do Nothing
            //m_csSimTime += m_csDltTime;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデルのユニーク種別を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>HySkind cskind = GetModelKind()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>モデルの種別を取得する</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override HySKind GetModelKind()
        { return McModelLibraryDefine.HYM_MODEL_TYPICAL_CONVERGENCE; }
    }
}


