// <summary>ソースコード：テストCSVファイル入力モデルクラス</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.HYSSOP.Interface.HSData;

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

namespace CommonMP.HYMCO.OptionImpl.McSampleModelForDeveloper
{
    /// <summary><para>class outline:</para>
    /// <para>テストCSVファイル入力クラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2008/10/01][新規作成]</para>
    /// </remarks>
    public class McTestINFileModel : McBasicFileInCtl //McFileInCtl
    {
        /// <summary> 内部変数 </summary>
        McTestINFileInfo m_csInFileInfo = null;//new McTestINFileInfo();

        /// <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)
            {
                // 警告（エラーではない）
                csErrorInf.AddCheckWarningData(this.GetID(), McModelSampleDefine.TEST_FILE_IN_KIND, "No send port.");
            }
            for (long lP = 0; lP < lOutputDataNum; lP++)
            {   // 出力側接続線数分チェックを行う
                if (McModelSampleDefine.IN_OUT_PATTERN_ANY_ONE.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                {   // 単独セルの出力ならば
                    m_csInFileInfo.m_lOutPutPortNum += 1;
                    if (m_csInFileInfo.m_lOutDataIdx >= m_csInFileInfo.m_lDataNum)
                    {
                        bRtn = false;
                        csErrorInf.AddCheckErrorData(this.GetID(), McModelSampleDefine.TEST_FILE_IN_KIND,
                             "OutDataIndex is larger than read data . (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                    }
                }
                else if (McModelSampleDefine.IN_OUT_PATTERN_ANY.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                {   // １次元配列セル出力ならば
                    m_csInFileInfo.m_lOutPutPortNum += 1;
                    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 (this.m_csInFileInfo.m_lDataNum >= lD1)
                    {
                        // エラー
                        bRtn = false;
                        csErrorInf.AddCheckErrorData(this.GetID(), McModelSampleDefine.TEST_FILE_IN_KIND,
                             "Cell Dimension is too short. (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                    }
                }
                else
                {
                    // エラー
                    bRtn = false;
                    csErrorInf.AddCheckErrorData(this.GetID(), McModelSampleDefine.TEST_FILE_IN_KIND,
                        "Unexpected send data type.");
                }
            }
            m_csInFileInfo.m_csLastDataOutTime = new HySTime[lOutputDataNum];

            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 = false;
            // 最初に全ての情報を読んでおく
            for (long lP = 0; lP < m_lOutputDataNum; lP++)
            {   // 出力側接続線数分チェックを行う
                m_csInFileInfo.m_csLastDataOutTime[lP] = HySTime.DEFAULT_TIME.Clone();
            }
            // CSV入力データの格納用クラス
            if (m_csInFileInfo.m_csReadCSVData == null)
            {
                m_csInFileInfo.m_csReadCSVData = new HySCSVFileData(HySCSVFileData.DATA_KIND.TIME_SERIES_DATA, m_csInFileInfo.m_lDataNum);
            }
            m_csInFileInfo.m_csReadCSVData.SetFileName(m_csInFileNameWithFullPath);
            if (0 == m_csInFileInfo.m_csReadCSVData.ReadCSVFile())
            {
                long lCellNo = m_csInFileInfo.m_csReadCSVData.GetSeriesNum();
                if( lCellNo <= this.m_csInFileInfo.m_lDataNum )
                {
                    this.m_csInFileInfo.m_lDataNum = lCellNo;
                    bRtn = true;
                }
                if (this.m_csInFileInfo.m_lOutDataIdx >= lCellNo)
                {
                    this.m_csInFileInfo.m_lOutDataIdx = lCellNo - 1;
                    bRtn = true;
                }
            }
            else
            {
                m_csInFileInfo.m_csReadCSVData = null;
            }
            
            return bRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデルを初期化する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>OnlineInitialize(csInitialData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <returns>bool</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool OnlineInitialize(ref McPropertyInfoRoot csInitialData, long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
        {
            // Do Nothing
            return true;
        }
        /// <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)
        {
            long lRtn = 0;
            long lNotSendDataNum = 0;
            HySTime csCursTm = HySTime.DEFAULT_TIME.Clone();
            HySCellData[] csSndCellData = null;
            long lCellNo = m_csInFileInfo.m_csReadCSVData.GetSeriesNum();
            //double[] dData = new double[this.m_csInFileInfo.m_lDataNum];
            double[] dData = new double[lCellNo];
            bool bLclRtn = false;
            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);

                lNotSendDataNum=m_csInFileInfo.m_csReadCSVData.SetCursor(m_csInFileInfo.m_csLastDataOutTime[lP]); // カーソル位置を　最後に送信した時刻に合わせる
                for( long lCnt = 0;lCnt<lNotSendDataNum;lCnt++)
                {   // 送信していない分データを繰り返す
                    //bLclRtn = m_csInFileInfo.m_csReadCSVData.GetCursorTimeSeriesData(ref csCursTm, ref dData, this.m_csInFileInfo.m_lDataNum);
                    bLclRtn = m_csInFileInfo.m_csReadCSVData.GetCursorTimeSeriesData(ref csCursTm, ref dData, lCellNo);
                    if (bLclRtn == true)
                    {
                        if (csCursTm.After(this.m_csInFileInfo.m_csLastDataOutTime[lP]) == true &&
                            (this.m_csTgtTime.Before(csCursTm) == false))
                        {   // 取得時刻が　最後に送信した時刻よりも　新しく　目標時刻よりと同じまたは古ければ
                            /*
                            this.m_csInFileInfo.m_csLastDataOutTime[lP].SetTime(csCursTm); // 送信した時刻を設定する

                            csOutputCellData[lP].SetCurrentTime(csCursTm);// 送信用のレコードを設定する（時刻設定）

                            csSndCellData = csOutputCellData[lP].PrepareSendCellD1(); // 送信用情報格納セルの準備
                            csSndCellData[0].m_dData[0] = dData[0]; // データを設定

                            m_OutputCellData[lP].SendData();    //設定データの送信

                            McLog.DebugOut(csCursTm, m_csElement.GetID(), 
                                "McTestINFileModel", "DataFusion", " OutQ[" + lP.ToString() + "]=" + dData[0].ToString());
                            */
                            if (McModelSampleDefine.IN_OUT_PATTERN_ANY_ONE.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                            {   // 単独セルの出力ならば
                                this.m_csInFileInfo.m_csLastDataOutTime[lP].SetTime(csCursTm); // 送信した時刻を設定する

                                csOutputCellData[lP].SetCurrentTime(csCursTm);// 送信用のレコードを設定する（時刻設定）

                                csSndCellData = csOutputCellData[lP].PrepareSendCellD1(); // 送信用情報格納セルの準備
                                csSndCellData[0].m_dData[0] = dData[m_csInFileInfo.m_lOutDataIdx]; // データを設定
                                //csSndCellData[0].m_dData[0] = dData[0]; // データを設定

                                m_OutputCellData[lP].SendData();    //設定データの送信

                                //McLog.DebugOut(csCursTm, m_csElement.GetID(),
                                //    "McTestINFileModel", "DataFusion", " OutQ[" + lP.ToString() + "]=" + dData[m_csInFileInfo.m_lOutDataIdx].ToString());
                            }
                            else if (McModelSampleDefine.IN_OUT_PATTERN_ANY.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                            {   // １次元配列セル出力ならば
                                this.m_csInFileInfo.m_csLastDataOutTime[lP].SetTime(csCursTm); // 送信した時刻を設定する

                                csOutputCellData[lP].SetCurrentTime(csCursTm);// 送信用のレコードを設定する（時刻設定）

                                csSndCellData = csOutputCellData[lP].PrepareSendCellD1(); // 送信用情報格納セルの準備

                                if (lCellNo >= lD1) { lCellNo = lD1; }
                                //for (long lClNo = 0; lClNo < this.m_csInFileInfo.m_lDataNum; lClNo++)
                                for (long lClNo = 0; lClNo < lCellNo; lClNo++)
                                {
                                    csSndCellData[lClNo].m_dData[0] = dData[lClNo]; // データを設定
                                    //McLog.DebugOut(csCursTm, m_csElement.GetID(),
                                    //"McTestINFileModel", "DataFusion", " OutQ[" + lP.ToString() + "]=" + dData[lClNo].ToString());
                                }

                                m_OutputCellData[lP].SendData();    //設定データの送信
                            }
                        }
                        m_csInFileInfo.m_csReadCSVData.MoveCursorNext();    // カーソル位置をひとつ進める
                    }
                } // end of for(lCnt)
            }   // end of for(出力数）

            return lRtn;
        }

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

        /// <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)
        {
            // 使用しやすいようにキャストしておく
            m_csInFileInfo = (McTestINFileInfo)m_csCalInfo;

            McModelPropertyInfo csPropInf = csCellMdlPropertyInfo as McModelPropertyInfo;
            if (csPropInf != null)
            {
                csPropInf.GetInfo(new HySString("m_csInFileNameWithPath"), ref m_csInFileNameWithFullPath);
                csPropInf.GetInfo("m_lSeriesNum", ref this.m_csInFileInfo.m_lDataNum);
                csPropInf.GetInfo("m_lOutDataIdx", ref this.m_csInFileInfo.m_lOutDataIdx);
            }
            else
            {
                m_csInFileNameWithFullPath = new HySString(HySEnvInf.GetHomeDirectory().ToString() + "\\temp\\TestFileIn.csv");
            }
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>演算実行中断中のプロパティ等情報設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = SetOnlineProperty(csCellMdlPropertyInfo)</para>
        /// </example>
        /// <param name="csCellMdlPropertyInfo">プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>演算中断中にプロパティ、初期値等を変更して動作させ場合等に使用する</para>
        /// </remarks>
        public override bool SetOnlineProperty(McCellModelPropertyIF csCellMdlPropertyInfo)
        {
            // Do Nothing
            return true;
        }
 


    }
}
