using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Configuration;
using Core.Mes.Common;
using Core.Mes.IBaseInterface;

namespace Core.Mes.ServerFrameWork
{
    public class Dispatcher : MarshalByRefObject, ICommon
    {
        private ArrayList _objects = null;
        private ServerConfigure _servConf = null;
        public ServerConfigure ServConfig
        {
            get { return _servConf; }
        }

        #region	"	Construct	"
        public Dispatcher() { }
        public Dispatcher(IServerPool pool, ServerConfigure _conf, ArrayList _objs)
        {
            Pool = pool;
            _servConf = _conf;
            _objects = _objs;
        }
        private IServerPool _pool = null;
        public IServerPool Pool
        {
            get { return _pool; }
            set
            {
                _pool = value;
                if (_pool.OwnObjects == null && _objects != null) _pool.OwnObjects = _objects;
            }
        }
        #endregion

        #region "	Variable	"

        //== 子服务集合
        public static Hashtable _htServers = new Hashtable();
        //== 数据链接集合
        public static Hashtable htDBManager = new Hashtable();

        public event GetStatusInfoHandler getStatusInfo;

        public delegate void GetStatusInfoHandler(string info);

        protected virtual void SetStatusMessage(string info)
        {
            if (getStatusInfo != null)
            {
                getStatusInfo(info);
            }
        }

        #endregion

        #region 内存释放
        public void MemoryDispose()
        {
            long memorysize = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64;
            int PagedMemorySize = (int)memorysize / (1024 * 1024);
            if (PagedMemorySize > _servConf.MemoryMaxSize)//进程占用内存>100M 做GC.
            {
                try
                {
                    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                }
                catch
                {

                }
                System.Diagnostics.Process.GetCurrentProcess().Dispose();
            }
        }
        #endregion

