using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

using System.Net;
using System.Configuration;
using System.Threading;
using DataAccess;

namespace RevampResmedService
{
    public partial class RevampResmedSvc : ServiceBase
    {
        /// <summary>
        /// timer property
        /// </summary>
        private System.Threading.Timer m_Timer;

        /// <summary>
        /// constructor
        /// </summary>
        public RevampResmedSvc()
        {
            m_Timer = null;

            InitializeComponent();
        }

        /// <summary>
        /// On start
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            int nTimerStartInterval = 0;
            int nTimerThreadPoolInterval = 0;

            CLogEvent evt = new CLogEvent();
            string strConn = String.Empty;
            bool bAudit = false;

            evt.LogEvent(CLogEvent.EventMessage.nSERVICE_STARTING, EventLogEntryType.Information);
            
            //always check and protect the connection strings if necessary
            //this would allow an admin user to stop the service, 
            //change the conn string and restart.
            //on restart of the service the section would be protected
            try
            {
                Configuration ctg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                ConnectionStringsSection sect = ctg.GetSection("connectionStrings") as ConnectionStringsSection;
                if (sect != null && !sect.SectionInformation.IsProtected)
                {
                    //protect the section
                    sect.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");

                    //save the file
                    ctg.Save();
                }
            }
            catch (Exception e)
            {
                if (e != null)
                {
                    //an error occured while accessing or protecting the config file
                    //this is catastrophic so log and return
                    evt.LogEvent(CLogEvent.EventMessage.nERROR_CONFIG_FILE, EventLogEntryType.Error);
                    return;
                }
            }
             
            //get the connection string
            try
            {
                string strUseCnnConfig = "DBConnString_" + ConfigurationManager.AppSettings["APP_TARGET_ENV"];
                strConn = ConfigurationManager.ConnectionStrings[strUseCnnConfig].ToString();
                bAudit = (ConfigurationManager.AppSettings["AUDIT"] == "1") ? true : false;
            }
            catch (ConfigurationErrorsException e)
            {
                if (e != null)
                {
                    evt.LogEvent(CLogEvent.EventMessage.nERROR_CONFIG_FILE, EventLogEntryType.Error);
                    return;
                }
            }
            
            //test conenction to the database
            CDataConnection conn = new CDataConnection();
            if (!conn.Connect(strConn, (int)DataConnectionType.Oracle, false))
            {
                evt.LogEvent(CLogEvent.EventMessage.nERROR_CONNECTING_DB, EventLogEntryType.Error);
                return;
            }
            else
            {
                evt.LogEvent(CLogEvent.EventMessage.nSUCCESS_CONN_DB, EventLogEntryType.Information);
                //leave connection open to get system settings from database
            }

