using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


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

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

using CommonMP.HYMCO.CoreOptionl.HymcoExpansionModel;

using CommonMP.HYMCO._SYSTEM_;

namespace CommonMP.HYMCO.Ocean.McOceanBaseModel
{
    /// <summary><para>class outline:</para>
    /// <para> 分岐・合流 </para>
    /// </summary>
    /// <remarks>
    /// <para>history:</para>
    /// <para>
    /// [2022/04/30][メソッド追加]
    /// </para>
    /// <para>remarks:</para>
    /// <para> 補間処理付き </para>
    /// </remarks>
    public class MzCmnBranchConfluentModel : MzOceanModelElement // MoCashflowModelElement
    {
        /// <summary> 演算データ（キャスト用） </summary>
        protected MzCmnBranchConfluentCalInfo m_csOcCmnInf = null; // 便利の為、キャスト用に定義しておく

        //-----------------------------------------
        // 
        protected McPatternRdvSndTranInfoPair m_csRcvCmnINCnnct = new McPatternRdvSndTranInfoPair();
        //protected McPatternRdvSndTranInfoPair m_csSndCmnINCnnct = new McPatternRdvSndTranInfoPair();
        // 
        //protected McPatternRdvSndTranInfoPair m_csRcvCmnOUTCnnct = new McPatternRdvSndTranInfoPair();
        protected McPatternRdvSndTranInfoPair m_csSndCmnOUTCnnct = new McPatternRdvSndTranInfoPair();


        //McPatternRdvSndTranInfoPair csRcvRtn = new McPatternRdvSndTranInfoPair();
        //McPatternRdvSndTranInfoPair csSndRtn = new McPatternRdvSndTranInfoPair();
        List<McReceiveCellDataIF> csRcvIFListD = new List<McReceiveCellDataIF>();
        List<McSendCellDataIF> csSndIFListD = new List<McSendCellDataIF>();
        List<McReceiveCellDataIF> csRcvIFListU = new List<McReceiveCellDataIF>();
        List<McSendCellDataIF> csSndIFListU = new List<McSendCellDataIF>();

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

