using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

using VRH.Common;
using VRH.Log4Pro.MultiLanguageManager;
using Vrh.XmlProcessing;
using System.Timers;
using Vrh.Logger;
using System.Data.SqlClient;
using System.Xml.Linq;

namespace Vrh.iScheduler
{
    public class iSchedulerXMLProcessor : LinqXMLProcessorBase
    {
        #region Elements and Attributes private classes
        private class Elements
        {
            public const string DATABASECONNECTIONSTRING = "DatabaseConnectionString";
            public const string OBJECTTYPE = "ObjectType";
            public const string GROUPID = "GroupId";

            public const string MONITORSERVICE = "MonitorService";
            public const string CHECKINTERVAL = "CheckInterval";
            public const string ISCHEDULERPARAMETERS = "iSchedulerParameters";
            public const string ENABLEWEBAPPSCHEDULER = "EnableWebAppScheduler";
        }

        private class Attributes
        {
        }
        #endregion Elements and Attributes private classes

        #region Properties

        /// <summary>
        /// Feldolgozás közben keletkezett hibaüzenetek.
        /// </summary>
        public string ErrorMessage { get; private set; } = string.Empty;

        /// <summary>
        /// Itt a model létrejöttekor egy fix érték: "en-US".
        /// </summary>
        public string LCID { get; private set; }

        /// <summary>
        /// Az adatbázishoz való kapcsolódás adatai.
        /// A ConnectionStringStore által feloldott érték, ha nem tudta feloldani akkor ami az xml-ben van.
        /// </summary>
        private string _DatabaseConnectionStringName = null;
        private string _DatabaseConnectionString = null;
        public string DatabaseConnectionString
        {
            get
            {
                if (_DatabaseConnectionString == null)
                {
                    _DatabaseConnectionStringName = GetValue(GetXElement(Elements.DATABASECONNECTIONSTRING), "");
                    try { _DatabaseConnectionString = ConnectionStringStore.GetSQL(_DatabaseConnectionStringName); }
                    catch { _DatabaseConnectionString = _DatabaseConnectionStringName; }
                    if (string.IsNullOrWhiteSpace(_DatabaseConnectionString)) { throw new ApplicationException($"The <{Elements.DATABASECONNECTIONSTRING}> element is missing or empty!"); }
                }
                return _DatabaseConnectionString;
            }
        }

        #region ObjectType property
        /// <summary>
        /// Az xml-ben található object type.
        /// Az ütemezések lekérdezéséhez szükséges.
        /// </summary>
        public string ObjectType
        {
            get
            {
                if (_ObjectType == null)
                {
                    _ObjectType = GetValue(GetXElement(Elements.OBJECTTYPE), "");
                    if (string.IsNullOrWhiteSpace(_ObjectType)) { throw new ApplicationException($"The <{Elements.OBJECTTYPE}> element is missing or empty!"); }
                }
                return _ObjectType;
            }
        }
        private string _ObjectType = null;
        #endregion ObjectType property

        #region GroupId property
        /// <summary>
        /// Az xml-ben található GroupId érték.
        /// Az ütemezések lekérdezéséhez szükséges.
        /// </summary>
        public string GroupId
        {
            get
            {
                if (_GroupId == null)
                {
                    _GroupId = GetValue(GetXElement(Elements.GROUPID), "");
                    if (string.IsNullOrWhiteSpace(_GroupId)) { throw new ApplicationException($"The <{Elements.GROUPID}> element is missing or empty!"); }
                    else if (_GroupId.Trim() == "*") { throw new ApplicationException($"The value of the <{Elements.GROUPID}> element can not equal '*'!"); }
                }
                return _GroupId;
            }
        }
        private string _GroupId = null;
        #endregion GroupId property

