using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Configuration;
using System.Data;
using System.Diagnostics;

using WinSCP;
using DataAccess;


namespace RevampPhilipsService
{
    public class CSFTP
    {

        string m_strHostKey = String.Empty;
        string m_strHostName = String.Empty;
        string m_strUserName = String.Empty;
        string m_strPwd = String.Empty;
        int m_nPort = 0;
        string m_strDataDir = String.Empty;
        string m_strLocalDataDir = String.Empty;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cnn"></param>
        /// <param name="evt"></param>
        /// <returns></returns>
        private bool LoadSystemSettings(ref CDataConnection cnn,
                                        ref CLogEvent evt)
        {
            bool bSuccess = false;
            string strMsg = String.Empty;
            string strHostKey = String.Empty;
            string strHostName = String.Empty;
            string strUserName = String.Empty;
            string strPwd = String.Empty;
            int nPort = 0;
            string strDataDir = String.Empty;
            string strLocalDataDir = String.Empty;

            long lStatusCode = 0;
            string strStatusComment = String.Empty;


            
            //parameter list (BaseMstr.ASPSessionID, BaseMstr.ClientIP, BaseMstr.FXUserID);
            CDataParameterList plist = new CDataParameterList(String.Empty, String.Empty, 0);

            //
            CDataSet cds = new CDataSet();
            DataSet ds = cds.GetOracleDataSet(cnn,
                                              "PCK_UTL_PARAMETERS.GetSystemParametersRS",
                                              plist,
                                              out lStatusCode,
                                              out strStatusComment);

            //check response
            if (lStatusCode == 0)
            {
                if (ds != null)
                {
                    foreach (DataTable table in ds.Tables)
                    {
                        //get the parameters
                        foreach (DataRow row in table.Rows)
                        {
                            string strParamName = String.Empty;
                            string strParamValue = String.Empty;

                            strParamName = CDataUtils2.GetDSStringValue(row, "PARAMETER_NAME");
                            strParamValue = CDataUtils2.GetDSStringValue(row, "PARAMETER_VALUE");

                            if (!String.IsNullOrEmpty(strParamName))
                            {
                                switch (strParamName)
                                {
                                    case "PHILIPS_SFTP_HOSTKEY":
                                        strHostKey = strParamValue;
                                        break;

                                    case "PHILIPS_SFTP_HOSTNAME":
                                        strHostName = strParamValue;
                                        break;

                                    case "PHILIPS_SFTP_USR":
                                        strUserName = strParamValue;
                                        break;

                                    case "PHILIPS_SFTP_PWD":
                                        strPwd = strParamValue;
                                        break;

                                    case "PHILIPS_SFTP_PORT":
                                        nPort = Convert.ToInt16(strParamValue);
                                        break;

                                    case "PHILIPS_SFTP_DATADIR":
                                        strDataDir = strParamValue;
                                        break;

                                }
                            }
                        }

                        //work with the parameters...
                        if (!String.IsNullOrEmpty(strHostKey) &&
                            !String.IsNullOrEmpty(strHostName) &&
                            !String.IsNullOrEmpty(strUserName) &&
                            !String.IsNullOrEmpty(strPwd) &&
                            nPort > 0 &&
                            !String.IsNullOrEmpty(strDataDir))
                        {
                            m_strHostKey = strHostKey;
                            m_strHostName = strHostName;
                            m_strUserName = strUserName;
                            m_strPwd = strPwd;
                            m_nPort = nPort;
                            m_strDataDir = strDataDir;

                            //try loading the system settings from the config file
                            try
                            {
                                m_strLocalDataDir = ConfigurationManager.ConnectionStrings["PhilipsDataDir"].ConnectionString;
                                bSuccess = true;
                            }
                            catch (ConfigurationErrorsException e)
                            {
                                if (e != null)
                                {
                                    lStatusCode = 1;
                                    strMsg = "Local data dir setting not found.";
                                    bSuccess = false;
                                }
                            }
                            catch (NullReferenceException e)
                            {
                                if (e != null)
                                {
                                    lStatusCode = 1;
                                    strMsg = "Local data dir setting not found.";
                                    bSuccess = false;
                                }
                            }
                        }
                        else
                        {
                            lStatusCode = 1;
                            strMsg = "Not all system settings are found for Philips SFTP.";
                            bSuccess = false;
                        }

                    }
                }
                else
                {
                    lStatusCode = 1;
                    strMsg = "System settings not found for Philips SFTP.";
                }
            }
            else
            {
                lStatusCode = 1;
                strMsg = "An error occurred while loading system settings.";
            }

            if (lStatusCode != 0)
            {
                evt.EventMessages[(int)CLogEvent.EventMessage.nDETAIL_MESSAGE] = strMsg;
                evt.LogEvent(CLogEvent.EventMessage.nDETAIL_MESSAGE, EventLogEntryType.Error);
            }

            return bSuccess;
        }

