using System;
using System.ComponentModel;
using System.Xml;
using System.Data;
using System.Reflection;
using System.Configuration;
using Autofac;
using Bowin.Common.Log;
using EMIS.CommonLogic.SystemServices;
using EMIS.Entities;

namespace EMIS.Services
{
    #region 所有的服务工作接口 IServiceJob
    /// <summary>
    /// IServiceJob : 所有的服务工作接口
    /// </summary>
    public interface IServiceJob
    {
        string JobID { get; set; }
        string JobName { get; set; }
        Guid SchedulerID { get; set; }
        int MaxThreadSize { get; set; }
        bool IsDebug { get; set; }
        string CertFile { get; set; }
        void ExecuteJob();

        DateTime AllTimeBegin { get; set; }
        DateTime AllTimeEnd { get; set; }
        int AllUseSeconds { get; set; }
        string Desc { get; set; }
    }
    #endregion

    #region  所有Job的基类
    /// <summary>
    /// 所有Job的基类。
    /// </summary>
    public abstract class EAPServiceJob : IServiceJob
    {
        #region 实现IServiceJob接口
        private string _jobid = "";
        private string _jobname = "";
        private Guid _schedulerid = Guid.Empty;
        private int _MaxThreadSize = 1;

        private bool _isdubug = false;

        private string _certfile = "";

        DateTime _AllTimeBegin;
        DateTime _AllTimeEnd;
        int _AllUseSeconds;

        DateTime _OneScheduleTimeBegin;
        DateTime _OneScheduleTimeEnd;
        int _OneScheduleUseSeconds;
        bool _Successful;

        string _Desc;
        /// <summary>
        /// 任务ID
        /// </summary>
        public string JobID
        {
            get { return _jobid; }
            set { _jobid = value; }
        }

        /// <summary>
        /// 任务名称
        /// </summary>
        public string JobName
        {
            get { return _jobname; }
            set { _jobname = value; }
        }

        /// <summary>
        /// 执行ID
        /// </summary>
        public Guid SchedulerID
        {
            get { return _schedulerid; }
            set { _schedulerid = value; }
        }

        /// <summary>
        /// 子服务同时最大线程数
        /// </summary>
        public int MaxThreadSize
        {
            get { return _MaxThreadSize; }
            set { _MaxThreadSize = value; }
        }

        /// <summary>
        /// 是否调试状态
        /// </summary>
        public bool IsDebug
        {
            get { return _isdubug; }
            set { _isdubug = value; }
        }

        /// <summary>
        /// 证书文件
        /// </summary>
        public string CertFile
        {
            get { return this._certfile; }
            set { this._certfile = value; }
        }

        /// <summary>
        /// 总体执行开始时间
        /// </summary>
        public DateTime AllTimeBegin
        {
            get { return _AllTimeBegin; }
            set { _AllTimeBegin = value; }
        }

        /// <summary>
        /// 总体执行结束时间
        /// </summary>
        public DateTime AllTimeEnd
        {
            get { return _AllTimeEnd; }
            set { _AllTimeEnd = value; }
        }



        /// <summary>
        /// 总体服务执行耗时秒数
        /// </summary>
        public int AllUseSeconds
        {
            get { return _AllUseSeconds; }
            set { _AllUseSeconds = value; }
        }

        /// <summary>
        /// 单个服务执行开始时间
        /// </summary>
        public DateTime OneScheduleTimeBegin
        {
            get { return _OneScheduleTimeBegin; }
            set { _OneScheduleTimeBegin = value; }
        }

        /// <summary>
        /// 单个服务执行结束时间
        /// </summary>
        public DateTime OneScheduleTimeEnd
        {
            get { return _OneScheduleTimeEnd; }
            set { _OneScheduleTimeEnd = value; }
        }

        /// <summary>
        /// 单个服务执行耗时秒数
        /// </summary>
        public int OneScheduleUseSeconds
        {
            get { return _OneScheduleUseSeconds; }
            set { _OneScheduleUseSeconds = value; }
        }

