using DevExpress.Xpf.Core.Native;
using DevExpress.Xpf.Printing;
using log4net;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using VIZ.Framework.Common;
using VIZ.Framework.Core;
using VIZ.Package.Domain;
using VIZ.Package.Plugin;
using VIZ.Package.Storage;

namespace VIZ.Package.Module
{
    /// <summary>
    /// 插件视图模型
    /// </summary>
    public class PluginViewModel : ViewModelBase, IPluginService
    {
        /// <summary>
        /// 日志
        /// </summary>
        private readonly static ILog log = LogManager.GetLogger(typeof(PluginViewModel));

        public PluginViewModel()
        {
            // 初始化命令
            this.InitCommand();

            // 初始化消息
            this.InitMessage();

            // 注册服务
            ApplicationDomainEx.ServiceManager.AddService(ViewServiceKeys.PLUGIN_SERVICE, this);
        }

        /// <summary>
        /// 初始化命令
        /// </summary>
        private void InitCommand()
        {
            this.LoadedCommand = new VCommand(this.Loaded);
        }

        /// <summary>
        /// 初始化消息
        /// </summary>
        private void InitMessage()
        {
            ApplicationDomainEx.MessageManager.Register<ProjectCloseMessage>(this, this.OnProjectCloseMessage);
            ApplicationDomainEx.MessageManager.Register<PageInitedMessage>(this, this.OnPageInitedMessage);
            ApplicationDomainEx.MessageManager.Register<PageDeleteMessage>(this, this.OnPageDeleteMessage);
            ApplicationDomainEx.MessageManager.Register<PageGroupDeleteMessage>(this, this.OnPageGroupDeleteMessage);
        }

        // ========================================================================
        // Property
        // ========================================================================

        #region SelectedValue -- 当前选择项

        private PluginNavigationConfig selectedValue;
        /// <summary>
        /// 当前选择项
        /// </summary>
        public PluginNavigationConfig SelectedValue
        {
            get { return selectedValue; }
            set { selectedValue = value; this.RaisePropertyChanged(nameof(SelectedValue)); }
        }

        #endregion

        #region ItemsSource -- 数据源

        private ObservableCollection<PluginNavigationConfig> itemsSource = new ObservableCollection<PluginNavigationConfig>();
        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<PluginNavigationConfig> ItemsSource
        {
            get { return itemsSource; }
            set { itemsSource = value; this.RaisePropertyChanged(nameof(ItemsSource)); }
        }

        #endregion

        // ========================================================================
        // Command
        // ========================================================================

        #region LoadedCommand -- 加载命令

        /// <summary>
        /// 加载命令
        /// </summary>
        public VCommand LoadedCommand { get; set; }

        /// <summary>
        /// 加载
        /// </summary>
        private void Loaded()
        {
            if (this.IsAlreadyLoaded)
                return;

            // 获取插件映射配置
            PluginMappingConfigEntity config = ApplicationDomainEx.LocalDbContext.PluginMappingConfig.FindOne(p => p.PluginGroup == ApplicationDomainEx.VizConfig.PluginGroup);
            if (config == null)
            {
                config = new PluginMappingConfigEntity();
                config.PluginGroup = ApplicationDomainEx.VizConfig.PluginGroup;
                config.Mappings = new List<PluginMapping>();

                ApplicationDomainEx.LocalDbContext.PluginMappingConfig.Insert(config);
            }

            ApplicationDomainEx.PluginMappingConfig = config;

            this.IsAlreadyLoaded = true;
        }

        #endregion

        // ========================================================================
        // Message
        // ========================================================================

        /// <summary>
        /// 项目关闭消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnProjectCloseMessage(ProjectCloseMessage msg)
        {
            this.SelectedValue = null;

            foreach (NavigationConfig config in this.ItemsSource)
            {
                if (config.View == null || !config.View.TryGetTarget(out object target))
                    continue;

                if (!(target is IPluginView view))
                    continue;

                try
                {
                    view.Dispose();
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                }
            }
        }

