
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreImpl.Tool;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.Interface.Model;
using CommonMP.HYSSOP.CoreImpl.HSData;

namespace CommonMPIntroduction
{
	/// <summary><para>class outline:</para>
	/// <para>線形貯水池モデルのクラス宣言</para>
	/// </summary>
	public class LinearReservoirModel : McForecastModelBase
	{
		/// <summary> 演算データ（キャスト用） </summary>
		LinearReservoirModelCalInfo mInf = 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)
		{
			bool bRtn = true;

			if (lInputDataNum == 0)
			{
				// 入力対象が無い場合 エラーを返す
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckErrorData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND, 
                     Properties.Resources.STATEMENT_NO_REC_DATA );
               // csErrorInf.AddCheckErrorData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND, "No receive data.");
                bRtn = false;
			}
			else if (lInputDataNum > 0)
			{
				// 入力側の接続の数だけ繰り返す
				for (long lP = 0; lP < lInputDataNum; lP++)
				{
                    if (csInputCellData[lP].GetReceivePatternID().Equals(LinearReservoirModelDefine.IN_PATTERN_TOP) == false)
					{
						// 予期しない接続が行われている場合
                       // ver1.5 エラートレース日本語対応
                        csErrorInf.AddCheckErrorData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND,
							 Properties.Resources.STATEMENT_UNEXPECT_REC_DATA_TYPE_R + csInputCellData[lP].GetUpperElementID().ToString() + ")");
                       // csErrorInf.AddCheckErrorData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND,
                       //     "Unexpected receive data type. (Received from " + csInputCellData[lP].GetUpperElementID().ToString() + ")");
                        bRtn = false;
					}
				}
			}

			return bRtn;
		}

		/// <summary><para>method outline:</para>
		/// <para>出力側の接続情報をチェックする</para>
		/// </summary>
		/// <example><para>usage:</para>
		/// <para>bool bRtn = SendConnectionCheck(ref csErrorInf)</para>
		/// </example>
		/// <param name="csErrorInf">エラー出力</param>
		/// <param name="lOutputDataNum">出力情報数</param>
		/// <param name="csOutputCellData">出力情報配列</param>
		/// <returns>=true:正常、=false:異常</returns>
		/// <exception cref="">無し</exception>
		/// <remarks><para>remarks:</para>
		/// <para>送信端子に設定されている伝送データが自モデルが期待している情報か否かをチェックする</para>
		/// </remarks>
		protected override bool SendConnectionCheck(ref McStructErrorInfo csErrorInf, long lOutputDataNum, McSendCellDataIF[] csOutputCellData)
		{
			bool bRtn = true;

			if (lOutputDataNum == 0)
			{
				// 出力対象がない場合は警告（エラーではない）
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckWarningData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND, 
                     Properties.Resources.STATEMENT_NO_SND_PORT );
               // csErrorInf.AddCheckWarningData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND, "No send port.");
            }
			else if (lOutputDataNum > 0)
			{
				// 出力側の接続の数だけ繰り返す
				for (long lP = 0; lP < lOutputDataNum; lP++)
				{
                    if (csOutputCellData[lP].GetSendPatternID().Equals(LinearReservoirModelDefine.OUT_PATTERN_BOTTOM) == false)
					{
						// 予期しない接続が行われている場合
                       // ver1.5 エラートレース日本語対応
                        csErrorInf.AddCheckErrorData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND,
							 Properties.Resources.STATEMENT_UNEXPECT_SND_DATA_TYPE_S + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                       // csErrorInf.AddCheckErrorData(this.GetID(), LinearReservoirModelDefine.MODEL_KIND,
                       //     "Unexpected send data type. (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                        bRtn = false;
					}
				}
			}

			return bRtn;
		}

		/// <summary><para>method outline:</para>
		/// <para>モデルを初期化する</para>
		/// </summary>
		/// <example><para>usage:</para>
		/// <para>Initialize(csInitialData)</para>
		/// </example>
		/// <param name="csInitialData">初期化設定情報</param>
		/// <param name="lInputDataNum">入力情報数</param>
		/// <param name="csInputCellData">演算に必要な入力情報配列</param>
		/// <returns>無し</returns>
		/// <exception cref="">無し</exception>
		/// <remarks><para>remarks:</para>
		/// <para>無し</para>
		/// </remarks>
		protected override bool Initialize(ref McPropertyInfoRoot csInitialData, long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
		{
           // ver1.5 エラートレース日本語対応
			McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "Initialize", Properties.Resources.STATEMENT_INIT );
           // McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "Initialize", "<<Init>>");
            McInitialInfo csInDt = csInitialData as McInitialInfo;
			if (csInDt != null)
			{
				// 初期値を設定する
				csInDt.GetInfo("m_storage", ref mInf.m_storage);
				mInf.m_outflow = mInf.m_storage / mInf.m_k;
			}
			return true;
		}

		/// <summary><para>method outline:</para>
		/// <para>モデルを初期化する</para>
		/// </summary>
		/// <example><para>usage:</para>
		/// <para>OnlineInitialize(csInitialData)</para>
		/// </example>
		/// <param name="csInitialData">初期化設定情報</param>
		/// <param name="lInputDataNum">入力情報数</param>
		/// <param name="csInputCellData">演算に必要な入力情報配列</param>
		/// <returns>bool</returns>
		/// <exception cref="">無し</exception>
		/// <remarks><para>remarks:</para>
		/// <para>無し</para>
		/// </remarks>
		protected override bool OnlineInitialize(ref McPropertyInfoRoot csInitialData, long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
		{
			return true;
		}
		/// <summary><para>method outline:</para>
		/// <para>モデル演算</para>
		/// </summary>
		/// <example><para>usage:</para>
		/// <para>long lRtn = Calculate(ref csInputCellData)</para>
		/// </example>
		/// <param name="lInputDataNum">入力情報数</param>
		/// <param name="csInputCellData">演算に必要な入力情報配列</param>
		/// <returns>=0:正常 -1:異常</returns>
		/// <exception cref="">無し</exception>
		/// <remarks><para>remarks:</para>
		/// <para>無し</para>
		/// </remarks>
		protected override long Calculate(long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
		{
           // ver1.5 エラートレース日本語対応
			McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "Calculate", Properties.Resources.STATEMENT_START );
           // McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "Calculate", "<<Start>>");

			double inflow1 = 0.0;
			double inflow2 = 0.0;
			HySCellData csCell = null;

			for (long lnum = 0; lnum < lInputDataNum; lnum++)
			{
				// 接続ごとに時刻 t の流入量inflow1を取得
				csInputCellData[lnum].SetCurrentTime(m_csSimTime);
				csCell = csInputCellData[lnum].GetInterpolatedCell(0);
				inflow1 += csInputCellData[lnum].Data(csCell, 0);

				// 接続ごとに時刻 t + dt の流入量inflow2を取得
				csInputCellData[lnum].SetCurrentTime(m_csSimTime + m_csDltTime);
				csCell = csInputCellData[lnum].GetInterpolatedCell(0);
				inflow2 += csInputCellData[lnum].Data(csCell, 0);
			}

			// 状態量を更新
            mInf.m_storage = (inflow1 + inflow2) / 2.0 + mInf.m_storage * (1.0 / mInf.m_dt - 1.0 / (2.0 * mInf.m_k));
            mInf.m_storage = mInf.m_storage / (1.0 / mInf.m_dt + 1.0 / (2.0 * mInf.m_k));
            mInf.m_outflow = mInf.m_storage / mInf.m_k;
            
			return 0;
		}

		/// <summary><para>method outline:</para>
		/// <para>モデル演算結果を外部のエレメントに対して公開する</para>
		/// </summary>
		/// <example><para>usage:</para>
		/// <para>long lRtn = DataFusion( lOutputDataNum, ref csOutputCellData)</para>
		/// </example>
		/// <param name="lOutputDataNum">出力情報数</param>
		/// <param name="csOutputCellData">出力情報配列</param>
		/// <returns>=0:正常 -1:異常</returns>
		/// <exception cref="">無し</exception>
		/// <remarks><para>remarks:</para>
		/// <para>無し</para>
		/// </remarks>
		protected override long DataFusion(long lOutputDataNum, ref McSendCellDataIF[] csOutputCellData)
		{
           // ver1.5 エラートレース日本語対応
			McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "DataFusion", Properties.Resources.STATEMENT_START );
           // McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "DataFusion", "<<Start>>");
            HySCellData[] csSndCellData = null;

			for (long lnum = 0; lnum < lOutputDataNum; lnum++)
			{
				csSndCellData = csOutputCellData[lnum].PrepareSendCellD1();
				csSndCellData[0].m_dData[0] = mInf.m_outflow;
                csSndCellData[0].m_dData[1] = mInf.m_storage;
            }

			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)
		{
           // ver1.5 エラートレース日本語対応
			McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "SetProperty", Properties.Resources.STATEMENT_INIT );
           // McLog.DebugOut(m_csSimTime, GetID(), GetType().ToString(), "SetProperty", "<<Init>>");

			mInf = (LinearReservoirModelCalInfo)m_csCalInfo;

			McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
			if (csPrptyInfo != null)
			{
				// 演算ステップ設定
				this.m_csDltTime = new HySTime(csPrptyInfo.GetStepTime());
				mInf.m_dt = csPrptyInfo.GetStepTime();
				
				csPrptyInfo.GetInfo("m_k", ref mInf.m_k);
			}
			return true;

		}

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