        /// <summary>
        /// 是否执行成功
        /// </summary>
        public bool Successful
        {
            get { return _Successful; }
            set { _Successful = value; }
        }

        /// <summary>
        /// 执行结果备注信息
        /// </summary>
        public string Desc
        {
            get { return _Desc; }
            set { _Desc = value; }
        }

        #endregion

        #region	运行JOB
        public void RunJobOnce()
        {
            this.MyJob();
        }
        #endregion

        public virtual void ExecuteJob()
        {
            //起止配对;容易找起止。
            Guid tagID = Guid.NewGuid();
            try
            {
                this.Init();
                Desc = "服务【" + this._jobname + "】开始执行:{" + tagID.ToString() + "}";
                LogHelper.WriteLog(LogType.ServiceLog, Desc);

                //先置最后执行时间;防止多线程一次集中连续执行。
                using (var scop = Program.AutofacContainer.BeginLifetimeScope())
                {
                    var ScheduleServices = scop.Resolve<IScheduleServices>();
                    ScheduleServices.UpdateLastRun(SchedulerID);
                }

                this.MyJob();

                OneScheduleTimeEnd = System.DateTime.Now;
                TimeSpan ts = new TimeSpan();
                ts = OneScheduleTimeEnd - OneScheduleTimeBegin;
                OneScheduleUseSeconds = Convert.ToInt32(ts.TotalSeconds);
                Desc = "服务【" + this._jobname + "】结束执行;耗时:" + OneScheduleUseSeconds.ToString() + "秒。{" + tagID.ToString() + "}";
                LogHelper.WriteLog(LogType.ServiceLog, Desc);
                Successful = true;
                UpdateSchedulingLog(SchedulerID, JobID, OneScheduleTimeBegin, OneScheduleTimeEnd, OneScheduleUseSeconds,
                                     Successful, "执行成功");
            }
            catch (Exception err)
            {
                OneScheduleTimeEnd = System.DateTime.Now;
                Desc = "服务【" + this._jobname + "】执行异常:" + err.Message;
                TimeSpan ts = new TimeSpan();
                ts = OneScheduleTimeEnd - OneScheduleTimeBegin;
                OneScheduleUseSeconds = Convert.ToInt32(ts.TotalSeconds); //转换时间间隔为 秒   
                LogHelper.WriteLog(LogType.ServiceLog, "服务【" + this._jobname + "】结束;耗时:" + OneScheduleUseSeconds.ToString() + "秒;{" + tagID.ToString() + "} \r\n 执行结果:\r\n " + Desc);
                Successful = true;
                UpdateSchedulingLog(SchedulerID, JobID, OneScheduleTimeBegin, OneScheduleTimeEnd, OneScheduleUseSeconds,
                                     Successful, "执行失败:" + err.Message);
            }
            finally
            {
            }
        }

        protected virtual bool Init()
        {
            Successful = true;
            AllTimeBegin = System.DateTime.Now;
            AllTimeEnd = System.DateTime.Now;
            AllUseSeconds = 0;

            OneScheduleTimeBegin = System.DateTime.Now;
            OneScheduleTimeEnd = System.DateTime.Now;
            OneScheduleUseSeconds = 0;
            Desc = "服务【" + this._jobname + "】开始执行:";
            return true;
        }

        protected abstract bool MyJob();

