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>[2021/12/31][新規作成]</para>
    public class MzOceanHmnFishing : MzOceanHumanAct
    {
        /// <summary> 演算データ（キャスト用） </summary>
        protected MzOceanHmnFishingCalInfo m_HmnFishInf = null; // 便利の為、キャスト用に定義しておく

        //-----------------------------------------
        // 製品：購買者:使用せず
        protected McPatternRdvSndTranInfoPair m_csRcvDmyBuyFishCnnct = new McPatternRdvSndTranInfoPair();
        // 製品：生産者
        protected McPatternRdvSndTranInfoPair m_csSndSellFishCnnct = new McPatternRdvSndTranInfoPair();

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

        /// <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_csRcvDmyBuyFishCnnct, m_csSndSellFishCnnct) = this.PrepareRcvSndPattern(MzOceanBaseDefine.PRODUCT_FISH);

            //// ディバッグ用送信データ
            //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>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            // 捕食：漁獲等の取得
            ReceivePREDATION();

            // 漁獲水揚げ
            FishSellerReceive();

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

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {
            // 捕食物:植物プランクトンの捕食
            SendReqPREDATION(m_HmnFishInf.m_ReqFoodMass);

            // 漁獲水揚げ
            FishSellerSend();

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

            SendDEBUG();
            return;
        }

        /// <summary>
        /// 代金受け取り：売り手
        /// </summary>
        protected virtual void FishSellerReceive()
        {
            double dSum = 1.0E-8;
            for (int i = 0; i < m_csSndSellFishCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csSndSellFishCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    m_HmnFishInf.m_dNowDealingChash += csCell[0].m_dData[0];
                    m_HmnFishInf.m_dNextDealingChash += csCell[0].m_dData[1];
                    dSum += csCell[0].m_dData[1];
                    m_csSndSellFishCnnct.m_dRcvRatioData[i][0] = csCell[0].m_dData[1];
                    // 現在支払われた納入金ではなく、次回購入予定である事に注意
                }
            }
            // 分配係数設定（現在支払われた納入金ではなく、次回購入予定である事に注意）
            for (int i = 0; i < m_csSndSellFishCnnct.m_RcvInfNum; i++)
            {
                // 分配比計算
                m_csSndSellFishCnnct.m_dSendRatioData[i][0] = m_csSndSellFishCnnct.m_dRcvRatioData[i][0] / dSum;
            }
        }

        /// <summary>
        /// 漁獲：納入
        /// </summary>
        protected virtual void FishSellerSend( )
        {
            // 資源量計算
            double dMass = 0.0;
            for( int ll=0;ll<3;ll++)
            {
                dMass += m_HmnFishInf.m_TotalFoodMass[ll];
            }

            // 予め通知された購入額に応じて納入
            for (int i = 0; i < m_csSndSellFishCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csSndDt = m_csSndSellFishCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                csSndDt[0].m_dData[0] = m_HmnFishInf.m_CatchFishMass[0] * m_csSndSellFishCnnct.m_dSendRatioData[i][0];
                csSndDt[0].m_dData[1] = m_HmnFishInf.m_CatchFishMass[1] * m_csSndSellFishCnnct.m_dSendRatioData[i][0];
                csSndDt[0].m_dData[2] = m_HmnFishInf.m_CatchFishMass[2] * m_csSndSellFishCnnct.m_dSendRatioData[i][0];
                csSndDt[0].m_dData[3] = m_HmnFishInf.m_dNowUnitCost;
                csSndDt[0].m_dData[4] = m_HmnFishInf.m_dFeedCapability;
                if (dMass * 0.001 < m_HmnFishInf.m_dFeedCapability)
                {   // 資源量が少ない時
                    csSndDt[0].m_dData[4] = dMass * 0.001;
                }
            }
        }


        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_HmnFishInf.m_CatchFishMass[0];
                csCell[0].m_dData[1] = m_HmnFishInf.m_CatchFishMass[1];
                csCell[0].m_dData[2] = m_HmnFishInf.m_CatchFishMass[2];
                csCell[0].m_dData[3] = m_HmnFishInf.m_dFeedCapability;
                csCell[0].m_dData[4] = m_HmnFishInf.m_TotalReqFishMass;
                csCell[0].m_dData[5] = m_HmnFishInf.m_dNextDealingChash;
            }
        }

        /// <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)
        {
            McInitialInfo csInDt = csInitialData as McInitialInfo;
            if (csInDt != null)
            {   // 初期化情報有り
                double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);
                // CO2排出
                m_HmnFishInf.m_HmnCO2Emission = m_HmnFishInf.m_HmnCO2EmissionDay * dT;
                m_HmnFishInf.m_HmnReqO2 = (32.0 / 44.0) * m_HmnFishInf.m_HmnCO2EmissionDay * dT;
            }
            return true;
        }


        /// <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);

            // 要求金額から、漁獲の量を算出
            //       最終的に[m2]あたりの質量に変換
            m_HmnFishInf.m_TotalReqFishMass = 10000 * (m_HmnFishInf.m_dNextDealingChash / m_HmnFishInf.m_dNowUnitCost) 
               * (1.0 / MzOceanModelElementCalInfo.m_dFace ) *  dT ;

            //--------------------------
            m_HmnFishInf.m_ReqFoodMass[0] = m_HmnFishInf.m_TotalReqFishMass * 0.4;
            m_HmnFishInf.m_ReqFoodMass[1] = m_HmnFishInf.m_TotalReqFishMass * 0.5;
            m_HmnFishInf.m_ReqFoodMass[2] = m_HmnFishInf.m_TotalReqFishMass * 0.1;
            //深層部からは、漁獲無とする
            for(int ll=3;ll< m_HmnFishInf.m_lLayerNumber;ll++)
            {
                m_HmnFishInf.m_ReqFoodMass[ll] = 0.0;
            }

            // 取れた魚の総トン数を計算
            double dSumCatch = 0.0;
            for (int ll = 0; ll < m_HmnFishInf.m_lLayerNumber; ll++)
            {
                m_HmnFishInf.m_CatchFishMass[ll] =  m_csOcnBacedlInf.m_EatenMass[ll] * 1E-6 * MzOceanModelElementCalInfo.m_dFace;
                dSumCatch += m_HmnFishInf.m_CatchFishMass[ll];
            }
            m_HmnFishInf.m_TotalReqFishMass -= dSumCatch;
            m_HmnFishInf.m_dNextDealingChash -= m_HmnFishInf.m_dNowUnitCost * dSumCatch;

            // 燃料費等の経費が考慮されていない！！

            // CO2排出  最初に決定積みの為、変動がなければ変更しない
            //m_HmnFishInf.m_HmnCO2Emission = m_HmnFishInf.m_HmnCO2EmissionDay * dT;
            //m_HmnFishInf.m_HmnReqO2 = (32.0 / 44.0) * m_HmnFishInf.m_HmnCO2EmissionDay * dT;
            m_HmnFishInf.m_HmnRcvO2 -= m_HmnFishInf.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_HmnFishInf = (MzOceanHmnFishingCalInfo)m_csCalInfo;

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

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

                csPrptyInfo.GetInfo("m_dNowUnitCost", ref m_HmnFishInf.m_dNowUnitCost);
            }
            return true;
        }
  
    }
}