        #region MethodTimeLog
        private static object lockObj = new object();
        public void MethodTimeLog(TimeSpan tspan, object[] objs, object[] args)
        {
            string path = string.Format(@"./log/Method/MethodTimeLog_{0}.txt", System.DateTime.Now.ToString("yyyy_MM_dd"));

            lock (lockObj)
            {
                using (StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8))
                {

                    StringBuilder sbtxt = new StringBuilder();
                    sbtxt.AppendLine("==============================================");
                    sbtxt.AppendLine(string.Format("LogWriteTime:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                    sbtxt.AppendLine(string.Format("Time:{0}", tspan.TotalMilliseconds));
                    sbtxt.AppendLine(string.Format("ClassName:{0}", objs[0].ToString()));
                    sbtxt.AppendLine(string.Format("MethodName:{0}", objs[1].ToString()));
                    if (args != null)
                    {
                        foreach (object obj in args)
                        {
                            if (obj != null)
                            {
                                sbtxt.AppendLine(string.Format("Parameters:{0}", obj.ToString()));
                            }
                        }
                    }
                    sbtxt.AppendLine("==============================================");
                    sw.WriteLine(sbtxt.ToString());

                }
            }
        }
        public void MethodErrLog(Exception ex, object[] objs, object[] args)
        {
            string path = string.Format(@"./log/Method/MethodErrLog_{0}.txt", System.DateTime.Now.ToString("yyyy_MM_dd"));
            lock (lockObj)
            {
                using (StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8))
                {

                    StringBuilder sbtxt = new StringBuilder();
                    sbtxt.AppendLine("==============================================");
                    sbtxt.AppendLine(string.Format("LogWriteTime:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                    sbtxt.AppendLine(string.Format("ClassName:{0}", objs[0].ToString()));
                    sbtxt.AppendLine(string.Format("MethodName:{0}", objs[1].ToString()));
                    if (args != null)
                    {
                        foreach (object obj in args)
                        {
                            if (obj != null)
                            {
                                sbtxt.AppendLine(string.Format("Parameters:{0}", obj.ToString()));
                            }
                        }
                    }
                    sbtxt.AppendLine(ex.Message);
                    sbtxt.AppendLine(ex.StackTrace);
                    sbtxt.AppendLine("==============================================");
                    sw.WriteLine(sbtxt.ToString());

                }
            }
        }
        public void DebugLog(object[] objs, object[] args)
        {
            string path = string.Format(@"./log/Method/DebugLog_{0}.txt", System.DateTime.Now.ToString("yyyy_MM_dd"));
            lock (lockObj)
            {
                if (File.Exists(Path.GetFullPath(path)))
                {
                    FileInfo fileInfo = new FileInfo(Path.GetFullPath(path));
                    if (fileInfo.Length / (1024 * 1024) > 6)
                    {
                        File.Delete(path);
                    }
                }

                using (StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8))
                {

                    StringBuilder sbtxt = new StringBuilder();
                    sbtxt.AppendLine("==============================================");
                    sbtxt.AppendLine(string.Format("LogWriteTime:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                    sbtxt.AppendLine(string.Format("ClassName:{0}", objs[0].ToString()));
                    sbtxt.AppendLine(string.Format("MethodName:{0}", objs[1].ToString()));
                    if (args != null)
                    {
                        foreach (object obj in args)
                        {
                            if (obj != null)
                            {
                                sbtxt.AppendLine(string.Format("Parameters:{0}", obj.ToString()));
                            }
                        }
                    }
                    sbtxt.AppendLine("==============================================");
                    sw.WriteLine(sbtxt.ToString());

                }
            }
        }
        #endregion
        #region "	调用服务	"
        /// <summary>
        /// 服务端公开给客户端的调用后台服务的方法
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public ReturnObject MethodHandler(CallingMessage message, ValidateInfo validateInfo)
        {
            CallingMessageEx messageEx = new CallingMessageEx();
            messageEx.FromCallingMessage(message);
            messageEx.RedirectLimit = 0;
            messageEx.InnerServerRedirect = true;

            ReturnObjectEx rtnObjEx = Execute(messageEx, validateInfo);
            ReturnObject rtnObj = new ReturnObject();
            rtnObj.ErrCode = rtnObjEx.ErrCode;
            rtnObj.ErrMessage = rtnObjEx.ErrMessage;
            rtnObj.RealDataSet = rtnObjEx.RealDataSet;
            rtnObj.RealObject = rtnObjEx.RealObject;

            return rtnObj;
        }

        public ReturnObjectEx MethodHandlerEx(CallingMessageEx message, ValidateInfo validateInfo)
        {
            return Execute(message, validateInfo);
        }

        private ReturnObjectEx Execute(CallingMessageEx messageEx, ValidateInfo validateInfo)
        {
            //step1:
            MemoryDispose();

            //step2:
            string serverName = messageEx.ServerName;
            string assemblyName = messageEx.AssemblyName;
            string className = messageEx.ClassName;
            string methodName = messageEx.MethodName;
            object[] args = messageEx.args;

            ReturnObjectEx rtnObjEx = new ReturnObjectEx();
            MethodInfo myMethod = null;
            try
            {
                if (Pool.HtComponent.Contains(className))
                {
                    try
                    {
                        if (serverName.ToUpper() != "SERVERCOMMON" && messageEx.RedirectLimit > 0)
                        {
                            string RedirURL = "";
                            double sum_factor = 0;
                            ArrayList serviceProvider = new ArrayList();
                            ArrayList pfactors = new ArrayList();
                            serviceProvider.Add("THIS");
                            sum_factor += this.ServConfig.PriorityFactor;
                            pfactors.Add(sum_factor);
                            foreach (string server in Pool.HtExtServer.Keys)
                            {
                                RemotingServer rs = (RemotingServer)Pool.HtExtServer[server];
                                if (rs.Valid != RemoteServerStatus.Normal || rs.Enable == false) continue;

                                rs.FindRemoteServer(serverName);

                                if (!rs.HTServices.ContainsKey(serverName)) continue;
                                ServiceObject so = ((ServiceObject)(rs.HTServices[serverName]));
                                if (so.Valid != ServiceObjectStatus.Normal || so.Enable == false) continue;

                                RedirURL = so.URL;
                                sum_factor += rs.PriorityFactor;
                                serviceProvider.Add(server);
                                pfactors.Add(sum_factor);
                            }

                            Random rand = new Random();
                            double rand_selector = rand.NextDouble() * sum_factor;
                            int selector = 0;
                            for (int idx = 0; idx < pfactors.Count; idx++)
                            {
                                if (rand_selector <= (double)pfactors[idx])
                                {
                                    selector = idx;
                                    break;
                                }
                            }
                            if (selector != 0)
                            {
                                SimpleReturnObject _out = new SimpleReturnObject();
                                if (messageEx.InnerServerRedirect)
                                {
                                    RemotingServer rs = (RemotingServer)Pool.HtExtServer[serviceProvider[selector]];
                                    rtnObjEx = (ReturnObjectEx)rs.ExecuteMethod(messageEx, out _out);
                                    return rtnObjEx;
                                }
                                else
                                {
                                    rtnObjEx.ReDirectURL = RedirURL;
                                    return rtnObjEx;
                                }
                            }
                        }

                        //使用本地服务 
                        myMethod = Pool.GetType().GetMethod("HandleMethodEx"); ;

                        DateTime startTime = DateTime.Now;
                        if (_servConf.Debug == "true")
                        {
                            DebugLog(new object[] { className, methodName }, args);
                        }

                        ReturnObject rtnObj = (ReturnObject)myMethod.Invoke(Pool, new object[] { className, methodName, args, _objects });

                        rtnObjEx.ReDirectURL = "";
                        rtnObjEx.ErrCode = rtnObj.ErrCode;
                        rtnObjEx.ErrMessage = rtnObj.ErrMessage;
                        rtnObjEx.RealDataSet = rtnObj.RealDataSet;
                        rtnObjEx.RealObject = rtnObj.RealObject;

                        DateTime endTime = DateTime.Now;
                        TimeSpan tspan = endTime - startTime;
                        if (tspan.TotalMilliseconds > (_servConf.MethodTime * 1000))
                        {
                            MethodTimeLog(tspan, new object[] { className, methodName }, args);
                        }

                        if (rtnObjEx.RealObject != null)
                        {
                            if (rtnObjEx.RealObject.GetType() == typeof(DataSet))
                            {
                                DataSet _ds = (DataSet)rtnObjEx.RealObject;
                                bool largeData = false;

                                int row_cnt = 0;
                                foreach (DataTable _dt in _ds.Tables)
                                {
                                    row_cnt += _dt.Rows.Count;
                                    if (_dt.Rows.Count > _servConf.CompressThreshold || row_cnt > _servConf.CompressThreshold)
                                    {
                                        largeData = true;
                                        break;
                                    }
                                }

                                if (largeData)
                                {
                                    byte[] _rtn = Utility.SerializeDataSet(_ds);
                                    byte[] _rtn_comp = Utility.CompressBytes(_rtn);
                                    DataTable dt_rus = new DataTable("RETURN_RESULT");
                                    dt_rus.Columns.AddRange(new DataColumn[]{
                                    new DataColumn("IsCompressed",  System.Type.GetType("System.Int32") ),
                                    new DataColumn("UnCompress_size", System.Type.GetType("System.Int32")),
                                    new DataColumn("Compress_size", System.Type.GetType("System.Int32"))}
                                    );
                                    dt_rus.AcceptChanges();
                                    dt_rus.Rows.Add(new object[] { 1, _rtn.Length, _rtn_comp.Length });
                                    dt_rus.AcceptChanges();
                                    if (rtnObjEx.RealDataSet == null)
                                    {
                                        rtnObjEx.RealDataSet = new DataSet();
                                    }
                                    rtnObjEx.RealDataSet.Tables.Add(dt_rus);
                                    rtnObjEx.RealObject = _rtn_comp;
                                }
                            }
                        }

                        return rtnObjEx;

                    }
                    catch (Exception ex)
                    {
                        MethodErrLog(ex, new object[] { className, methodName }, args);
                        return new ReturnObjectEx(null, ex.Message);
                    }
                    finally
                    {
                        try
                        {
                            if (rtnObjEx.RealObject != null)
                            {
                                rtnObjEx.RealObject = null;
                            }
                            if (rtnObjEx.RealDataSet != null)
                            {
                                rtnObjEx.RealDataSet = null;
                            }
                        }
                        catch { }
                    }

                }
                else
                {
                    return new ReturnObjectEx(null, "未找到请求的服务！[2]");
                }
            }
            catch (Exception ex)
            {
                return new ReturnObjectEx(null, "服务调用发生异常！ \n" + ex.Message);
            }
        }
        #endregion

        #region "	Common Handler	"
        //=======================================================
        // 用来确保当创建 Singleton 时, 第一个实例永远不会过期
        //=======================================================
        public override object InitializeLifetimeService()
        {
            return null;
        }
        #endregion
    }
}