        #region 修改具体服务调度表中的执行信息,记录服务调度历史记录。
        /// <summary>
        /// 修改具体服务调度表中的执行信息,记录服务调度历史记录。
        /// </summary>
        public void UpdateSchedulingLog(Guid schedulerID, string jobID, DateTime scheduleTimeBegin, DateTime scheduleTimeEnd, int UseSeconds,
                                        bool successful, string desc)
        {
            try
            {
                using (var scop = Program.AutofacContainer.BeginLifetimeScope())
                {
                    var ScheduleServices = scop.Resolve<IScheduleServices>();
                    ScheduleServices.UpdateLastRunAndLoopNum(SchedulerID);

                    Sys_ScheduleLog log = new Sys_ScheduleLog();
                    log.scid = schedulerID;
                    log.timeBegin = scheduleTimeBegin;
                    log.timeEnd = scheduleTimeEnd;
                    log.successful = successful;
                    log.useSeconds = UseSeconds;
                    log.Desc = desc;
                    ScheduleServices.InsertLog(log);
                }

            }
            catch (Exception ce)
            {
                LogHelper.WriteLog(LogType.ServiceLog, "操作数据库异常:" + ce.Message);
            }

        }
        #endregion
    }
    #endregion

    #region ServiceWrapper的接口
    namespace MyEAPServiceWrapper
    {
        /// <summary>
        /// ServiceWrapper的接口。
        /// 开启多线程,并且控制每个子服务当前最多只有一个线程在执行;多个子服务可以同时执行;防止不同的子服务彼此相互堵塞。
        /// </summary>
        public interface IServiceWrapper
        {
            bool IsDebug { get; set; }
            bool Execute();
        }
    }
    #endregion

    #region EAPServiceWrapper
    namespace MyEAPServiceWrapper
    {
        /// <summary>
        /// ServiceWrapper的具体子服务执行。
        /// 开启多线程,并且控制每个子服务当前最多只有一个线程在执行;多个子服务可以同时执行;防止不同的子服务彼此相互堵塞。
        /// </summary>
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Linq.Expressions;
        using System.Data.Entity;
        using System.Data.SqlClient;
        using System.Data;
        using System.Collections;
        public class ServiceWrapper : IServiceWrapper
        {
            #region 实现IServiceWrapper接口属性
            private bool _isdubug = false;

            DateTime _AllTimeBegin;
            DateTime _AllTimeEnd;
            int _AllUseSeconds;

            DateTime _OneScheduleTimeBegin;
            DateTime _OneScheduleTimeEnd;
            int _OneScheduleUseSeconds;
            bool _Successful;
            string _Desc;
            Guid SchedulerID = Guid.Empty;
            int MaxThreadSize = 1;
            string JobID = "";
            string JobName = "";
            string AssemName = "";
            string ClassName = "";

            /// <summary>
            /// 是否调试状态
            /// </summary>
            public bool IsDebug
            {
                get { return _isdubug; }
                set { _isdubug = value; }
            }

            /// <summary>
            /// 总体执行开始时间
            /// </summary>
            public DateTime AllTimeBegin
            {
                get { return _AllTimeBegin; }
                set { _AllTimeBegin = value; }
            }

            /// <summary>
            /// 总体执行结束时间
            /// </summary>
            public DateTime AllTimeEnd
            {
                get { return _AllTimeEnd; }
                set { _AllTimeEnd = value; }
            }

            /// <summary>
            /// 总体服务执行耗时秒数
            /// </summary>
            public int AllUseSeconds
            {
                get { return _AllUseSeconds; }
                set { _AllUseSeconds = value; }
            }

            /// <summary>
            /// 单个服务执行开始时间
            /// </summary>
            public DateTime OneScheduleTimeBegin
            {
                get { return _OneScheduleTimeBegin; }
                set { _OneScheduleTimeBegin = value; }
            }

            /// <summary>
            /// 单个服务执行结束时间
            /// </summary>
            public DateTime OneScheduleTimeEnd
            {
                get { return _OneScheduleTimeEnd; }
                set { _OneScheduleTimeEnd = value; }
            }

            /// <summary>
            /// 单个服务执行耗时秒数
            /// </summary>
            public int OneScheduleUseSeconds
            {
                get { return _OneScheduleUseSeconds; }
                set { _OneScheduleUseSeconds = value; }
            }

