using System;
using System.Collections.Generic;
using Mesnac.Basic;
using System.Text;
using System.IO;
using System.Xml;
using System.Windows.Forms;
using System.Reflection;
using System.Data.Common;
using ICSharpCode.Core;
using ICSharpCode.Data.Core;
using ICSharpCode.Data.Core.Common;
using ICSharpCode.Data.Core.Interfaces;
using ICSharpCode.Data.Core.DatabaseObjects;
using ICSharpCode.Data.Core.Enums;

using Mesnac.Codd.Session;

namespace Mesnac.Basic
{
    public delegate void CallBackDelegate();        //回调方法
    /// <summary>
    /// 数据源工厂
    /// </summary>
    public class DataSourceFactory
    {
        private static DataSourceFactory instance = null;           //保存工厂实例
        private Dictionary<string, DataSourceItem> _dataSources = null;         //保存数据源
        private TreeNode root = null;
        public event EventHandler DataSourceRefresh;

        private DataSourceFactory()
        {
            
            this.root = new TreeNode();
            root.Text = StringParser.Parse(ResourceService.GetString("Mesnac_Basic_DataSourceFactory_Root_Text")); //"数据源列表";
        }
        /// <summary>
        /// 工厂实例
        /// </summary>
        public static DataSourceFactory Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new DataSourceFactory();
                }
                return instance;
            }
        }
        /// <summary>
        /// 把内存中的数据源数据保存只文件
        /// </summary>
        /// <param name="fileName">要保存数据源信息的文件名</param>
        public void RefreshDataFromFile(string fileName, params CallBackDelegate[] callBack)
        {
            if (System.IO.File.Exists(fileName))
            {
                this._dataSources = XmlHandler.ParseFromDataSourceXml(fileName);
                //触发事件
                if (DataSourceRefresh != null)
                {
                    DataSourceRefresh(this, EventArgs.Empty);
                }
                //
                if (Mesnac.Basic.AppConfigHelper.GetAppSettingValue("IsLoadDataSourceTree", true))
                {
                    new System.Threading.Thread(new System.Threading.ThreadStart(delegate()
                    {
                        LanguageHelper.RefreshCultureInfo();
                        this.GenerateDataSourceTree();
                        foreach (CallBackDelegate call in callBack)
                        {
                            call();
                        }
                    })).Start();   //异步生成数据源树
                }
            }
            else
            {
                this._dataSources = new Dictionary<string, DataSourceItem>();
            }
        }
        /// <summary>
        /// 把文件中的内容读取至内存
        /// </summary>
        /// <param name="fileName">保存数据源信息的文件名</param>
        public void RefreshDataToFile(string fileName, params CallBackDelegate[] callBack)
        {
            if (this._dataSources != null)
            {
                XmlHandler.GenerateDataSourceXml(this._dataSources, fileName);
                new System.Threading.Thread(new System.Threading.ThreadStart(delegate() {
                    LanguageHelper.RefreshCultureInfo();
                    this.GenerateDataSourceTree(); 
                    foreach (CallBackDelegate call in callBack) 
                    { 
                        call(); 
                    } 
                })).Start();   //异步生成数据源树
            }
        }
        /// <summary>
        /// 数据源信息
        /// </summary>
        public Dictionary<string, DataSourceItem> DataSources
        {
            get
            {
                return this._dataSources;
            }
        }

        /// <summary>
        /// 数据源树
        /// </summary>
        public TreeNode Root
        {
            get { return this.root; }
        }

        /// <summary>
        /// 生成数据源树
        /// </summary>
        public void GenerateDataSourceTree()
        {
            lock (this)
            {
                try
                {
                    DateTime begin = DateTime.Now;
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Debug("GenerateDataSourceTree begin");

                    this.root.Nodes.Clear();
                    this.root = new TreeNode();
                    this.root.Text = StringParser.Parse(ResourceService.GetString("Mesnac_Basic_DataSourceFactory_Root_Text")); //"数据源列表";
                    if (this._dataSources != null)
                    {
                        TreeNode nodeDataSource = null;
                        int cnt = 0;
                        DataSourceItem[] dataSourceArr = new DataSourceItem[this._dataSources.Count];
                        this._dataSources.Values.CopyTo(dataSourceArr, 0);
                        foreach (DataSourceItem dataSourceItem in dataSourceArr)
                        {
                            nodeDataSource = new TreeNode();
                            nodeDataSource.Text = dataSourceItem.Name;
                            nodeDataSource.ToolTipText = dataSourceItem.Driver;

                            #region 数据源处理
                            //string driverAssembly = dataSourceItem.DriverAssembly;//.Split( new char[] { ',' } )[ 0 ];
                            //string driverClass = dataSourceItem.DriverClass;
                            //System.Runtime.Remoting.ObjectHandle obj = Activator.CreateInstance(driverAssembly, driverClass) as System.Runtime.Remoting.ObjectHandle;
                            string driverAssembly = dataSourceItem.DriverAssembly.IndexOf(",") > 0 ? dataSourceItem.DriverAssembly.Split(new char[] { ',' })[0] : dataSourceItem.DriverAssembly;//.Split( new char[] { ',' } )[ 0 ];
                            string path = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
                            path = new System.IO.FileInfo(path).Directory.FullName;
                            path = Path.Combine(path, "DynamicLib", "DataBaseDriver", driverAssembly + ".dll");
                            string driverClass = dataSourceItem.DriverClass;
                            System.Runtime.Remoting.ObjectHandle obj = Activator.CreateInstanceFrom(path, driverClass) as System.Runtime.Remoting.ObjectHandle;

                            IDatabaseDriver driver = obj.Unwrap() as IDatabaseDriver;
                            IDatasource ds = driver.CreateNewIDatasource(dataSourceItem.Server, dataSourceItem.UserName, dataSourceItem.Password);

                            driver.PopulateDatabases(ds);
                            IDatabase database = null;
                            if (ds.Databases != null)
                            {
                                foreach (IDatabase db in ds.Databases)
                                {
                                    if (db.ToString() == dataSourceItem.Database)
                                    {
                                        database = db;
                                        break;
                                    }
                                }
                                if (database != null)
                                {
                                    database.LoadDatabase();
                                    TreeNode nodeTables = new TreeNode();
                                    nodeTables.Text = StringParser.Parse(ResourceService.GetString("Mesnac_Basic_DataSourceFactory_nodeTables_Text"));  //"数据表";
                                    TreeNode nodeTable = null;
                                    foreach (ITable table in database.Tables)
                                    {
                                        nodeTable = new TreeNode();
                                        nodeTable.Text = table.TableName;

                                        TreeNode nodeColumn = null;
                                        foreach (IColumn col in table.Items)
                                        {
                                            nodeColumn = new TreeNode();
                                            nodeColumn.Text = col.Name;
                                            nodeTable.Nodes.Add(nodeColumn);
                                        }

                                        nodeTables.Nodes.Add(nodeTable);
                                    }

                                    TreeNode nodeViews = new TreeNode();
                                    nodeViews.Text = StringParser.Parse(ResourceService.GetString("Mesnac_Basic_DataSourceFactory_nodeViews_Text")); //"视图";
                                    TreeNode nodeView = null;
                                    if (database.Views != null && database.Views.Count > 0)
                                    {
                                        foreach (IView view in database.Views)
                                        {
                                            nodeView = new TreeNode();
                                            nodeView.Text = view.Name;
                                            TreeNode nodeColumn = null;
                                            foreach (IColumn col in view.Items)
                                            {
                                                nodeColumn = new TreeNode();
                                                nodeColumn.Text = col.Name;
                                                nodeView.Nodes.Add(nodeColumn);
                                            }
                                            nodeViews.Nodes.Add(nodeView);
                                        }
                                    }

                                    TreeNode nodeProcedures = new TreeNode();
                                    nodeProcedures.Text = StringParser.Parse(ResourceService.GetString("Mesnac_Basic_DataSourceFactory_nodeProcedures_Text")); //"存储过程";
                                    TreeNode nodeProcedure = null;
                                    if (database.Procedures != null && database.Procedures.Count > 0)
                                    {
                                        foreach (IProcedure procedure in database.Procedures)
                                        {
                                            nodeProcedure = new TreeNode();
                                            nodeProcedure.Text = procedure.Name;
                                            nodeProcedures.Nodes.Add(nodeProcedure);
                                        }
                                    }

                                    nodeDataSource.Nodes.Add(nodeTables);
                                    nodeDataSource.Nodes.Add(nodeViews);
                                    nodeDataSource.Nodes.Add(nodeProcedures);
                                }
                            }
                            #endregion

                            cnt++;
                            if (cnt > dataSourceArr.Length)
                                break;

                            this.root.Nodes.Add(nodeDataSource);
                        }
                    }

                    TimeSpan ts = DateTime.Now - begin;
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Debug("GenerateDataSourceTree end complete = " + ts);
                }
                catch (Exception ex)
                {
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Error("获取数据源列表失败:" + ex.Message, ex);
                }
            }
        }
        /// <summary>
        /// 添加数据源
        /// </summary>
        /// <param name="name"></param>
        /// <param name="item"></param>
        public void Add(string name, DataSourceItem item)
        {
            if (this._dataSources == null)
            {
                this._dataSources = new Dictionary<string, DataSourceItem>();
            }
            if (!this.IsExists(name))
            {
                this._dataSources.Add(name, item);
                //触发事件
                if (DataSourceRefresh != null)
                {
                    DataSourceRefresh(this, EventArgs.Empty);
                }
            }
        }
        /// <summary>
        /// 移除数据源
        /// </summary>
        /// <param name="name"></param>
        public void Remove(string name)
        {
            if (this.IsExists(name))
            {
                this._dataSources.Remove(name);
                //触发事件
                if (DataSourceRefresh != null)
                {
                    DataSourceRefresh(this, EventArgs.Empty);
                }
            }
        }
        /// <summary>
        /// 修改数据源
        /// </summary>
        /// <param name="name"></param>
        /// <param name="newItem"></param>
        public void Modify(string name, DataSourceItem newItem)
        {
            if (this._dataSources == null)
            {
                this._dataSources = new Dictionary<string, DataSourceItem>();
            }
            if (this.IsExists(name))
            {
                this._dataSources[name] = newItem;
                //触发事件
                if (DataSourceRefresh != null)
                {
                    DataSourceRefresh(this, EventArgs.Empty);
                }
            }
        }
        /// <summary>
        /// 获取下一个可用的数据源名称
        /// </summary>
        /// <returns></returns>
        public string GetNextDataSourceName()
        {
            int i = 1;
            if (this._dataSources == null)
            {
                return "DataSource1";
            }
            else
            {
                while (this._dataSources.ContainsKey("DataSource" + i))
                {
                    i++;
                }
            }
            return "DataSource" + i;
        }
        /// <summary>
        /// 判断指定名称的数据源是否存在
        /// </summary>
        /// <param name="dataSourceName">要判断的数据源名称</param>
        /// <returns>存在返回true,否则返回false</returns>
        public bool IsExists(string dataSourceName)
        {
            if (this._dataSources == null)
            {
                return false;
            }
            else
            {
                if (this._dataSources.ContainsKey(dataSourceName))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        #region DbHelper

        /// <summary>
        /// 创建数据提供程序工厂对象
        /// </summary>
        /// <param name="assemblyFile">数据提供程序工厂类所在的程序集文件路径</param>
        /// <param name="providerName">数据提供程序工厂类名称</param>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <returns></returns>
        public DbProviderFactory CreateDbProviderFactory(string assemblyFile, string providerName)
        {
            try
            {
                DbProviderFactory factory = null;
                Assembly assemblyInstance = Assembly.LoadFrom(assemblyFile);
                Type providerFactoryType = assemblyInstance.GetType(providerName);
                FieldInfo factoryInstance = providerFactoryType.GetField("Instance");
                if (factoryInstance != null)
                {
                    factory = factoryInstance.GetValue(null) as DbProviderFactory;
                    //ICSharpCode.Core.LoggingService<DataSourceFactory>.Debug("创建DbProviderFactory成功!");
                }
                return factory;
            }
            catch (Exception ex)
            {
                ICSharpCode.Core.LoggingService<DataSourceFactory>.Error("创建DbProviderFactory错误:" + ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 获取操作系统位版本(32位、64位)
        /// </summary>
        /// <returns>返回操作系统版本32、64</returns>
        public string GetWinVersion()
        {
            bool type;
            type = Environment.Is64BitOperatingSystem;
            if (type)
            {
                return "64";
            }
            else
            {
                return "32";
            }
        }

        /// <summary>
        /// 获取DbHelper
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public DbHelper GetDbHelper(DataSourceItem item)
        {
            string path = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
            path = new System.IO.FileInfo(path).Directory.FullName;

            DbProviderFactory dbProviderFactory = null;
            if (item.Driver.Replace(" ", "").ToLower() == "mssqlserver")
            {
                string constr = "Persist Security Info=True;Password=" + item.Password
                    + ";User ID=" + item.UserName + ";Initial Catalog=" + item.Database
                    + ";Data Source=" + item.Server + ";Connection Timeout=" + item.ConnectionTimeout;
                string assemblyFile = Path.Combine(path, "DynamicLib", "DataBase", "SQLServer", "System.Data.dll");
                if (!File.Exists(assemblyFile))
                {
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Warn("获取SQLServer连接失败,缺少依赖文件:" + assemblyFile);
                    return null;
                }
                dbProviderFactory = this.CreateDbProviderFactory(assemblyFile, "System.Data.SqlClient.SqlClientFactory");
                DbSession dbsession = new DbSession(dbProviderFactory, constr);
                DbHelper Result = new DbHelper(dbsession);
                return Result;
            }
            else if (item.Driver.Replace(" ", "").ToLower() == "oracle")
            {
                string constr = "Data Source={0};Persist Security Info=True;User ID={1};Password={2}";
                constr = String.Format(constr, item.Server, item.UserName, item.Password);
                string assemblyFile = Path.Combine(path, "DynamicLib", "DataBase", "Oracle", "Oracle.ManagedDataAccess.dll");
                if (!File.Exists(assemblyFile))
                {
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Warn("获取Oracle连接失败,缺少依赖文件:" + assemblyFile);
                    return null;
                }
                dbProviderFactory = this.CreateDbProviderFactory(assemblyFile, "Oracle.ManagedDataAccess.Client.OracleClientFactory");
                DbSession dbsession = new DbSession(dbProviderFactory, constr);
                DbHelper Result = new DbHelper(dbsession);
                return Result;
            }
            else if (item.Driver.Replace(" ", "").ToLower() == "mysql")
            {
                string constr = "Persist Security Info=True;Password=" + item.Password
                    + ";User ID=" + item.UserName + ";Initial Catalog=" + item.Database
                    + ";Data Source=" + item.Server;
                string assemblyFile = Path.Combine(path, "DynamicLib", "DataBase", "MySql", "MySql.Data.dll");
                if (!File.Exists(assemblyFile))
                {
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Warn("获取MySql连接失败,缺少依赖文件:" + assemblyFile);
                    return null;
                }
                //DbSession dbsession = new DbSession(MySql.Data.MySqlClient.MySqlClientFactory.Instance, constr);
                dbProviderFactory = this.CreateDbProviderFactory(assemblyFile, "MySql.Data.MySqlClient.MySqlClientFactory");
                DbSession dbsession = new DbSession(dbProviderFactory, constr);
                DbHelper Result = new DbHelper(dbsession);
                return Result;
            }
            else if (item.Driver.Replace(" ", "").ToLower() == "access")
            {
                string constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + item.Server
                    + ";User ID=" + item.UserName + ";Jet OLEDB:Database Password=" + item.Password;
                DbSession dbsession = new DbSession(System.Data.OleDb.OleDbFactory.Instance, constr);
                DbHelper Result = new DbHelper(dbsession);
                return Result;
            }
            else
            {
                string constr = "Persist Security Info=True;Password=" + item.Password
                    + ";User ID=" + item.UserName + ";Initial Catalog=" + item.Database
                    + ";Data Source=" + item.Server;
                string assemblyFile = Path.Combine(path, "DynamicLib", "DataBase", "SQLServer", "System.Data.dll");
                if (!File.Exists(assemblyFile))
                {
                    ICSharpCode.Core.LoggingService<DataSourceFactory>.Warn("获取SQLServer连接失败,缺少依赖文件:" + assemblyFile);
                    return null;
                }
                //DbSession dbsession = new DbSession(MySql.Data.MySqlClient.MySqlClientFactory.Instance, constr);
                dbProviderFactory = this.CreateDbProviderFactory(assemblyFile, "System.Data.SqlClient.SqlClientFactory");
                DbSession dbsession = new DbSession(dbProviderFactory, constr);
                DbHelper Result = new DbHelper(dbsession);
                return Result;
            }
        }
        public DbHelper GetDbHelper(string dbName)
        {
            DataSourceItem item;
            if (DataSourceFactory.Instance.DataSources != null && DataSourceFactory.Instance.DataSources.TryGetValue(dbName, out item))
            {
                return GetDbHelper(item);
            }
            return null;
        }
        /// <summary>
        /// 获取数据源组
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        public DataSourceItem GetDataSourceItem(MCDbType dbType)
        {
            string dbName = this.GetDataSourceName(dbType);
            DataSourceItem item;
            if (DataSourceFactory.Instance.DataSources != null && DataSourceFactory.Instance.DataSources.TryGetValue(dbName, out item))
            {
                return item;
            }
            return null;
        }

        public DbHelper GetDbHelper(MCDbType dbType)
        {
            string dbName = this.GetDataSourceName(dbType);
            return this.GetDbHelper(dbName);
        }

        #region GetConfigValue
        /// <summary>
        /// 数据库枚举类型
        /// </summary>
        public enum MCDbType
        {
            /// <summary>
            /// 本地库
            /// </summary>
            Local,
            /// <summary>
            /// 本地曲线库
            /// </summary>
            Curve,
            /// <summary>
            /// MES中间数据库
            /// </summary>
            MesInterface
            /// <summary>
            /// 回放数据库
            /// </summary>
            //BackView
        }
        /// <summary>
        /// 根据数据枚举类型获取数据源名称的方法
        /// </summary>
        /// <param name="dbtype">数据库枚举类型对象</param>
        /// <returns>返回对应的数据源名称</returns>
        public string GetDataSourceName(MCDbType dbtype)
        {
            switch (dbtype)
            {
                case MCDbType.Local:
                    return RunSchema.Instance.GetConfigValue("DataSource.Local", "DataSource1");
                case MCDbType.Curve:
                    return RunSchema.Instance.GetConfigValue("DataSource.Curve", "DataSource2");
                case MCDbType.MesInterface:
                    return RunSchema.Instance.GetConfigValue("DataSource.MesInterface", "DataSource3");
                default:
                    return RunSchema.Instance.GetConfigValue("DataSource.Local", "DataSource1");
            }
        }
        #endregion

        #endregion
    }
}