        #region CheckInterval property
        public bool EnableWebAppExecution
        {
            get
            {
                string stringvalue = GetValue(GetXElement(Elements.MONITORSERVICE, Elements.ENABLEWEBAPPSCHEDULER), bool.FalseString);
                if (string.IsNullOrEmpty(stringvalue)) return false;
                return stringvalue.ToLower() == bool.TrueString.ToLower();
            }
        }
        /// <summary>
        /// Az időzítések figyelése ennyi időközönként (másodperc) fog megtörténni.
        /// Minimum: 60 sec (1perc), maximum: 86400 sec (1nap).
        /// Ha a tulajdonság nem létezik, vagy értelmezhetetlen, akkor a minimum lesz.
        /// </summary>
        public int CheckIntervalInSeconds
        {
            get
            {
                if (_CheckInterval < CheckIntervalMinimum)
                {
                    string chckint = GetValue(GetXElement(Elements.MONITORSERVICE, Elements.CHECKINTERVAL), "");
                    if (string.IsNullOrEmpty(chckint))
                    {
                        _CheckInterval = CheckIntervalMinimum;
                    }
                    else
                    {
                        if (!int.TryParse(chckint, out _CheckInterval)) { _CheckInterval = CheckIntervalMinimum; }
                    }
                    _CheckInterval = Math.Min(Math.Max(_CheckInterval, CheckIntervalMinimum), CheckIntervalMaximum);
                }
                return _CheckInterval;
            }
        }
        private int _CheckInterval;
        #endregion CheckInterval properties

        #region iSchedulerParameters property
        /// <summary>
        /// Az iScheduler xml paraméter file pontos elérési útja.
        /// Ha nincs megadva a plugin InstanceData paramétereként, akkor ez lesz használatos, ha pedig ez sincs megadva, 
        /// akkor maga a plug InstanceConfig paramétereként megadott file.
        /// Minimum: 60 sec (1perc), maximum: 86400 sec (1nap).
        /// Ha a tulajdonság nem létezik, vagy értelmezhetetlen, akkor a minimum lesz.
        /// </summary>
        public string iSchedulerParameters
        {
            get { return GetValue(GetXElement(Elements.MONITORSERVICE, Elements.ISCHEDULERPARAMETERS), ""); }
        }
        //private string _iSchedulerParameters;
        #endregion iSchedulerParameters properties

        /// <summary>
        /// Az időzítések figyelésének minimum értéke.
        /// </summary>
        public int CheckIntervalMinimum { get; private set; }

        /// <summary>
        /// Az időzítések figyelésének maximum értéke.
        /// </summary>
        public int CheckIntervalMaximum { get; private set; }

        public string ScheduleMonitorXmlPath { get; private set; }

        public string ScheduleXmlPath { get; private set; }

        #endregion Properties

        public iSchedulerXMLProcessor(string scheduleMonitorXmlPath, string scheduleXmlPath = null) : base(scheduleMonitorXmlPath)
        {
            try
            {
                base._xmlNameSpace = string.Empty;
                base._xmlFileDefinition = scheduleMonitorXmlPath;
                this.SetThrowException(true);
                XElement rootXE = base.GetRootElement();    // csak azért, hogy kiderüljenek az XML hibák!
                this.SetThrowException(false);
                //rootXE = base.GetRootElement();    // csak azért, hogy kiderüljenek az XML hibák!

                LCID = "en-US";    //fix érték, mert nincs honnan megtudni a beállítást!
                CheckIntervalMinimum = 60; // 1 perc
                CheckIntervalMaximum = 86400; // 1 nap
                this.ScheduleMonitorXmlPath = scheduleMonitorXmlPath;
                this.ScheduleXmlPath = string.IsNullOrEmpty(scheduleXmlPath) ? this.iSchedulerParameters : scheduleXmlPath;
                this.ScheduleXmlPath = string.IsNullOrEmpty(this.ScheduleXmlPath) ? this.ScheduleMonitorXmlPath : this.ScheduleXmlPath;

                this._CheckInterval = -1;   // annak jelzése, hogy a beállítás még nem történt meg.

                if (ErrorMessage != string.Empty) { throw new ApplicationException(ErrorMessage); }
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Error occured while xml processing!", ex);
            }
        }
    }
}