            /// <summary>
            /// 是否执行成功
            /// </summary>
            public bool Successful
            {
                get { return _Successful; }
                set { _Successful = value; }
            }

            /// <summary>
            /// 执行结果备注信息
            /// </summary>
            public string Desc
            {
                get { return _Desc; }
                set { _Desc = value; }
            }
            #endregion

            #region 子服务线程控制
            public class ThreadInfo
            {
                public int ManagedThreadId { get; set; }
                public string Name { get; set; }
                public bool IsAlive { get; set; }
                public DateTime StartTime { get; set; }
            }

            /// <summary>
            /// 存放当前正在执行的子服务线程信息 
            /// </summary>
            static System.Collections.Generic.List<ThreadInfo> NowExecThreadsInfo = new System.Collections.Generic.List<ThreadInfo>();
            #endregion

            #region 整体控制执行服务
            /// <summary>
            /// 开启多线程,并且控制每个子服务当前最多只有一个线程在执行;多个子服务可以同时执行;防止不同的子服务彼此相互堵塞。
            /// </summary>
            /// <returns></returns>
            public bool Execute()
            {
                //AllTimeEnd = System.DateTime.Now;
                //Desc = "总体服务执行成功!";
                //TimeSpan ts = new TimeSpan();
                //ts = AllTimeEnd - AllTimeBegin;
                //AllUseSeconds = Convert.ToInt32(ts.TotalSeconds); //转换时间间隔为 秒   
                //Log.WriteLog("总体服务结束;耗时:" + AllUseSeconds.ToString() + "秒; \r\n 执行结果:\r\n " + Desc);
                bool bResult = true;
                //string serverName = ConfigurationManager.AppSettings["ServerName"]; 
                var scheduleJobList = QureyScheduleJobs();
                foreach (var scheduleJob in scheduleJobList)
                {
                    string sStartDate = scheduleJob.datebegin.ToString().Trim(); ;//20040707
                    sStartDate = sStartDate.Substring(0, 4) + "-" + sStartDate.Substring(4, 2) + "-" + sStartDate.Substring(6, 2);   //转换成2004-07-07
                    DateTime tmpStartDate = System.Convert.ToDateTime(sStartDate);

                    sStartDate = scheduleJob.dateend.ToString().Trim();
                    sStartDate = sStartDate.Substring(0, 4) + "-" + sStartDate.Substring(4, 2) + "-" + sStartDate.Substring(6, 2);   //转换成2004-07-07
                    DateTime tmpEndDate = System.Convert.ToDateTime(sStartDate);
                    int scinterval = scheduleJob.scinterval;
                    /* D:天 H:小时 M:分钟 S:秒 */
                    switch (scheduleJob.scmode.ToUpper())
                    {
                        case "D":
                            scinterval = scheduleJob.scinterval * (60 * 60 * 24);
                            //对于周期跨天的,要防止累计偏差而出现跳天现象(空出2分钟的柔韧空间值)。
                            scinterval = scinterval - 120;
                            break;
                        case "H":
                            scinterval = scheduleJob.scinterval * (60 * 60);
                            break;
                        case "M":
                            scinterval = scheduleJob.scinterval * (60);
                            break;
                        //默认秒
                        default:
                            break;
                    }
                    this.SchedulerID = scheduleJob.scid;
                    this.MaxThreadSize = 1;
                    this.JobID = scheduleJob.Sys_ScheduleJob.jobid;
                    this.JobName = scheduleJob.Sys_ScheduleJob.jobname;
                    this.AssemName = scheduleJob.Sys_ScheduleJob.assemname;
                    this.ClassName = scheduleJob.Sys_ScheduleJob.classname;
                    //检查该项服务是否到了下次运行时间,如是则运行。
                    if (this.CheckJobAllowRun(tmpStartDate, tmpEndDate, scinterval, scheduleJob.lastrun,
                        scheduleJob.timefrom, scheduleJob.timeto))
                    {
                        //this.JobRun(tmpSchedulerID, tmpJobID,tmpServerName, tmpJobName, tmpAssemName, tmpClassName); 
                        System.Threading.Thread thread = new System.Threading.Thread(JobRun);
                        thread.Start();
                        //防止循环后再次获取数据库进行判断,而当前的验证还没有加入线程属性导致可能多1个子线程服务在运行;需要停顿一下。
                        System.Threading.Thread.Sleep(3000);
                    }
                }
                return bResult;
            }
            #endregion

