using System;
using System.Threading;
using System.Collections;
using System.Reflection;

using Core.Mes.IBaseInterface;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Core.Mes.ServerFrameWork
{
    /// <summary>
    /// 容器型服务的统一接口
    /// </summary>
    public class IServerPool : MarshalByRefObject, IServerBase
    {
        #region IServerBase 成员

        public string Description
        {
            get
            {
                // TODO:  添加 IServerPool.Description getter 实现
                return null;
            }
        }

        private ArrayList _objects = null;
        public ArrayList OwnObjects
        {
            get { return _objects; }
            set { _objects = value; }
        }

        private Hashtable _dbManager = null;
        public Hashtable DBManagerList
        {
            get { return _dbManager; }
            set { _dbManager = value; }
        }

        private Hashtable _htServiceKeys = null;
        public Hashtable HTServiceKeys
        {
            get { return _htServiceKeys; }
            set { _htServiceKeys = value; }
        }

        private Hashtable _htComponent = new Hashtable();
        public Hashtable HtComponent
        {
            get { return _htComponent; }
            set { _htComponent = value; }
        }

        private SrvDaemon _srvDaemon = null;
        public SrvDaemon srvDaemon
        {
            get { return _srvDaemon; }
            set { _srvDaemon = value; }
        }

        private Hashtable _htExtServer = null;
        public Hashtable HtExtServer
        {
            get { return _htExtServer; }
            set { _htExtServer = value; }
        }

        private ServerConfigure _servConf = null;
        public ServerConfigure ServerConfig
        {
            get { return _servConf; }
            set { _servConf = value; }
        }
        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            System.Collections.IEnumerator ie = this.HtComponent.GetEnumerator();

            while (ie.MoveNext())
            {
                try
                {
                    System.Collections.DictionaryEntry de = (DictionaryEntry)ie.Current;
                    DisposeClass((Hashtable)de.Value, 0);
                    DisposeClass((Hashtable)de.Value, 1);
                }
                catch { }
            }
        }
        private void DisposeClass(Hashtable ht, int index)
        {
            try
            {
                ArrayList al = ht[index] as ArrayList;
                int count = al.Count;
                for (int i = 0; i < al.Count; i++)
                {
                    try
                    {
                        ((IComponent)al[0]).Dispose();
                    }
                    catch { }
                }
            }
            catch { }
        }

        Assembly assembly = null;
        public bool LoadAllClass(string dll_file, string dbName)
        {
            if (!File.Exists(dll_file)) return false;
            try
            {
                assembly = Assembly.LoadFile(dll_file);
                foreach (Type type in assembly.GetTypes())
                {
                    if (type.IsClass && type.IsSubclassOf(typeof(IComponent)))
                    {
                        LoadClass(type, dbName);
                    }
                }
                return true;
            }
            catch { return false; }
        }
        //=======================================================
        // 加载单个类,并按最小副本数生成多个类的实例
        //	classPoolHash 0--闲列表	1-忙列表	2--最小副本数	3--最大副本数
        //=======================================================
        public void LoadClass(Type moduleType, string dataBaseName)
        {
            try
            {
                string className = moduleType.FullName;
                //== 反射类
                IComponent module = (IComponent)Activator.CreateInstance(moduleType);
                module.DBName = dataBaseName;
                module.DBManagerList = this.DBManagerList;
                module.HTServiceKeys = this.HTServiceKeys;
                module.ServerConfig = this.ServerConfig;
                module.OwnObjects = this._objects;

                int maxCopyValue = module.maxValue;
                int minCopyValue = module.minValue;

                Hashtable classPoolHash = (Hashtable)HtComponent[className];

                if (classPoolHash == null)
                {
                    classPoolHash = new Hashtable();
                    HtComponent.Add(className, classPoolHash);
                }

                //存储每个类的空闲列表
                ArrayList freeList = classPoolHash[0] as ArrayList;
                if (freeList == null)
                {
                    freeList = new ArrayList();
                    classPoolHash.Add(0, freeList);
                }

                //存储一个空忙列表
                ArrayList busyList = classPoolHash[1] as ArrayList;
                if (busyList == null)
                {
                    busyList = new ArrayList();
                    classPoolHash.Add(1, busyList);
                }

                //加入最小副本数个副本到空闲列表
                freeList.Add(module);

                if (minCopyValue < 1) minCopyValue = 1;

                for (int i = 0; i < minCopyValue - 1; i++)
                {
                    IComponent classObj = (IComponent)Activator.CreateInstance(moduleType);

                    classObj.DBName = dataBaseName;
                    classObj.DBManagerList = this.DBManagerList;
                    classObj.HTServiceKeys = this.HTServiceKeys;
                    classObj.ServerConfig = this.ServerConfig;
                    classObj.OwnObjects = _objects;

                    freeList.Add(classObj);
                }

                //加入最大，最小副本值
                classPoolHash.Add(2, maxCopyValue);
                classPoolHash.Add(3, minCopyValue);
                classPoolHash.Add(4, dataBaseName);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        #endregion

        private string _serverName = "";
        public string ServerName
        {
            get { return _serverName; }
            set { _serverName = value; }
        }
        private string _assemblyName = "";
        public string AssemblyName
        {
            get { return _assemblyName; }
            set { _assemblyName = value; }
        }

        public ReturnObject HandleMethod(string className, string methodName, object[] args)
        {
            //查找对应的业务组件子服务
            Result structObj = this.searchObject(className, methodName);

            if (structObj.busy.Equals("Error"))
            {
                //无此所访问的类
                return new ReturnObject(null, 10003, "未找到请求的服务！[1]");
            }
            else if (structObj.busy.Equals("Wait"))
            {
                //达到最大访问限制，等待，超过规定时间放弃
                int i = 1;
                while (structObj.busy.Equals("Wait"))
                {
                    if ((i++) > 30)
                    {
                        //3秒后放弃，超时返回
                        return new ReturnObject(null, 10001, "服务正忙，请稍后再试！");
                    }
                    Thread.Sleep(100);
                    structObj = this.searchObject(className, methodName);
                }
            }

            //得到正确的副本后...
            //设置相关信息
            Type type = structObj.obj.GetType();
            IComponent component = (IComponent)(structObj.obj);

            component.CallingMethodStartTime = DateTime.Now;
            component.CallingClass = type.FullName;

            //执行方法
            MethodInfo mthod = type.GetMethod(methodName);
            object myReturnObj;

            if (mthod == null)
            {
                myReturnObj = new ReturnObject(null, 10002, string.Format("调用的方法不存在，请检查方法名是否正确！\nServerName=[{0}]\nMethod=[{1}]", className, methodName));
            }
            else
            {
                try
                {

                    myReturnObj = mthod.Invoke(structObj.obj, args);
                }
                catch (Exception ex)
                {
                    if (((IComponent)(structObj.obj)).DBManager == null)
                    {
                        myReturnObj = new ReturnObject(null, 20000, "数据库链接不存在！ 请检查服务器链接配置[DBManager]");
                    }
                    else
                    {
                        myReturnObj = new ReturnObject(null, ex.Message);
                    }
                }
            }

            //释放副本
            this.realeasObject(className, structObj.obj as IComponent);

            if (myReturnObj.GetType().Equals(typeof(ReturnObject)))
                return (ReturnObject)myReturnObj;
            else
                return new ReturnObject(myReturnObj, 10005, "未按指定的类型定义返回值！");
        }

        public ReturnObject HandleMethodEx(string className, string methodName, object[] args, ArrayList _objs)
        {
            _objects = _objs;

            return HandleMethod(className, methodName, args);
        }

        private IComponent RequestServerResource(string className, string methodName)
        {
            if (srvDaemon == null) return null;
            string _sName = this.ServerName.Trim().ToUpper();
            string _cName = string.IsNullOrEmpty(className.Trim()) ? "" : "." + className.Trim().ToUpper();
            string _mName = string.IsNullOrEmpty(methodName.Trim()) ? "" : "." + methodName.Trim().ToUpper();
            string _name = _sName + _cName + _mName;

            double OccupyMem = 30.0;
            if (srvDaemon.SrvClassManager.ContainsKey(_name))
            {
                SrvClassInfo sci = (SrvClassInfo)(srvDaemon.SrvClassManager[_name]);
                OccupyMem = sci.AvgMemUsed;
            }

            SystemInfo si = new SystemInfo();
            if ((double)(si.MemoryAvailable / 1024 / 1024) - OccupyMem < ServerConfig.PreserveSystemMemory) return null;

            Assembly ab = Assembly.Load(this.AssemblyName);
            Type tp = ab.GetType(className);
            IComponent newObj = (IComponent)Activator.CreateInstance(tp);

            return newObj;
        }

        private Result searchObject(string className)
        {
            return searchObject(className, "");
        }

        private Result searchObject(string className, string methodName)
        {
            string busy = "Success";
            string err = "";

            Hashtable poolHash = (Hashtable)this.HtComponent[className];

            if (poolHash == null)
            {
                busy = "Error";
                err = "no the class";
                Result result = new Result(busy, err, null);
                return result;
            }
            lock (poolHash)
            {
                //取出空闲和忙列表
                ArrayList frList = poolHash[0] as ArrayList;
                ArrayList bsyList = poolHash[1] as ArrayList;
                if (bsyList == null)
                {
                    bsyList = new ArrayList();
                    poolHash.Add(1, bsyList);
                }
                //如果无空闲副本，且忙列表超过最大副本数目，等待后重新请求
                //否则返回空闲副本
                if (frList.Count > 0)
                {
                    IComponent temp = (IComponent)frList[0];

                    bsyList.Add(temp);
                    frList.RemoveAt(0);
                    Result result = new Result(busy, err, temp);

                    return result;
                }

                //创建并返回新副本
                IComponent newObj = RequestServerResource(className, methodName);
                if (newObj != null)
                {
                    newObj.DBManagerList = this.DBManagerList;
                    newObj.DBName = poolHash[4].ToString();
                    newObj.HTServiceKeys = this.HTServiceKeys;
                    newObj.ServerConfig = this.ServerConfig;
                    newObj.OwnObjects = _objects;

                    bsyList.Add(newObj);
                    Result result = new Result("Success", "", newObj);
                    return result;
                }

                //最大，等待
                if (bsyList.Count == Convert.ToInt16(poolHash[2]))
                {
                    busy = "Wait";
                    Result result = new Result(busy, err, null);
                    return result;
                }

                if (bsyList.Count < Convert.ToInt16(poolHash[2]))
                {
                    Assembly ab = Assembly.Load(this.AssemblyName);
                    Type tp = ab.GetType(className);
                    newObj = (IComponent)Activator.CreateInstance(tp);
                    newObj.DBManagerList = this.DBManagerList;
                    newObj.DBName = poolHash[4].ToString();
                    newObj.HTServiceKeys = this.HTServiceKeys;
                    newObj.ServerConfig = this.ServerConfig;
                    newObj.OwnObjects = _objects;

                    bsyList.Add(newObj);
                    Result result = new Result(busy, err, newObj);
                    return result;
                }
                return new Result("", "", null);
            }
        }

        public string realeasObject(string className, IComponent busyObj)
        {
            string err = "success";

            Hashtable poolHash = (Hashtable)this.HtComponent[className];

            if (poolHash == null)
            {
                err = "no the class";
                return err;
            }

            lock (poolHash)
            {
                //移入空闲列表
                ArrayList frList = poolHash[0] as ArrayList;
                ArrayList bsyList = poolHash[1] as ArrayList;

                //如果空闲副本数目大于最小副本数目，销毁生存期较长副本
                if (frList.Count > Convert.ToInt16(poolHash[3]))
                {
                    bsyList.Remove(busyObj);
                    busyObj.Dispose();
                    busyObj = null;
                    return err;
                }
                else
                {
                    bsyList.Remove(busyObj);
                    frList.Add(busyObj);
                }
                return err;
            }
        }


        private string MD5key = "";
        public string MD5_KEY
        {
            get { return MD5key; }
        }
        private string SHA256key = "";
        public string SHA256_KEY
        {
            get { return SHA256key; }
        }

        public void GetFileKey(string filename, out string _MD5key, out string _SHA256key)
        {
            _MD5key = "";
            _SHA256key = "";
            if (!File.Exists(filename)) return;

            FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] b_md5 = md5.ComputeHash(file);
            file.Seek(0, SeekOrigin.Begin);
            byte[] b_sha256 = SHA256Managed.Create().ComputeHash(file);
            file.Close();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < b_md5.Length; i++)
            {
                sb.Append(b_md5[i].ToString("x2"));
            }
            MD5key = sb.ToString();

            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < b_sha256.Length; i++)
            {
                builder.Append(b_sha256[i].ToString("X2"));
            }
            SHA256key = builder.ToString();

            _MD5key = MD5_KEY;
            _SHA256key = SHA256_KEY;
        }

        public struct Result
        {
            public string busy;
            public string err;
            public object obj;

            public Result(string busy, string err, object obj)
            {
                this.busy = busy;
                this.err = err;
                this.obj = obj;
            }
        }
    }
}