            //try loading the system setting from the database...
            if (LoadSystemSettings(ref conn, ref nTimerStartInterval, ref nTimerThreadPoolInterval))
            {
                evt.EventMessages[(int)CLogEvent.EventMessage.nDETAIL_MESSAGE] = "[DB] ntimerStartInterval ntimerThreadPoolInterval " + Convert.ToString(nTimerStartInterval) + "  " + Convert.ToString(nTimerThreadPoolInterval);
                evt.LogEvent(CLogEvent.EventMessage.nDETAIL_MESSAGE, EventLogEntryType.Information);
            }
            else
            {
                evt.LogEvent(CLogEvent.EventMessage.nSWITCH_TO_CONFIG, EventLogEntryType.Warning);

                //try loading the system settings from the config file
                try
                {
                    //intervlas are stored in seconds in the config file
                    nTimerStartInterval = 1000 * Convert.ToInt32(ConfigurationManager.AppSettings["timerStartInterval"].ToString());
                    nTimerThreadPoolInterval = 1000 * Convert.ToInt32(ConfigurationManager.AppSettings["timerThreadPoolInterval"].ToString());

                    evt.EventMessages[(int)CLogEvent.EventMessage.nDETAIL_MESSAGE] = "[CONFIG] ntimerStartInterval ntimerThreadPoolInterval " + Convert.ToString(nTimerStartInterval) + "  " + Convert.ToString(nTimerThreadPoolInterval);
                    evt.LogEvent(CLogEvent.EventMessage.nDETAIL_MESSAGE, EventLogEntryType.Information);
                }
                catch (ConfigurationErrorsException e)
                {
                    if (e != null)
                    {
                        //get the timer cycle (300000 milliseconds or 5 minutes)
                        nTimerStartInterval = 5000;
                        nTimerThreadPoolInterval = 300000;

                        //log the issue but press on with defaults
                        evt.LogEvent(CLogEvent.EventMessage.nSWITCH_TO_DEFAULT_INTERVALS, EventLogEntryType.Warning);

                        evt.EventMessages[(int)CLogEvent.EventMessage.nDETAIL_MESSAGE] = "[DEFAULT] ntimerStartInterval ntimerThreadPoolInterval " + Convert.ToString(nTimerStartInterval) + "  " + Convert.ToString(nTimerThreadPoolInterval);
                        evt.LogEvent(CLogEvent.EventMessage.nDETAIL_MESSAGE, EventLogEntryType.Information);
                    }
                }
                catch (NullReferenceException e)
                {
                    if (e != null)
                    {
                        //get the timer cycle (300000 milliseconds or 5 minutes)
                        nTimerStartInterval = 5000;
                        nTimerThreadPoolInterval = 300000;

                        //log the issue but press on with defaults
                        evt.LogEvent(CLogEvent.EventMessage.nSWITCH_TO_DEFAULT_INTERVALS, EventLogEntryType.Warning);

                        evt.EventMessages[(int)CLogEvent.EventMessage.nDETAIL_MESSAGE] = "[DEFAULT] ntimerStartInterval ntimerThreadPoolInterval " + Convert.ToString(nTimerStartInterval) + "  " + Convert.ToString(nTimerThreadPoolInterval);
                        evt.LogEvent(CLogEvent.EventMessage.nDETAIL_MESSAGE, EventLogEntryType.Information);
                    }
                }
            }
            //now get can close the connection
            conn.Close();


            //create a new timer, will run once at 5 seconds (ntimerStartInterval) and then 
            //every 5 minutes (ntimerThreadPoolInterval)...
            AutoResetEvent autoEvent = new AutoResetEvent(false);
            CServiceTimer svcTimer = new CServiceTimer();
            TimerCallback tcb = svcTimer.OnTimer;
            m_Timer = new Timer(tcb,
                                autoEvent,
                                nTimerStartInterval,
                                nTimerThreadPoolInterval);

        }

        /// <summary>
        /// On stop
        /// </summary>
        protected override void OnStop()
        {

        }

        /// <summary>
        /// Load System Setting from DB (level 1)
        /// </summary>
        /// <param name="cnn"></param>
        /// <param name="nTimerStartInterval"></param>
        /// <param name="nTimerThreadPoolInterval"></param>
        /// <returns></returns>
        private bool LoadSystemSettings(ref CDataConnection cnn,
                                        ref int nTimerStartInterval,
                                        ref int nTimerThreadPoolInterval)
        {
            bool bLoaded = false;
            string strTimerStartInterval = String.Empty;
            string strTimerThreadPoolInterval = 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)
                    {
                        //load from list...
                        foreach (DataRow row in table.Rows)
                        {
                            if(!row.IsNull("PARAMETER_NAME"))
                            {
                                switch (row["PARAMETER_NAME"].ToString())
                                {
                                    case "RESMED_SVC_START_INTERVAL":
                                        if (!row.IsNull("PARAMETER_VALUE"))
                                        {
                                            strTimerStartInterval = row["PARAMETER_VALUE"].ToString();
                                        }
                                        break;

                                    case "RESMED_SVC_THREAD_INTERVAL":
                                        if (!row.IsNull("PARAMETER_VALUE"))
                                        {
                                            strTimerThreadPoolInterval = row["PARAMETER_VALUE"].ToString();
                                        }
                                        break;
                                }
                            }
                        }

                        //convert to actual settings...
                        if (!String.IsNullOrEmpty(strTimerStartInterval) && !String.IsNullOrEmpty(strTimerThreadPoolInterval))
                        {
                            nTimerStartInterval = 1000 * Convert.ToInt32(strTimerStartInterval);
                            nTimerThreadPoolInterval = 1000 * Convert.ToInt32(strTimerThreadPoolInterval);
                            bLoaded = true;
                        }
                        else
                        {
                            bLoaded = false;
                        }                            

                    }
                }
            }

            return bLoaded;

        }
      
    }
}