            #region 检查是允许运行
            /// <summary>
            /// 检查任务是否允许运行
            /// </summary>
            /// <param name="StartDate"></param>
            /// <param name="EndDate"></param>
            /// <param name="SecondTiple"></param>
            /// <param name="LastUpdate"></param>
            /// <returns></returns>
            private bool CheckJobAllowRun(DateTime StartDate, DateTime EndDate, int SecondTiple, DateTime? LastUpdate, string StartTime, string EndTime)
            {
                DateTime nowday = new System.DateTime(System.DateTime.Now.Year, System.DateTime.Now.Month, System.DateTime.Now.Day);

                StartDate = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day);
                EndDate = new DateTime(EndDate.Year, EndDate.Month, EndDate.Day);
                if ((nowday >= StartDate) && (nowday <= EndDate))
                {
                    if (InRunTimeRange(StartTime, EndTime))
                    {
                        if ((ReturnSecondFromDate(System.DateTime.Now) - ReturnSecondFromDate(LastUpdate)) >= SecondTiple)
                            return true;
                        else
                            return false;
                    }
                    else
                        return false;
                }
                else
                {
                    return false;
                }
            }
            /// <summary>
            /// 把日期转化为秒
            /// </summary>
            /// <param name="datetime1"></param>
            /// <returns></returns>
            private long ReturnSecondFromDate(DateTime? datetime1)
            {
                if (!datetime1.HasValue) return 0;
                return (long)((datetime1.Value.Year * 365 + datetime1.Value.DayOfYear) * 24 * 60 + datetime1.Value.Hour * 60 + datetime1.Value.Minute) * 60 + datetime1.Value.Second;
            }

            private bool InRunTimeRange(string StartTime, string EndTime)
            {
                int mHour = System.DateTime.Now.Hour;
                int mMinute = System.DateTime.Now.Minute;
                int mSecond = System.DateTime.Now.Second;

                string[] splStartTime = StartTime.Split(':');
                int mStartHour = Convert.ToInt32(splStartTime[0]);
                int mStartMinute = Convert.ToInt32(splStartTime[1]);
                int mStartSecond = Convert.ToInt32(splStartTime[2]);

                string[] splEndTime = EndTime.Split(':');
                int mEndHour = Convert.ToInt32(splEndTime[0]);
                int mEndMinute = Convert.ToInt32(splEndTime[1]);
                int mEndSecond = Convert.ToInt32(splEndTime[2]);

                int mCurrent = mHour * 60 * 60 + mMinute * 60 + mSecond;
                int mStart = mStartHour * 60 * 60 + mStartMinute * 60 + mStartSecond;
                int mEnd = mEndHour * 60 * 60 + mEndMinute * 60 + mEndSecond;

                if (mCurrent >= mStart && mCurrent <= mEnd)
                    return true;

                return false;
            }
            #endregion

