// <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.Model;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreImpl.Tool;

// ToDo namespace は　モデル開発者が変更して、ユニークな名称にして下さい
namespace CommonMP.HYMCO.OptionImpl.ModelGeneratorSample
{
    /// <summary><para>class outline:</para>
    /// <para>ソースコード：テスト用降雨発生演算モデル</para>
    /// </summary>
    /// <remarks><para>remarks:</para>
    /// <para>ディバッグテスト用のダミーデータ発生の為、物理的意味は無い</para>
    /// <para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2009/10/01][新規作成]</para>
    /// </remarks>
    public class DmyRainFallModel : McForecastModelBase
    {
        /// <summary> 演算データ（キャスト用） </summary>
        DmyRainFallCalInfo m_csMyInf = 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; // false;
            if (lInputDataNum > 0)
            {
                // エラー
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckErrorData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL,
                    Properties.Resources.STATEMENT_NO_RECEIVE_DATA );
               // csErrorInf.AddCheckErrorData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL, "Cannot receive data.");
                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;

            if (lOutputDataNum == 0)
            {
                // 警告（エラーではない）
               // ver1.5 エラートレース日本語対応
                csErrorInf.AddCheckWarningData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL,
                     Properties.Resources.STATEMENT_NO_PORT );
               // csErrorInf.AddCheckWarningData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL, "No send port.");
            }
            for (long lP = 0; lP < lOutputDataNum; lP++)
            {   // 出力側接続線数分チェックを行う
                long lD1 = 0; long lD2 = 0; long lD3 = 0; long lCellDataNum = 0;
                long lCellDim = csOutputCellData[lP].GetDimension(ref lD1, ref lD2, ref lD3, ref lCellDataNum);
                if (lCellDim == 1 && lD1 == 1)
                {   // １次元配列で１セルならば
                    if (lCellDataNum < 1)
                    {   // セル内の変数の数
                       // ver1.5 エラートレース日本語対応
                        csErrorInf.AddCheckErrorData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL,
                            Properties.Resources.STATEMENT_VAL_NUM_SHORT_S + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                       // csErrorInf.AddCheckErrorData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL,
                       //     "Variable number in the Cells is too short. (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                        bRtn = false;
                    }
                }
                else
                {
                    // エラー
                   // ver1.5 エラートレース日本語対応
                    csErrorInf.AddCheckErrorData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL,
                                            Properties.Resources.STATEMENT_UNEXPECT_DATA_TYPE_S + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                   // csErrorInf.AddCheckErrorData(this.GetID(), SampleMdlGenDefine.TEST_RAINFALL_POINT_MODEL,
                   //                         "Unexpected send data type. (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");

                    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)
        {
            McInitialInfo csInDt = csInitialData as McInitialInfo;

            DmyRainFallCalInfo.iRndSeed += 1234;
            int iTmp = (int)(HySCalendar.CreateNowTime().GetTime() / 10000.0);
            int iSeed = (int)(HySCalendar.CreateNowTime().GetTime() - iTmp * 10000) + DmyRainFallCalInfo.iRndSeed;
            m_csMyInf.m_Rnd = new Random(iSeed);

            m_csMyInf.m_iOffset = m_csMyInf.m_Rnd.Next(45)+m_csMyInf.m_Rnd.Next(135);
            m_csMyInf.m_dData = 0.0;
            m_csMyInf.m_dAcc = Math.Sin(3.14 / 180.0 * (m_csMyInf.m_iCnt + m_csMyInf.m_iOffset));
            m_csMyInf.m_dInth = m_csMyInf.m_dMax * 0.0;
            m_csMyInf.m_dMax = 9.0;
            csInDt.GetInfo("m_dMax", ref m_csMyInf.m_dMax);

            m_csMyInf.m_iOffsetLg = m_csMyInf.m_Rnd.Next(45);
            m_csMyInf.m_dDataLg = m_csMyInf.m_Rnd.Next(5);
            m_csMyInf.m_dAccLg = Math.Sin(3.14 / 180.0 * (m_csMyInf.m_iCntLg + m_csMyInf.m_iOffsetLg));
            m_csMyInf.m_dInthLg = m_csMyInf.m_dMaxLg * 0.0;
            m_csMyInf.m_dMaxLg = 4.0;
            csInDt.GetInfo("m_dMaxLg", ref m_csMyInf.m_dMaxLg);

            m_csMyInf.m_iCntOFF = 0;
            m_csMyInf.m_iOffsetOFF = m_csMyInf.m_Rnd.Next(360);
            m_csMyInf.m_dDataOFF = 0.0;
            return true;
        }
 
        //=======================
        // 演算実行処理関連メソッド
        //=======================

        /// <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)
        {
            long lRtn = 0;

            // 地点降雨データ擬似発生計算
            // 短期用
            m_csMyInf.m_dAcc = ((double)(m_csMyInf.m_Rnd.Next(1000)))/1000.0 * Math.Sin(2.0*3.14 / 180.0 * (m_csMyInf.m_iCnt + m_csMyInf.m_iOffset))+0.1;
            m_csMyInf.m_dInth += m_csMyInf.m_dAcc;
            m_csMyInf.m_dData += m_csMyInf.m_dInth;

            if (m_csMyInf.m_dData < m_csMyInf.m_dMax / 10.0)
            {
                //if (m_csTestGISInf.m_dAcc < -0.5) { m_csTestGISInf.m_dAcc = m_csTestGISInf.m_dAcc * 0.2; }  
                if (m_csMyInf.m_dData < 0.0)
                {
                    //m_csTestGISInf.m_dInth += 1.0 / ((double)m_csTestGISInf.m_Rnd.Next(1, 500));
                }
                if (m_csMyInf.m_dData < -20.0)
                {
                    m_csMyInf.m_dData = -20.0;
                }
            }
            if (m_csMyInf.m_dData > m_csMyInf.m_dMax)
            {
                m_csMyInf.m_dInth += -100.0 / ((double)m_csMyInf.m_Rnd.Next(1, 100));
                m_csMyInf.m_dData = m_csMyInf.m_dMax;
            }
            if (m_csMyInf.m_dInth > 20.0) { m_csMyInf.m_dInth = 20.0; }
            if (m_csMyInf.m_dInth < -10.0) { m_csMyInf.m_dInth = -10.0; }
            if (m_csMyInf.m_dData > 100.0) { m_csMyInf.m_dData = 100.0; }

            m_csMyInf.m_iCnt += 4;
            if (m_csMyInf.m_iCnt > 360*100) { m_csMyInf.m_iCnt = 0; }

            // 長期用
            m_csMyInf.m_dAccLg = ((double)(m_csMyInf.m_Rnd.Next(1000))) / 1000.0 * Math.Sin(2.0*3.14 / 180.0 * (m_csMyInf.m_iCntLg + m_csMyInf.m_iOffsetLg)) + 0.1;
            m_csMyInf.m_dInthLg += m_csMyInf.m_dAccLg;
            m_csMyInf.m_dDataLg += m_csMyInf.m_dInthLg;

            if (m_csMyInf.m_dDataLg < m_csMyInf.m_dMaxLg / 5.0)
            {
                //if (m_csTestGISInf.m_dAccLg < -0.5) { m_csTestGISInf.m_dAccLg = m_csTestGISInf.m_dAccLg * 0.2; }
                if (m_csMyInf.m_dDataLg < 0.0)
                {
                    //m_csTestGISInf.m_dInthLg += 1.0 / ((double)m_csTestGISInf.m_Rnd.Next(1, 50));
                }
                if (m_csMyInf.m_dDataLg < -35.0) 
                {
                    m_csMyInf.m_dDataLg = -35.0;
                }
            }
            if (m_csMyInf.m_dDataLg > m_csMyInf.m_dMaxLg)
            {
                double dlt = m_csMyInf.m_dDataLg - m_csMyInf.m_dMaxLg;
                m_csMyInf.m_dDataLg = m_csMyInf.m_dMaxLg + dlt * 25.0/((double)m_csMyInf.m_Rnd.Next(1, 200));
                m_csMyInf.m_dInthLg += -1.0 / ((double)m_csMyInf.m_Rnd.Next(1, 10));
            }
            if (m_csMyInf.m_dInthLg > 5.0) { m_csMyInf.m_dInthLg = 5.0; }
            if (m_csMyInf.m_dInthLg < -10.0) { m_csMyInf.m_dInthLg = -10.0; }
            //if (m_csTestGISInf.m_dData > 30.0) { m_csTestGISInf.m_dData = 30.0; }

            m_csMyInf.m_iCntLg += 1;
            if (m_csMyInf.m_iCntLg > 360*100) { m_csMyInf.m_iCntLg = 0; }

            m_csMyInf.m_dDataOFF = 4.0*m_csMyInf.m_dMax * (Math.Sin(0.5 * 3.14 / 180.0 * (m_csMyInf.m_iCntOFF + m_csMyInf.m_iOffsetOFF)) - 0.0);
            if (m_csMyInf.m_dDataOFF > 0.0) { m_csMyInf.m_dDataOFF = 0.0; }
            m_csMyInf.m_iCntOFF += 1;
            if (m_csMyInf.m_iCntOFF > 360*100) { m_csMyInf.m_iCntOFF = 0; }

            //McLog.DebugOut(GetSimulationTime(), GetID(), "McGISTest2DMeshDataGenerateModel", "Calculate", "out");
            return lRtn;
        }

        /// <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)
        {
            HySCellData[] csSndCellData = null;
            double dRin = 0.0;
            dRin = m_csMyInf.m_dDataLg + m_csMyInf.m_dData + m_csMyInf.m_dDataOFF;
            if (dRin > 0.0 && m_csMyInf.m_dData < -2.0)
            {
                dRin = m_csMyInf.m_dDataLg -2.0;
            }
            else if (dRin > m_csMyInf.m_dMax)
            {
                if (m_csMyInf.m_dDataLg > m_csMyInf.m_dMax)
                {
                    dRin = m_csMyInf.m_dMax + 0.5*m_csMyInf.m_dData + 0.5*m_csMyInf.m_dData* ((double)m_csMyInf.m_Rnd.Next(10))/10.0;
                }
                else
                {
                    dRin = m_csMyInf.m_dDataLg + 0.2 * m_csMyInf.m_dData + 0.8 * m_csMyInf.m_dData * ((double)m_csMyInf.m_Rnd.Next(20)) / 20.0;
                }
            }
            else if (dRin > m_csMyInf.m_dMaxLg)
            {
                if (m_csMyInf.m_dDataLg > m_csMyInf.m_dMaxLg)
                {
                    dRin = m_csMyInf.m_dMaxLg + 0.5 * m_csMyInf.m_dData + 0.5 * m_csMyInf.m_dData * ((double)m_csMyInf.m_Rnd.Next(10)) / 10.0;
                }
                else
                {
                    if (m_csMyInf.m_dDataLg > m_csMyInf.m_dMax)
                    {
                        dRin = m_csMyInf.m_dMax + 0.7 * m_csMyInf.m_dData + 0.3 * m_csMyInf.m_dData * ((double)m_csMyInf.m_Rnd.Next(20)) / 20.0;
                    }
                    else
                    {
                        dRin = m_csMyInf.m_dDataLg + 0.1 * m_csMyInf.m_dData + 0.4 * m_csMyInf.m_dData * ((double)m_csMyInf.m_Rnd.Next(20)) / 20.0;
                    }
                }
            }
            if (dRin > 100.0)
            {
                dRin = 100.0 * 0.5 + 0.5 * 20.0 / ((double)m_csMyInf.m_Rnd.Next(1,20));
            }
            if(dRin < 0.0 )
            {  
                dRin = 0.0;
            }
            for (long lP = 0; lP < m_lOutputDataNum; lP++)
            {
                csSndCellData = csOutputCellData[lP].PrepareSendCellD1();
                csSndCellData[0].m_dData[0] = dRin;
            }
            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_csMyInf = (DmyRainFallCalInfo)m_csCalInfo;

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

                bRtn = true;

                // To Do
                // モデルの係数等、必要な情報に対して、引数で与えられたプロパティ情報の内容を読み取って、設定します。
            }
            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()
        {
            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()
        {
            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()
        {
            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(), "McGISTest2DMeshDataGenerateModel", "ChangeDeltaTimeAutomatically", "in");

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

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

    }
    //
}