        /// <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 CheckReceiveDataConnection(ref McStructErrorInfo csErrorInf, long lInputDataNum, McReceiveCellDataIF[] csInputCellData)
        {
            bool bRtn = true;
            csRcvIFListD.Clear();
            csSndIFListD.Clear();
            csRcvIFListU.Clear();
            csSndIFListU.Clear();
            //-------------------------
            McPatternRdvSndTranInfoPair m_csDmy = new McPatternRdvSndTranInfoPair();
            (m_csRcvCmnINCnnct, m_csDmy) = this.PrepareRcvSndPattern(MzOceanBaseDefine.COMMON_DATA);

            for (int i = 0; i < lInputDataNum; i++)
            {
                if (MzOceanBaseDefine.F_COMMON_DATA.Equals(csInputCellData[i].GetReceiveTranInfoPattern().GetPatternID()) == true)
                {
                    csRcvIFListD.Add(csInputCellData[i]);
                }
                else if (MzOceanBaseDefine.B_COMMON_DATA.Equals(csInputCellData[i].GetReceiveTranInfoPattern().GetPatternID()) == true)
                {
                    csRcvIFListU.Add(csInputCellData[i]);
                }
            }

            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>出力側の接続情報チェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = CheckSendDataConnection(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 CheckSendDataConnection(ref McStructErrorInfo csErrorInf, long lOutputDataNum, McSendCellDataIF[] csOutputCellData)
        {
            bool bRtn = true;
            //-------------------------
            for (int i = 0; i < lOutputDataNum; i++)
            {
                if (MzOceanBaseDefine.B_COMMON_DATA.Equals(csOutputCellData[i].GetID()) == true)
                {
                    csSndIFListD.Add(csOutputCellData[i]);
                }
                else if (MzOceanBaseDefine.F_COMMON_DATA.Equals(csOutputCellData[i].GetID()) == true)
                {
                    csSndIFListU.Add(csOutputCellData[i]);
                }
            }

            m_csRcvCmnINCnnct.m_RcvInfNum = csRcvIFListD.Count;
            m_csRcvCmnINCnnct.m_csRcvInfArry = csRcvIFListD.ToArray();
            m_csRcvCmnINCnnct.m_dRcvRatioData = new double[m_csRcvCmnINCnnct.m_RcvInfNum][];
            m_csRcvCmnINCnnct.m_csSndInfArry = csSndIFListD.ToArray();
            m_csRcvCmnINCnnct.m_dSendRatioData = new double[m_csRcvCmnINCnnct.m_RcvInfNum][];

            m_csSndCmnOUTCnnct.m_RcvInfNum = csRcvIFListU.Count;
            m_csSndCmnOUTCnnct.m_csRcvInfArry = csRcvIFListU.ToArray();
            m_csSndCmnOUTCnnct.m_dRcvRatioData = new double[m_csSndCmnOUTCnnct.m_RcvInfNum][];
            m_csSndCmnOUTCnnct.m_csSndInfArry = csSndIFListU.ToArray();
            m_csSndCmnOUTCnnct.m_dSendRatioData = new double[m_csSndCmnOUTCnnct.m_RcvInfNum][];

            for (int z = 0; z < m_csRcvCmnINCnnct.m_RcvInfNum; z++)
            {
                m_csRcvCmnINCnnct.m_dRcvRatioData[z] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                m_csRcvCmnINCnnct.m_dSendRatioData[z] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                for (int j = 0; j < m_csOcnBacedlInf.m_lLayerNumber; j++)
                {
                    m_csRcvCmnINCnnct.m_dRcvRatioData[z][j] = 0.0;
                    m_csRcvCmnINCnnct.m_dSendRatioData[z][j] = 1.0;
                }
            }
            for (int z = 0; z < m_csSndCmnOUTCnnct.m_RcvInfNum; z++)
            {
                m_csSndCmnOUTCnnct.m_dRcvRatioData[z] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                m_csSndCmnOUTCnnct.m_dSendRatioData[z] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                for (int j = 0; j < m_csOcnBacedlInf.m_lLayerNumber; j++)
                {
                    m_csSndCmnOUTCnnct.m_dRcvRatioData[z][j] = 0.0;
                    m_csSndCmnOUTCnnct.m_dSendRatioData[z][j] = 1.0;
                }
            }

            return bRtn;
        }

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

        /// <summary>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            ReceiveIN();
            ReceiveOUT();
            return;
        }

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {
            SendIN();
            SendOUT();
        }

        /// <summary>
        /// 各送り元から受信
        /// </summary>
        protected virtual void ReceiveIN()
        {
            //------------------------
            for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
            {
                for (int id = 0; id < 8; id++)
                {
                    m_csOcCmnInf.m_SumRsvINdata[ll][id] = 0.0;
                }
            }
            for (int i = 0; i < m_csRcvCmnINCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csRcvCmnINCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    int dtL = csCell[0].m_dData.Length;
                    if (dtL > 8) { dtL = 8; }
                    for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
                    {
                        for (int id = 0; id < dtL; id++)
                        {
                            m_csOcCmnInf.m_SumRsvINdata[ll][id] += csCell[ll].m_dData[id];
                        }
                        m_csRcvCmnINCnnct.m_dRcvRatioData[i][ll] = csCell[0].m_dData[0];
                    }
                }
            }
            for (int i = 0; i < m_csRcvCmnINCnnct.m_RcvInfNum; i++)
            {
                for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
                {
                    m_csRcvCmnINCnnct.m_dSendRatioData[i][ll] = m_csRcvCmnINCnnct.m_dRcvRatioData[i][ll] / (m_csOcCmnInf.m_SumRsvINdata[ll][0] + 1E-9);
                }
            }
        }

        /// <summary>
        /// 各送り元へ送信
        /// </summary>
        protected virtual void SendIN()
        {
            HySCellData[] csSndDt = null;

            for (int i = 0; i < m_csRcvCmnINCnnct.m_RcvInfNum; i++)
            {
                csSndDt = m_csRcvCmnINCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }

                int dtL = csSndDt[0].m_dData.Length;
                if (dtL > 8) { dtL = 8; }
                for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
                {
                    
                    for (int id = 0; id < dtL; id++)
                    {
                        csSndDt[ll].m_dData[id] = m_csRcvCmnINCnnct.m_dSendRatioData[i][ll] * m_csOcCmnInf.m_SumSndINdata[ll][id];
                    }
                }
            }
        }

