// <summary>ソースコード：フィードバック情報出力モデルクラス</summary>
// <author>CommonMP</author>

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

using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.CoreImpl;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;
using CommonMP.HYSSOP.CoreImpl.HSController;
using CommonMP.HYMCO.Interface;
using CommonMP.HYMCO.Interface.Controller;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.Interface.Model;
using CommonMP.HYMCO.CoreImpl.Data.FileIO;
using CommonMP.HYMCO.CoreImpl.Data.StructInfo;
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreOption.McSTGSystemBase;

namespace CommonMP.HYMCO.AddInSysOptions.SampleFloodPrediction
{
    /// <summary><para>class outline:</para>
    /// <para>フィードバック情報出力モデルクラス</para>
    /// </summary>
    /// <remarks>
    /// <para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2011/10/01][新規作成]</para>
    /// </remarks>
    public class SampleSTGFeedbackModel : McSTGFeedbackModelBase
    {
        SampleSTGFeedbackCalInf m_fdInf = null;

        /// <summary><para>method outline:</para>
        /// <para>入力側の接続情報チェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = ReceiveConnectionCheck(ref csErrorInf)</para>
        /// </example>
        /// <param name="csErrorInf">エラー出力</param>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <returns>=true:正常、=false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>受信するデータが自モデルが期待している情報か否かをチェックする</para>
        /// </remarks>
        protected override bool ReceiveConnectionCheck(ref McStructErrorInfo csErrorInf, long lInputDataNum, McReceiveCellDataIF[] csInputCellData)
        {
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>フィードバック情報を初期化する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>InitializeFeedbackData(ref csInitialData,lInputDataNum,ref csInputCellData, ref csFeedbackData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <param name="csFeedbackData">フィードバック情報</param>
        /// <returns>true:正常、false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool InitializeFeedbackData(ref McPropertyInfoRoot csInitialData, long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData, ref McSTGSysFeedbackDataBase csFeedbackData)
        {
            //現時刻よりも計算時間が後になった場合：True
            for (long lP = 0; lP < 5; lP++)
            {
                m_fdInf.m_bNowTime_after_cal[lP] = false;
            }
            m_fdInf.m_bNowTime_after_obs = false;
            
            SampleFloodPrdctFeedbakData csFBDt = csFeedbackData as SampleFloodPrdctFeedbakData;
            csFBDt.SetObservedData(0.0);
            for (long lP = 0; lP < 5; lP++)
            {
                csFBDt.SetSimuData(0.0,lP);
            }

            return true;
        }

        /// <summary><para>method outline:</para>
        /// <para>入力値を元にフィードバック情報を書き込む</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = WriteToFeedbackData(lInputDataNum, ref csInputCellData,ref csFeedbackData)</para>
        /// </example>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <param name="csFeedbackData">フィードバック書き込み情報</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override long WriteToFeedbackData(long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData, ref McSTGSysFeedbackDataBase csFeedbackData)
        {
            SampleFloodPrdctFeedbakData csFdBkDt = csFeedbackData as SampleFloodPrdctFeedbakData;

            HySCellData csCell = null;
            for (long lLp = 0; lLp < lInputDataNum; lLp++)
            {// 出力する伝送データ数分繰り返します。
                HySID csInputPtnID = csInputCellData[lLp].GetReceivePatternID();
                if (csInputPtnID.Equals(SampleFloodPrdctSysDefine.IN_PATTERN_OBSERVED))
                {
                    if (!m_fdInf.m_bNowTime_after_obs && m_csSimTime.After(m_fdInf.m_csNowTime))
                    {
                        //以降この分岐に入らないようにする。
                        m_fdInf.m_bNowTime_after_obs = true;
                        //時間の確認
                        string aaa = HySCalendar.ToString(m_csSimTime, HySCalendar.FORMAT.lSW_YEAR);
                        //データの抜き出し
                        csCell = csInputCellData[lLp].GetInterpolatedCell(0); // セル配列の０番目のセルを取得
                        double dQ = csInputCellData[lLp].Data(csCell, 0);   // セル内の流量値を取得
                        // フィードバック情報を書き込む
                        csFdBkDt.SetObservedData(dQ);
                    }
                }
                else
                {
                    long Ptn_Num = Convert.ToInt32(csInputPtnID.ToString().Substring(16, 2)) - 1; //-1でインデックスに変換
                    if (!m_fdInf.m_bNowTime_after_cal[Ptn_Num] && m_csSimTime.After(m_fdInf.m_csNowTime))
                    {
                        //以降この分岐に入らないようにする。
                        m_fdInf.m_bNowTime_after_cal[Ptn_Num] = true;
                        //時間の確認
                        string aaa = HySCalendar.ToString(m_csSimTime, HySCalendar.FORMAT.lSW_YEAR);
                        //データの抜き出し
                        csCell = csInputCellData[lLp].GetInterpolatedCell(0); // セル配列の０番目のセルを取得
                        double dQ = csInputCellData[lLp].Data(csCell, 0);   // セル内の流量値を取得
                        // フィードバック情報を書き込む
                        csFdBkDt.SetSimuData(dQ, Ptn_Num);
                    }
                }
            }

            return 0;
        }

        /// <summary><para>method outline:</para>
        /// <para>プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetProperty(csCellMdlPropertyInfo)</para>
        /// </example>
        /// <param name="csCellMdlPropertyInfo">セル型プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool SetProperty(McCellModelPropertyIF csCellMdlPropertyInfo)
        {
            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                m_fdInf = (SampleSTGFeedbackCalInf) m_csCalInfo;
                
                // 演算ステップ時刻設定
                this.m_csDltTime = new HySTime(csPrptyInfo.GetStepTime());

                string NowTime = null;
                // 各種係数設定
                csPrptyInfo.GetInfo("m_sNowTime", ref NowTime);

                m_fdInf.m_csNowTime = HySCalendar.CreateTime(NowTime);
            }
            return true;
        }
        /// <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>
        protected override bool ReadyCalculation(ref McSTGSysFeedbackDataBase csFeedbackData)
        {
            //現時刻よりも計算時間が後になった場合：True
            for (long lP = 0; lP < 5; lP++)
            {
                m_fdInf.m_bNowTime_after_cal[lP] = false;
            }
            m_fdInf.m_bNowTime_after_obs = false;

            SampleFloodPrdctFeedbakData csMyFeedbackData = csFeedbackData as SampleFloodPrdctFeedbakData;
            csMyFeedbackData.SetCalStartTime(m_csSimTime);
            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>
        protected override bool CompleteCalculation(ref McSTGSysFeedbackDataBase csFeedbackData)
        {
            SampleFloodPrdctFeedbakData csFdbkDt = csFeedbackData as SampleFloodPrdctFeedbakData;
            csFdbkDt.SetCalStopTime(m_csSimTime);

            //データ格納用
            double[] dSimData = new double[5];
            double[] dWeight = new double[5];
            double dObservedData = 0.0D;
            //重み補正前
            double[] dWeight_BeforeCorrect = new double[5];
            double forSum = 0.0D;
            //重み補正後
            double[] dWeight_AfterCorrect = new double[5];
            //観測値の取得
            dObservedData = csFdbkDt.GetObservedData();
            for (long lP = 0; lP < 5; lP++)
            {
                //計算値の取得
                dSimData[lP] = csFdbkDt.GetSimuData(lP);
                //重みの取得
                dWeight[lP] = csFdbkDt.GetWeight(lP);
                //重み補正前の計算
                if ((dSimData[lP] - dObservedData) == 0.0D)
                {
                    dWeight_BeforeCorrect[lP] = 100.0D;
                }
                else
                {
                    dWeight_BeforeCorrect[lP] = 1.0D / (Math.Abs(dSimData[lP] - dObservedData) / dObservedData) * dWeight[lP];
                }
                forSum += dWeight_BeforeCorrect[lP];
            }
            //重み補正後
            for (long lP = 0; lP < 5; lP++)
            {
                dWeight_AfterCorrect[lP] = dWeight_BeforeCorrect[lP] / forSum;
                csFdbkDt.SetWeight(dWeight_AfterCorrect[lP], lP);
            }

            return true;
        }
    }
}