        /// <summary>
        /// 页初始化完成消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageInitedMessage(PageInitedMessage msg)
        {
            // 页模板没有插件
            if (msg.Page == null || msg.Page is PageTemplateModel)
            {
                this.SelectedValue = null;
                return;
            }

            // 页拥有插件
            PageModel page = msg.Page as PageModel;

            PluginNavigationConfig config = this.ItemsSource.FirstOrDefault(p => p.Key == page.PageID.ToString());
            if (config != null)
            {
                this.SelectedValue = config;
                return;
            }

            PluginInfo plugin = ApplicationDomainEx.PluginInfos.FirstOrDefault(p => p.ID == page.PluginID && p.Group == ApplicationDomainEx.VizConfig.PluginGroup);
            if (plugin == null)
            {
                this.SelectedValue = null;
                return;
            }

            config = new PluginNavigationConfig();
            config.Key = page.PageID.ToString();
            config.ViewType = plugin.ViewType;
            config.PageModel = page;
            config.PluginInfo = plugin;

            this.ItemsSource.Add(config);

            this.SelectedValue = config;
        }

        /// <summary>
        /// 页删除消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageDeleteMessage(PageDeleteMessage msg)
        {
            if (msg.Pages == null || msg.Pages.Count == 0)
                return;

            foreach (PageModelBase page in msg.Pages)
            {
                PluginNavigationConfig config = this.ItemsSource.FirstOrDefault(p => p.PageModel == page);
                if (config == null)
                    return;

                this.ItemsSource.Remove(config);
            }
        }

        /// <summary>
        /// 页分组删除消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageGroupDeleteMessage(PageGroupDeleteMessage msg)
        {
            if (msg.PageGroup == null || msg.PageGroup.Pages == null)
                return;

            foreach (PageModel page in msg.PageGroup.Pages)
            {
                PluginNavigationConfig config = this.ItemsSource.FirstOrDefault(p => p.PageModel == page);
                if (config == null)
                    continue;

                this.ItemsSource.Remove(config);
            }
        }

        // ========================================================================
        // Public Function
        // ========================================================================

        /// <summary>
        /// 获取当前插件视图
        /// </summary>
        /// <returns>当前插件视图</returns>
        public object GetCurrentPluginView()
        {
            if (this.SelectedValue == null)
                return null;

            this.SelectedValue.View.TryGetTarget(out object target);

            return target;
        }

        /// <summary>
        /// 根据视图获取页模型
        /// </summary>
        /// <param name="view">视图</param>
        /// <returns>页ID</returns>
        public PageModel GetPageModelFromView(IPluginView view)
        {
            foreach (PluginNavigationConfig config in this.ItemsSource)
            {
                if (config.View == null)
                    continue;

                config.View.TryGetTarget(out object target);
                if (target == null)
                    continue;

                IPluginView item = target as IPluginView;
                if (item == null)
                    continue;

                if (item == view)
                    return config.PageModel;
            }

            return null;
        }

        /// <summary>
        /// 获取所有的插件视图
        /// </summary>
        /// <returns>插件视图</returns>
        public List<IPluginView> GetPluginViews()
        {
            List<IPluginView> list = new List<IPluginView>();

            foreach (NavigationConfig config in this.ItemsSource)
            {
                config.View.TryGetTarget(out object target);
                if (target == null)
                    continue;

                IPluginView item = target as IPluginView;
                if (item == null)
                    continue;

                list.Add(item);
            }

            return list;
        }

        /// <summary>
        /// 根据页模型获取插件视图
        /// </summary>
        /// <param name="page">页模型</param>
        /// <returns>插件视图</returns>

        public IPluginView GetPluginView(PageModel page)
        {
            foreach (PluginNavigationConfig config in this.ItemsSource)
            {
                if (config.PageModel != page)
                    continue;

                config.View.TryGetTarget(out object target);
                if (target == null)
                    return null;

                return target as IPluginView;
            }

            return null;
        }

        /// <summary>
        /// 获取插件视图
        /// </summary>
        /// <typeparam name="T">插件视图类型</typeparam>
        /// <returns>插件视图</returns>
        public List<T> GetPluginViews<T>() where T : class, IPluginView
        {
            List<T> list = new List<T>();

            foreach (NavigationConfig config in this.ItemsSource)
            {
                config.View.TryGetTarget(out object target);
                if (target == null)
                    continue;

                T item = target as T;
                if (item == null)
                    continue;

                list.Add(item);
            }

            return list;
        }
    }
}