        /// <summary>
        /// 各送り先から受信
        /// </summary>
        protected virtual void ReceiveOUT()
        {
            //------------------------
            for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
            {
                for (int id = 0; id < 8; id++)
                {
                    m_csOcCmnInf.m_SumRsvOUTdata[ll][id] = 0.0;
                }
            }
            for (int i = 0; i < m_csSndCmnOUTCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csSndCmnOUTCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    int dtL = csCell[0].m_dData.Length;
                    if( dtL >8) { dtL = 8; }
                    for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
                    {
                        for (int id = 0; id < dtL; id++)
                        {
                            m_csOcCmnInf.m_SumRsvOUTdata[ll][id] += csCell[0].m_dData[id];
                        }
                        m_csSndCmnOUTCnnct.m_dRcvRatioData[i][ll] = csCell[0].m_dData[0];
                    }
                }
            }
            for (int i = 0; i < m_csSndCmnOUTCnnct.m_RcvInfNum; i++)
            {
                for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
                {
                    m_csSndCmnOUTCnnct.m_dSendRatioData[i][ll] = m_csSndCmnOUTCnnct.m_dRcvRatioData[i][ll]/(m_csOcCmnInf.m_SumRsvOUTdata[ll][0]+1E-9);
                }
            }
        }

        /// <summary>
        /// 各送り先へ送信
        /// </summary>
        protected virtual void SendOUT()
        {
            HySCellData[] csSndDt = null;

            for (int i = 0; i < m_csSndCmnOUTCnnct.m_RcvInfNum; i++)
            {
                csSndDt = m_csSndCmnOUTCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }

                int dtL = csSndDt[0].m_dData.Length;
                if (dtL > 8) { dtL = 8; }
                for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
                {
                    for (int id = 0; id < dtL; id++)
                    {
                        csSndDt[ll].m_dData[id] = m_csSndCmnOUTCnnct.m_dSendRatioData[i][ll]* m_csOcCmnInf.m_SumSndOUTdata[ll][id];
                    }
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = Calculate(ref csInputDataList)</para>
        /// </example>
        /// <param name="lOnlyReceveDataNum">入力だけの情報数</param>
        /// <param name="csOnlyReceiveCellData">入力だけの情報配列</param>
        /// <param name="lOnlySendDataNum">出力だけの情報数</param>
        /// <param name="csOnlySelDataCellData">出力だけの情報配列</param>
        /// <param name="lRcvSndDataNum">相互接続報数</param>
        /// <param name="csReceiveCellData">相互接続入力側情報配列</param>
        /// <param name="csSelDataCellData">相互接続出力側情報配列</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>派生クラス側で必ずオーバライドする必要がある</para>
        /// </remarks>
        protected override long Calculate(
            long lOnlyReceveDataNum, ref McReceiveOnlyTranInfo[] csOnlyReceiveCellData,
            long lOnlySendDataNum, ref McSendOnlyTranInfo[] csOnlySelDataCellData,
            long lRcvSndDataNum, ref McRdvSndTranInfoPair[] csRcvSndCelDataCellData
            )
        {
            for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
            {
                for (int id = 0; id < 8; id++)
                {
                    m_csOcCmnInf.m_SumSndOUTdata[ll][id] = m_csOcCmnInf.m_SumRsvINdata[ll][id];
                    m_csOcCmnInf.m_SumSndINdata[ll][id] = m_csOcCmnInf.m_SumRsvOUTdata[ll][id];
                }
            }
            return 0;
        }
        //protected override long HumanAction()
        //{
        //    for (int ll = 0; ll < m_csOcCmnInf.m_lLayerNumber; ll++)
        //    {
        //        for (int id = 0; id < 8; id++)
        //        {
        //            m_csOcCmnInf.m_SumSndOUTdata[ll][id] = m_csOcCmnInf.m_SumRsvINdata[ll][id];
        //            m_csOcCmnInf.m_SumSndINdata[ll][id] = m_csOcCmnInf.m_SumRsvOUTdata[ll][id];
        //        }
        //    }
        //    return 0;
        //}

        public override bool SetProperty(McCellModelPropertyIF csCellMdlPropertyInfo)
        {
            bool bRtn = base.SetProperty(csCellMdlPropertyInfo);

            // 使用しやすいようにキャストしておく
            m_csOcCmnInf = (MzCmnBranchConfluentCalInfo)m_csCalInfo;

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                //long lLayerNumber = 7;
                //csPrptyInfo.GetInfo("m_lLayerNumber", ref lLayerNumber);
                //m_csOcCmnInf.SetLayerNum(lLayerNumber);
            }

            return true;
        }
    }
}
