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;


namespace CommonMP.HYMCO.Ocean.McOceanBaseModel
{
    /// <summary><para>class outline:</para>
    /// <para> 海洋人工施肥作業 モデルクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[2021/12/31][新規作成]</para>
    public class MzOceanHmnFertilization : MzOceanHumanAct
    {
        /// <summary> 演算データ（キャスト用） </summary>
        protected MzOceanHmnFertilizationCalInfo m_HmnFrtInf = null; // 便利の為、キャスト用に定義しておく

        //========================================================
        //========================================================
        // 人間による施肥料 ：     McOceanBaseDefine.HUMAN_FERTILIZER_KIND  
        // 仕込み品（積み荷）
        protected McPatternRdvSndTranInfoPair m_csRcvHmnFertilizerCnnct = new McPatternRdvSndTranInfoPair();
        // 海洋散布
        protected McPatternRdvSndTranInfoPair m_csSndHmnFertilizerCnnct = new McPatternRdvSndTranInfoPair();



        //----- ワーク ------
        protected double m_WorkTime = 0.0;

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

        /// <summary><para>method outline:</para>
        /// <para>入力側の接続情報チェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = CheckReceiveDataConnection(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 = base.CheckReceiveDataConnection(ref csErrorInf, lInputDataNum, csInputCellData);

            // 仕込み品（積み荷）
            m_csRcvHmnFertilizerCnnct = this.PrepareRcvPattern(MzOceanBaseDefine.EC_HUMAN_FERTILIZER);
            // 海洋散布
            m_csSndHmnFertilizerCnnct = this.PrepareSndPattern(MzOceanBaseDefine.HUMAN_FERTILIZER);


