// <summary>ソースコード：次元変換モデルクラス</summary>
// <author>CommonMP</author>

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

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

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

namespace CommonMP.HYMCO.OptionImpl.McDimensionConversionForDevelop   
{
    /// <summary><para>class outline:</para>
    /// <para>次元変換モデルクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2012/02/07][新規作成]</para>
    /// </remarks>
    public class McDimensionConversionModel : McStateCalModelBase
    {
        /// <summary> 演算データ（キャスト用） </summary>
        McDimensionConversionCalInfo m_csDCInf = 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;

            // 受信は1端子のみ限定
            if (lInputDataNum != 1)
            {
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND,
                    Properties.McDimensionConversionResources.STATEMENT_REC_PORT_ONE_PERMIT );
               // csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND,
               //     "Receive port is permitted only one.");
                bRtn = false;
                return bRtn;
            }

            HySID csInputPtnID = csInputCellData[0].GetReceivePatternID();
            McDimensionConversionDefine.DimensionType type = (McDimensionConversionDefine.DimensionType)m_csDCInf.m_lReceiveType;
            string sReceiveType = type.ToString() + "In";
            if (sReceiveType.Equals(csInputPtnID.ToString()) == false)
            {   // 受信種別がプロパティ画面から設定した種別と異なる
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND,
                    Properties.McDimensionConversionResources.STATEMENT_REC_PATTERN_DEFF_SETTING + csInputCellData[0].GetUpperElementID().ToString() + ")");
               // csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND,
               //     "Receive pattern is different from the setting." + " (receive to " + csInputCellData[0].GetUpperElementID().ToString() + ")");
                bRtn = false;
            }

            // 1次元時系列・2次元時系列の場合は、指定したデータ位置がセル数を上回っていないかチェック
            long lD1 = 0;   // 1次元セル配列数
            long lD2 = 0;   // 2次元セル配列数
            long lD3 = 0;   // 3次元セル配列数
            long lCellDataNum = 0;  // 次元数
            long lCellDim = csInputCellData[0].GetDimension(ref lD1, ref lD2, ref lD3, ref lCellDataNum);
            // ver1.5 エラートレース日本語対応
            string sMessage = Properties.McDimensionConversionResources.STATEMENT_VAR_NUM_GREEAT_CELL_R 
                  + csInputCellData[0].GetUpperElementID().ToString() + ")";
           // string sMessage = "Variable number in the Cells must be greater than the setting."
           //                 + " (receive to " + csInputCellData[0].GetUpperElementID().ToString() + ")";
            if ((csInputPtnID.Equals(McDimensionConversionDefine.IN_PATTERN_SINGLE_CELL_SERIAL) == false)
                && (lCellDim > 0))
            {
                if (lD1 - 1 < m_csDCInf.m_lReceiveDataPosDim1)
                {
                    csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND, sMessage);
                    bRtn = false;
                }
            }

            if (lCellDim > 1)
            {
                if (lD2 - 1 < m_csDCInf.m_lReceiveDataPosDim2)
                {
                    csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND, sMessage);
                    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;
            for (long lLp = 0; lLp < lOutputDataNum; lLp++)
            {   // 出力する伝送データ数分繰り返します。
                HySID csOutputPtnID = csOutputCellData[lLp].GetSendPatternID();
                McDimensionConversionDefine.DimensionType type = (McDimensionConversionDefine.DimensionType)m_csDCInf.m_lSendType;
                string sSendType = type.ToString() + "Out";

                // 送信種別がプロパティ画面から設定した種別と異なる
                if (sSendType.Equals(csOutputPtnID.ToString()) == false)
                {
                   // ver1.5 エラートレース日本語対応
                    csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND,
                         Properties.McDimensionConversionResources.STATEMENT_SND_PATTERN_DEFF_SETTING + csOutputCellData[lLp].GetLowerElementID().ToString() + ")");
                   // csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND,
                   //     "Send pattern is different from the setting." + " (send to " + csOutputCellData[lLp].GetLowerElementID().ToString() + ")");
                    bRtn = false;
                }

                // 1次元時系列・2次元時系列の場合は、指定したデータ位置がセル数を上回っていないかチェック
                long lD1 = 0;   // 1次元セル配列数
                long lD2 = 0;   // 2次元セル配列数
                long lD3 = 0;   // 3次元セル配列数
                long lCellDataNum = 0;  // 次元数
                long lCellDim = csOutputCellData[lLp].GetDimension(ref lD1, ref lD2, ref lD3, ref lCellDataNum);
                // ver1.5 エラートレース日本語対応
                string sMessage = Properties.McDimensionConversionResources.STATEMENT_VAR_NUM_GREEAT_CELL_S 
                    + csOutputCellData[lLp].GetLowerElementID().ToString() + ")";
               // string sMessage = "Variable number in the Cells must be greater than the setting."
               //                    + " (send to " + csOutputCellData[lLp].GetLowerElementID().ToString() + ")";
                if ((csOutputPtnID.Equals(McDimensionConversionDefine.OUT_PATTERN_SINGLE_CELL_SERIAL) == false) 
                    && (lCellDim > 0))
                {
                    if (lD1 - 1 < m_csDCInf.m_lSendDataPosDim1)
                    {
                        csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND, sMessage);
                        bRtn = false;
                    }
                }

                if (lCellDim > 1)
                {
                    if (lD2 - 1 < m_csDCInf.m_lSendDataPosDim2)
                    {
                        csErrorInf.AddCheckErrorData(this.GetID(), McDimensionConversionDefine.DIMENSION_CONVERSION_KIND, sMessage);
                        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)
        {
            bool bRtn = false;
            // 引数で与えられたデータを　キャストしています。
            McInitialInfo csInDt = csInitialData as McInitialInfo;

            if (csInDt != null)
            {
                bRtn = true;
                // To Do
                // 演算データ等で初期化が必要な情報に対して、引数で与えられた初期化情報の内容を読み取って、設定します。
            }
            return bRtn;
        }

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

        /// <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)
        {
            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "Calculate", "in");
            HySCellData csCell = null;
            HySCellData[] csD1RcvCellData = null;
            HySCellData[,] csD2RcvCellData = null;

            // 入力データを取得
            for (long lLp = 0; lLp < lInputDataNum; lLp++)
            {
                HySID csInputPtnID = csInputCellData[lLp].GetReceivePatternID();
                if (csInputPtnID.Equals(McDimensionConversionDefine.IN_PATTERN_SINGLE_CELL_SERIAL) == true)
                {   // ポイント時系列
                    csCell = csInputCellData[lLp].GetInterpolatedCell(0);
                    m_csDCInf.m_dData = csInputCellData[lLp].Data(csCell, 0);
                }
                else if (csInputPtnID.Equals(McDimensionConversionDefine.IN_PATTERN_D1_CELL_SERIAL) == true)
                {   // 1次元時系列
                    csD1RcvCellData = csInputCellData[lLp].GetInterpolatedCellD1();
                    m_csDCInf.m_dData = csInputCellData[lLp].Data(csD1RcvCellData[m_csDCInf.m_lReceiveDataPosDim1], 0);
                }
                else if (csInputPtnID.Equals(McDimensionConversionDefine.IN_PATTERN_D2_CELL_SERIAL) == true)
                {   // 2次元時系列
                    csD2RcvCellData = csInputCellData[lLp].GetInterpolatedCellD2();
                    m_csDCInf.m_dData
                        = csInputCellData[lLp].Data(csD2RcvCellData[m_csDCInf.m_lReceiveDataPosDim1, m_csDCInf.m_lReceiveDataPosDim2], 0);
                }
            }

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "Calculate", "out");
            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)
        {
            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "DataFusion", "in");
            HySCellData[] csSndCellData = null;
            HySCellData[,] csSndCellData2 = null;

            for (long lLp = 0; lLp < lOutputDataNum; lLp++)
            {   // 出力する伝送データ数分繰り返します。
                HySID csOutputPtnID = csOutputCellData[lLp].GetSendPatternID();
                if (csOutputPtnID.Equals(McDimensionConversionDefine.OUT_PATTERN_SINGLE_CELL_SERIAL) == true)
                {   // ポイント時系列
                    csSndCellData = csOutputCellData[lLp].PrepareSendCellD1();
                    csSndCellData[0].m_dData[0] = m_csDCInf.m_dData;
                }
                else if (csOutputPtnID.Equals(McDimensionConversionDefine.OUT_PATTERN_D1_CELL_SERIAL) == true)
                {   // 1次元時系列
                    csSndCellData = csOutputCellData[lLp].PrepareSendCellD1();
                    csSndCellData[m_csDCInf.m_lSendDataPosDim1].m_dData[0] = m_csDCInf.m_dData;
                }
                else if (csOutputPtnID.Equals(McDimensionConversionDefine.OUT_PATTERN_D2_CELL_SERIAL) == true)
                {   // 2次元時系列
                    csSndCellData2 = csOutputCellData[lLp].PrepareSendCellD2();
                    csSndCellData2[m_csDCInf.m_lSendDataPosDim1, m_csDCInf.m_lSendDataPosDim2].m_dData[0] = m_csDCInf.m_dData;
                }
            }

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "DataFusion", "out");
            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)
        {
            bool bRtn = false;
            // 使用しやすいようにキャストしておく
            m_csDCInf = (McDimensionConversionCalInfo)m_csCalInfo;

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                // 演算ステップ時刻設定
                this.m_csDltTime = new HySTime(csPrptyInfo.GetStepTime());
                csPrptyInfo.GetInfo("m_lReceiveType", ref m_csDCInf.m_lReceiveType);
                csPrptyInfo.GetInfo("m_lReceiveDataPosDim1", ref m_csDCInf.m_lReceiveDataPosDim1);
                csPrptyInfo.GetInfo("m_lReceiveDataPosDim2", ref m_csDCInf.m_lReceiveDataPosDim2);

                csPrptyInfo.GetInfo("m_lSendType", ref m_csDCInf.m_lSendType);
                csPrptyInfo.GetInfo("m_lSendDataPosDim1", ref m_csDCInf.m_lSendDataPosDim1);
                csPrptyInfo.GetInfo("m_lSendDataPosDim2", ref m_csDCInf.m_lSendDataPosDim2);

                bRtn = true;
            }
            return bRtn;
        }

        /// <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()
        {
            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "ReadyCalculation", "in");

            // ToDo
            // 計算開始の　最初に１回だけコールされるメソッドです。不要ならば、本メソッドをオーバーライドする必要はありません。
            // （メソッド自身を削除してください）

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "ReadyCalculation", "out");
            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()
        {
            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "SuspendCalculation", "in");

            // ToDo
            // オペレーター操作等により計算中断時に　コールされるメソッドです。不要ならば、本メソッドをオーバーライドする必要はありません。
            // （メソッド自身を削除してください）

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "SuspendCalculation", "out");
            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()
        {
            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "CompleteCalculation", "in");

            // ToDo
            // 計算終了時　最後の最初に１回だけコールされるメソッドです。不要ならば、本メソッドをオーバーライドする必要はありません。
            // （メソッド自身を削除してください）

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "CompleteCalculation", "out");
            return true;
        }

        /// <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()
        {
            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "ChangeDeltaTimeAutomatically", "in");

            // ToDo
            // 演算中条件によって　自身のδTを(this.m_csDltTime) を変更するメソッドです。
            // 不要ならば、本メソッドをオーバーライドする必要はありません。（メソッド自身を削除してください）

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McDimensionConversionModel", "ChangeDeltaTimeAutomatically", "out");
        }
    }
}