        /// <summary>
        /// Get XML files from vendor
        /// </summary>
        /// <param name="evt"></param>
        /// <returns></returns>
        public bool GetFiles(ref CLogEvent evt, ref int nFilesToProcess)
        {
            bool bFilesToProcess = false;
            bool bStatus = false;

            CDataConnection conn = null;
            string strConnectionString = String.Empty;
            bool bAudit = true;

            //set to none...
            nFilesToProcess = 0;

            //config settings
            try
            {
                string strUseCnnConfig = "DBConnString_" + ConfigurationManager.AppSettings["APP_TARGET_ENV"];
                strConnectionString = ConfigurationManager.ConnectionStrings[strUseCnnConfig].ConnectionString;
                bAudit = (ConfigurationManager.AppSettings["AUDIT"] == "1") ? true : false;
            }
            catch (ConfigurationErrorsException e)
            {
                if (e != null) { }
                evt.LogEvent(CLogEvent.EventMessage.nERROR_CONFIG_FILE, EventLogEntryType.Error);
                return false;
            }

            //connect to data source
            conn = new CDataConnection();
            if (!conn.Connect(strConnectionString, (int)DataConnectionType.Oracle, bAudit))
            {
                evt.LogEvent(CLogEvent.EventMessage.nERROR_CONNECTING_DB, EventLogEntryType.Error);
                return false;
            }

            //load system settings
            bStatus = LoadSystemSettings(ref conn, ref evt);
            if(bStatus == false)
            {
                conn.Close();
                return false;
            }

            //SFTP
            try
            {
                // Setup session options
                SessionOptions sessionOptions = new SessionOptions
                {
                    Protocol = Protocol.Sftp,
                    SshHostKeyFingerprint = m_strHostKey,
                    HostName = m_strHostName,
                    UserName = m_strUserName,
                    Password = m_strPwd,
                    PortNumber = m_nPort
                };

                evt.LogEvent(CLogEvent.EventMessage.nSEARCHING_AVAILABLE_FILES, EventLogEntryType.Information);

                using (Session session = new Session())
                {
                    DateTime dtToday = System.DateTime.Now;
                    
                    // Connect
                    session.Open(sessionOptions);

                    TransferOptions transferOptions = new TransferOptions
                    {
                        TransferMode = TransferMode.Binary
                    };

                    //get all files...
                    RemoteDirectoryInfo directory = session.ListDirectory(m_strDataDir);
                    foreach (RemoteFileInfo fileInfo in directory.Files)
                    {
                        if (fileInfo.IsDirectory == false && 
                            fileInfo.FileType == '-' && 
                            fileInfo.Name.Substring(fileInfo.Name.Length - 4, 4).ToLower() == ".xml" &&
                            fileInfo.Name.Contains("-" + dtToday.ToString("yyyyMMdd")))
                        {
                            if (IsNewFile(fileInfo.Name, ref conn))
                            {
                                TransferOperationResult r = session.GetFiles(m_strDataDir + "/" + fileInfo.Name, m_strLocalDataDir, false, new TransferOptions() { TransferMode = TransferMode.Binary });
                                if (r.IsSuccess)
                                {
                                    nFilesToProcess += r.Transfers.Count;
                                    bFilesToProcess = true;
                                }
                            }
                        }
                    }

                    //close session
                    session.Close();

                }
            }
            catch (Exception e)
            {
                evt.LogEvent(e.ToString(), EventLogEntryType.Error);
            }

            //close connection.
            conn.Close();

            return bFilesToProcess;
        }

        /// <summary>
        /// Check if the data file was already processed.
        /// </summary>
        /// <param name="strFileName"></param>
        /// <param name="conn"></param>
        /// <returns></returns>
        public bool IsNewFile(string strFileName,
                              ref CDataConnection conn)
        {
            bool bNewFile = false;

            long lExists = 0;
            long lStatusCode = 0;
            string strStatusComment = String.Empty;

            CDataParameterList pList = new CDataParameterList();
            pList.AddInputParameter("pi_nVendorID", 1); //Vendor ID = 1 = Philips
            pList.AddInputParameter("pi_vDataName", strFileName);
            pList.AddOutputParameter("po_nExists", lExists);

            conn.ExecuteOracleSP("PCK_XFER.ExistsDataFile",
                                  pList,
                                  out lStatusCode,
                                  out strStatusComment);

            if (lStatusCode == 0)
            {
                CDataParameter paramValue = pList.GetItemByName("po_nExists");
                lExists = paramValue.LongParameterValue;

                if (lExists == 0)
                {
                    bNewFile = true;
                }
                else
                {
                    //file already exists; it is not a new file
                    bNewFile = false;
                }
            }
            
            return bNewFile;
        }
    }
}