            #region 运行具体某个Job
            /// <summary>
            /// 运行服务工作,不返回错误以免将其他的工作也停止
            /// private void JobRun(string schedulerID, string jobID,string serverName, string jobName, string assemName, string className)
            /// </summary>
            /// <param name="SqlConn"></param>
            /// <param name="JobName"></param>
            /// <param name="ClassName"></param>
            private void JobRun()
            {
                Guid schedulerID = SchedulerID;
                int maxThreadSize = MaxThreadSize;
                string jobID = JobID;
                string jobName = JobName;
                string assemName = AssemName;
                string className = ClassName;
                bool thisTimeNeedDo = true;
                ThreadInfo threadInfo = new ThreadInfo();
                try
                {

                    //判断检查该项服务对应的线程是否在运行。  
                    System.Threading.Thread currentSubServiceThread = System.Threading.Thread.CurrentThread;
                    currentSubServiceThread.Name = className;
                    //启动时间在6个钟内的线程才有效
                    var currentSubServices = (from a in NowExecThreadsInfo
                                              where a.Name == className
                                                    && a.StartTime > DateTime.Now.AddHours(-6)
                                              select new ThreadInfo
                                              {
                                                  ManagedThreadId = a.ManagedThreadId,
                                                  Name = a.Name,
                                                  IsAlive = a.IsAlive,
                                                  StartTime = a.StartTime
                                              }
                                             ).ToList();
                    int currentSubServiceNum = currentSubServices.Count;
                    LogHelper.WriteLog(LogType.ServiceLog, "当前【" + className + "】有个(" + currentSubServiceNum.ToString() + ")线程在执行。最大线程数:" + maxThreadSize.ToString() + ";时间:" + DateTime.Now.ToString());
                    if (currentSubServiceNum >= maxThreadSize)
                    {
                        thisTimeNeedDo = false;
                        LogHelper.WriteLog(LogType.ServiceLog, "当前【" + className + "】正已经有个(" + currentSubServiceNum.ToString() + ")线程在执行,本次跳过激发执行。" + DateTime.Now.ToString());
                    }
                    if (thisTimeNeedDo)
                    {
                        //加线程子服务信息   
                        threadInfo.ManagedThreadId = currentSubServiceThread.ManagedThreadId;
                        threadInfo.Name = currentSubServiceThread.Name;
                        threadInfo.IsAlive = currentSubServiceThread.IsAlive;
                        threadInfo.StartTime = DateTime.Now;
                        NowExecThreadsInfo.Add(threadInfo);


                        string fullClassName = "";
                        Assembly assem = Assembly.Load(assemName);


                        if (className.IndexOf(".") > 0)
                        {
                            fullClassName = className;
                        }
                        else
                        {
                            fullClassName = assemName + "." + className;
                        }

                        //Log.WriteLog("TestHere01 " + fullClassName);

                        Type classType = assem.GetType(fullClassName);
                        IServiceJob fss = (IServiceJob)System.Activator.CreateInstance(classType);
                        fss.SchedulerID = schedulerID;
                        fss.JobID = jobID;
                        fss.JobName = jobName;
                        fss.IsDebug = this._isdubug;
                        fss.CertFile = ConfigurationManager.AppSettings["CertFile"];


                        fss.ExecuteJob(); //运行Job
                    }
                }
                catch (Exception ce)
                {
                    LogHelper.WriteLog(LogType.ServiceLog, "服务【" + jobName + "】执行异常:" + ce.Message);
                }
                finally
                {
                    if (thisTimeNeedDo)
                    {
                        //处理完毕后清除线程子服务信息
                        NowExecThreadsInfo.Remove(threadInfo);
                    }
                }
            }
            #endregion


            #region 获取总体服务信息;然后处理那些需要执行的各个具体服务。
            /// <summary>
            /// 获取总体服务信息;然后处理那些需要执行的各个具体服务。
            /// </summary>
            public List<Sys_Scheduling> QureyScheduleJobs()
            {
                try
                {
                    using (var scop = Program.AutofacContainer.BeginLifetimeScope())
                    {
                        var ScheduleServices = scop.Resolve<IScheduleServices>();
                        return ScheduleServices.GetJobList();
                    }
                }
                catch (Exception ce)
                {
                    LogHelper.WriteLog(LogType.ServiceLog, "操作数据库异常:" + ce.Message);
                }
                finally
                {
                }
                return new List<Sys_Scheduling>();
            }
            #endregion
        }
    #endregion
    }
}