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>
    /// 入力：原料（購入金）、　　　投資（投資配当）
    /// 出力、バイオ燃料（売上金）、CO2（O2使用）
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[2022/4/29][新規作成]</para>
    /// </remarks>
    public class MzHmnBiofuelFactory : MzCashflowModelElement
    {
        /// <summary> 演算データ（キャスト用） </summary>
        MzHmnBiofuelFactoryCalInfo m_csOcnDvlpCoInf = null;

        /// <summary> 捕獲した魚を買う：購買者 </summary>
        protected McPatternRdvSndTranInfoPair m_csRcvBuyFishCnnct = new McPatternRdvSndTranInfoPair();

        /// <summary>生産したバイオ燃料を売る：売者 </summary>
        protected McPatternRdvSndTranInfoPair m_csSndBioFuelCnnct = 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);

            McPatternRdvSndTranInfoPair m_csDumylCnnct = new McPatternRdvSndTranInfoPair();
            // 漁獲 原料として購入
            (m_csRcvBuyFishCnnct, m_csDumylCnnct) = this.PrepareRcvSndPattern(MzOceanBaseDefine.PRODUCT_FISH);

            // バイオ燃料 製品として出荷
            (m_csDumylCnnct, m_csSndBioFuelCnnct) = this.PrepareRcvSndPattern(MzOceanBaseDefine.PRODUCT_BIO_FUEL);

            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)
        {
            base.Initialize(ref csInitialData, lInputDataNum, ref csInputCellData);
            McInitialInfo csInDt = csInitialData as McInitialInfo;
            if (csInDt != null)
            {   // 初期化情報有り
                m_csOcnDvlpCoInf.m_dFishNowDealingChash = m_csOcnDvlpCoInf.m_dDealingChash;
                m_csOcnDvlpCoInf.m_dFishNextDealingChash = m_csOcnDvlpCoInf.m_dNextDealingChash;
            }
            return true;
        }

        /// <summary>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            base.ReceiveData();
            {
                //原料魚受信
                BuyerFishReceive();
            }
            return;
        }

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {
            if (m_ActionFlg == true)
            {
                //原料魚買い付け
                BuyerFishSend();

                SendDEBUG();
            }
            base.SendData();

            ////----- 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 BuyerFishReceive()
        {
            double dSum = 0.0;
            m_csOcnDvlpCoInf.m_Materials = 0.0;
            for (int i = 0; i < m_csRcvBuyFishCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csRcvBuyFishCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    m_csOcnDvlpCoInf.m_CatchFishMass[0] += csCell[0].m_dData[0];
                    m_csOcnDvlpCoInf.m_CatchFishMass[1] += csCell[0].m_dData[1];
                    m_csOcnDvlpCoInf.m_CatchFishMass[2] += csCell[0].m_dData[2];
                    dSum += csCell[0].m_dData[0] + 1.0E-16;
                    // 支払いの為、購入量を覚えておく
                    m_csRcvBuyFishCnnct.m_dRcvRatioData[i][0] = csCell[0].m_dData[0] + 1.0E-16;

                    m_csOcnDvlpCoInf.m_Materials += m_csOcnDvlpCoInf.m_CatchFishMass[0];
                    m_csOcnDvlpCoInf.m_Materials += m_csOcnDvlpCoInf.m_CatchFishMass[1];
                    m_csOcnDvlpCoInf.m_Materials += m_csOcnDvlpCoInf.m_CatchFishMass[2];
                    m_csOcnDvlpCoInf.m_MaterialsUnitCost = csCell[0].m_dData[3];
                    m_csOcnDvlpCoInf.m_dFishFeedCapability = csCell[0].m_dData[4];
                }
            }
            // 分配係数設定
            for (int i = 0; i < m_csRcvBuyFishCnnct.m_RcvInfNum; i++)
            {
                // 分配比計算
                m_csRcvBuyFishCnnct.m_dSendRatioData[i][0] = m_csRcvBuyFishCnnct.m_dRcvRatioData[i][0] / dSum;
            }
        }

        /// <summary>
        /// 魚代金支払い：買い手
        /// </summary>
        protected virtual void BuyerFishSend()
        {
            for (int i = 0; i < m_csRcvBuyFishCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csSndDt = m_csRcvBuyFishCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                csSndDt[0].m_dData[0] = m_csOcnDvlpCoInf.m_dFishNowDealingChash * m_csRcvBuyFishCnnct.m_dSendRatioData[i][0];
                csSndDt[0].m_dData[1] = m_csOcnDvlpCoInf.m_dFishNextDealingChash;
            }
        }

        /// <summary>
        /// バイオ燃料　代金受け取り：生産者
        /// </summary>
        protected virtual void SellerBioBuelReceive()
        {
            double dSum = 0.0;
            m_csOcnDvlpCoInf.m_Materials = 0.0;
            for (int i = 0; i < m_csSndBioFuelCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csSndBioFuelCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    if (csCell[0].m_dData[1] < 0) { csCell[0].m_dData[1] = 0; }
                    // 発注額
                    dSum += csCell[0].m_dData[0] + 1.0E-16;
                    m_csSndBioFuelCnnct.m_dRcvRatioData[i][0] = csCell[0].m_dData[0] + 1.0E-16;
                    // 現在支払われた納入金ではなく、次回購入予定である事に注意
                    if (csCell[0].m_dData[0] < 0) { csCell[0].m_dData[0] = 0; }
                    //// 収入
                    //m_csOcCashInf.m_dNowDealingChash += csCell[0].m_dData[0];
                    //// 発注額
                    //m_csOcCashInf.m_dNextDealingChash+ = csCell[0].m_dData[1];
                    m_csOcCashInf.ProductSellerReceive(csCell[0].m_dData[0], csCell[0].m_dData[1]);
                }
            }
            // 分配係数設定
            for (int i = 0; i < m_csSndBioFuelCnnct.m_RcvInfNum; i++)
            {
                // 分配比計算
                m_csSndBioFuelCnnct.m_dSendRatioData[i][0] = m_csSndBioFuelCnnct.m_dRcvRatioData[i][0] / dSum;
            }
        }

        /// <summary>
        /// バイオ燃料　出荷：生産者
        /// </summary>
        protected virtual void SellerBioBuelSend()
        {
            for (int i = 0; i < m_csSndBioFuelCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csSndDt = m_csSndBioFuelCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                csSndDt[0].m_dData[0] = m_csOcnDvlpCoInf.m_dProduct * m_csSndBioFuelCnnct.m_dSendRatioData[i][0];
                if (csSndDt[0].m_dData[0] < 0) { csSndDt[0].m_dData[0] = 0; }
                csSndDt[0].m_dData[1] = m_csOcnDvlpCoInf.m_dPrductUnitCost;
                if (csSndDt[0].m_dData[1] < 0) { csSndDt[0].m_dData[1] = 0; }
                csSndDt[0].m_dData[2] = m_csOcnDvlpCoInf.m_dFeedCapability;
                if (csSndDt[0].m_dData[2] < 0) { csSndDt[0].m_dData[2] = 0; }
            }
        }

        protected override void SendDEBUG()
        {
            for (int i = 0; i < m_csDebugSendCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csDebugSendCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csCell == null) { continue; }
                csCell[0].m_dData[0] = m_csOcCashInf.m_dProduct;
                csCell[0].m_dData[1] = m_csOcCashInf.m_Materials;
                csCell[0].m_dData[2] = m_csOcCashInf.m_HmnCO2Emission;
                csCell[0].m_dData[3] = m_csOcCashInf.m_Chash;
            }
        }

        /// <summary>
        /// 人間の行為
        /// </summary>
        /// <returns></returns>
        protected override long HumanAction()
        {
            m_csOcCashInf.m_dProduct = 0.0;
            //double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);
            //double dACT_Day = m_csOcCashInf.m_HmnActTimeSpan / (3600.0 * 24.0);

            // バイオ燃料の生産及び、バイオ燃料売り込み準備
            this.ProductBioFuel();

            // 原料：魚の発注費捻出
            // ここでは、購入量は変化しないとする
            m_csOcCashInf.m_Chash -= m_csOcnDvlpCoInf.m_dFishNowDealingChash;

            return 0;
        }

        /// <summary>
        /// バイオ燃料の生産
        /// </summary>
        protected virtual void ProductBioFuel()
        {
            double dACT_Day = m_csOcCashInf.m_HmnActTimeSpan / (3600.0 * 24.0);

            // ★受注量の再計算をしていない
            double dUsedMaterials = m_csOcCashInf.m_Materials;

            // 売り手側の計算
            m_csOcCashInf.ProductSellerCalDealling(dUsedMaterials);

            //利益や、変動コストを計算していない
            // 生産コストを引く
// ★仮
double dExpence = 0.0;
            m_csOcCashInf.CalConstCost(dACT_Day, dExpence);

            // 次の購入用準備
            m_csOcCashInf.ProductBuyerCalDealling(10);
        }

        //====================
        // その他必要なメソッド
        //====================

        /// <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_csOcnDvlpCoInf = (MzHmnBiofuelFactoryCalInfo)m_csCalInfo;

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                // 散布間隔
                this.SetHumanActionSpanTime(ref csPrptyInfo);

                double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);
                csPrptyInfo.GetInfo("m_HmnCO2EmissionDay", ref m_csOcnDvlpCoInf.m_HmnCO2EmissionDay);
                m_csOcnDvlpCoInf.m_HmnCO2EmissionDay = m_csOcnDvlpCoInf.m_HmnCO2EmissionDay * 1E3; // * dT;

            }

            return true;
        }
    }
}