            // CO2排出
            (m_csRcvCO2DmyCnnct, m_csSndCO2EmissionCnnct) = this.PrepareRcvSndPattern(MzOceanBaseDefine.CO2_EMISSION);
            //// ディバッグ用送信データ
            //m_csDebugSendCnnct = this.PrepareSndPattern(MzOceanBaseDefine.DEBUG_OUT);
            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 = base.CheckSendDataConnection(ref csErrorInf, lOutputDataNum, csOutputCellData);
        //    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 = base.Initialize(ref csInitialData, lInputDataNum, ref csInputCellData);
            McInitialInfo csInDt = csInitialData as McInitialInfo;
            if (csInDt != null)
            {   // 初期化情報有り
                double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);
                // CO2排出
                m_HmnActInf.m_HmnCO2Emission = m_HmnActInf.m_HmnCO2EmissionDay * dT;
                m_HmnActInf.m_HmnReqO2 = (32.0 / 44.0) * m_HmnActInf.m_HmnCO2EmissionDay * dT;
            }
            return true;
        }

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

        /// <summary>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            ClearAllCalValue();

            // 工場からの肥料受信
            ReceiveFertilize();

            // 人間行為によって消費するO2：受信
            ReceiveO2Consumption();
            return;
        }

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {           
            // 散布周期で　施肥する
            m_WorkTime += m_csDltTime.TotalSec();
            if (m_WorkTime >= m_HmnActInf.m_HmnActTimeSpan)
            {
                m_WorkTime -= m_HmnActInf.m_HmnActTimeSpan;

            SendDEBUG();
                
                // 海洋散布
                SendFertilizer();
            }

            // 人間行為によって排出するCO2：送信
            SendCO2Emission();

            ////----- Debug Check ------
            //double dChk = (m_DtrtsInf.d_NowTotalMass - m_DtrtsInf.d_PreTotalMass) - (m_DtrtsInf.d_TotalIN - m_DtrtsInf.d_TotalOUT);
            //McLog.DebugOut("MzOceanDetritus", "SendData", "デトリタス総量チェック:" + dChk.ToString() + " = "
            //    + (m_DtrtsInf.d_NowTotalMass - m_DtrtsInf.d_PreTotalMass).ToString() + " - " + (m_DtrtsInf.d_TotalIN - m_DtrtsInf.d_TotalOUT).ToString());
            ////------------------------
            return;
        }

        /// <summary>
        /// 工場からの肥料取得
        /// </summary>
        protected virtual void ReceiveFertilize()
        {
            double dFace = MzOceanAreaColumnModelCalInfo.m_dFace;
            double dTon2Grm = 1000.0 * 1000.0;

            for (int i = 0; i < m_csRcvHmnFertilizerCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csRcvHmnFertilizerCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    // 単位の変更
                    m_HmnFrtInf.m_N_Fertilize += csCell[0].m_dData[0] * dTon2Grm / dFace;
                    m_HmnFrtInf.m_P_Fertilize += csCell[0].m_dData[1] * dTon2Grm / dFace;
                    m_HmnFrtInf.m_IOPMass_Si += csCell[0].m_dData[2] * dTon2Grm / dFace;
                    if (csCell[0].m_dData[3] > 0)
                    {
                        m_HmnFrtInf.m_Si_Size = csCell[0].m_dData[3];
                    }
                    m_HmnFrtInf.m_IOPMass_Fe += csCell[0].m_dData[4] * dTon2Grm / dFace;
                    if (csCell[0].m_dData[5] > 0)
                    {
                        m_HmnFrtInf.m_Fe_Size = csCell[0].m_dData[5];
                    }
                }
            }  // end of for(i)
        }

        /// <summary>
        /// 肥料要素を海洋に散布
        /// </summary>
        protected virtual void SendFertilizer()
        {
            if (m_csSndHmnFertilizerCnnct.m_RcvInfNum <= 0) { return;  }

            // 送信接続数による分配
            double dK = 1.0 / m_csSndHmnFertilizerCnnct.m_RcvInfNum; 
            for (int i = 0; i < m_csSndHmnFertilizerCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csSndDt = m_csSndHmnFertilizerCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                csSndDt[0].m_dData[0] = dK * m_HmnFrtInf.m_N_Fertilize;
                csSndDt[0].m_dData[1] = dK * m_HmnFrtInf.m_P_Fertilize;
                csSndDt[0].m_dData[2] = dK * m_HmnFrtInf.m_IOPMass_Si;
                csSndDt[0].m_dData[3] = m_HmnFrtInf.m_Si_Size;
                csSndDt[0].m_dData[4] = dK * m_HmnFrtInf.m_IOPMass_Fe;
                csSndDt[0].m_dData[5] = m_HmnFrtInf.m_Fe_Size;
            }

            // 受信量のリセット
            m_HmnFrtInf.m_N_Fertilize = 0;
            m_HmnFrtInf.m_P_Fertilize = 0;
            m_HmnFrtInf.m_IOPMass_Si = 0;
            m_HmnFrtInf.m_IOPMass_Fe = 0;
        }


        protected virtual void SendDEBUG()
        {
            for (int i = 0; i < m_csDebugSendCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csDebugSendCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                csCell[0].m_dData[0] = m_HmnFrtInf.m_N_Fertilize;
                csCell[0].m_dData[1] = m_HmnFrtInf.m_P_Fertilize;
                csCell[0].m_dData[2] = m_HmnFrtInf.m_IOPMass_Si;
                csCell[0].m_dData[3] = m_HmnFrtInf.m_IOPMass_Fe;
            }
        }



        /// <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
            )
        {
            //double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);
            //MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();

            // CO2排出  最初に決定積みの為、変動がなければ変更しない
            //m_HmnFishInf.m_HmnCO2Emission = m_HmnFishInf.m_HmnCO2EmissionDay * dT;
            //m_HmnFishInf.m_HmnReqO2 = (32.0 / 44.0) * m_HmnFishInf.m_HmnCO2EmissionDay * dT;
            
            //ReceiveFertilize()ですでに、撒く肥料数は設定されている。

            m_HmnActInf.m_HmnRcvO2 -= m_HmnActInf.m_HmnReqO2;

            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)
        {
            base.SetProperty(csCellMdlPropertyInfo);

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

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);

                // 散布間隔
                this.SetHumanActionSpanTime(ref csPrptyInfo);

                // 排出量
                m_HmnFrtInf.m_HmnCO2EmissionDay = GetHumanActionCO2Emission(ref csPrptyInfo);
            }

            return true;
        }

    }
}
