using DevExpress.Data;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VIZ.Framework.Core;
using VIZ.Package.Domain;
using VIZ.Package.Plugin;
using VIZ.Package.Service;

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

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

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

        /// <summary>
        /// 初始化命令
        /// </summary>
        private void InitCommand()
        {
            this.TakeCommand = new VCommand(this.Take);
            this.ContinueCommand = new VCommand(this.Continue);
            this.TakeOutCommand = new VCommand(this.TakeOut);
            this.UpdateCommand = new VCommand(this.Update);
        }

        // ==============================================================
        // Service & Controller
        // ==============================================================

        /// <summary>
        /// Viz引擎命令服务
        /// </summary>
        private VizCommandService vizCommandService = new VizCommandService();

        /// <summary>
        /// Viz引擎控制对象服务
        /// </summary>
        private VizCommandControlObjectService vizCommandControlObjectService = new VizCommandControlObjectService();

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

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

        #region TakeCommand -- 上版子命令

        /// <summary>
        /// 上版命令
        /// </summary>
        public VCommand TakeCommand { get; set; }

        /// <summary>
        /// 上板
        /// </summary>
        private void Take()
        {
            // 更新控制字段List的值
            IFieldTreeService service = ApplicationDomainEx.ServiceManager.GetService<IFieldTreeService>(ViewServiceKeys.FIELD_TREE_SERVICE);
            if (service == null)
                return;

            // 尝试更新控制字段List的值
            service.TryUpdateControlFieldListValue();

            // 执行上版流程
            this.Execute((obj, view, conn) =>
                {
                    this.vizCommandService.SetEnabledUpdate(conn, false);
                    this.vizCommandService.SetObject(conn, ApplicationDomainEx.CurrentPage.ScenePath, ApplicationDomainEx.CurrentPage.Layer);
                    if (obj != null)
                    {
                        this.vizCommandControlObjectService.SetControlObject(conn, obj);
                    }
                    if (view != null)
                    {
                        view.TakIn(conn);
                    }
                    this.vizCommandService.SetEnabledUpdate(conn, true);
                    this.vizCommandService.Start(conn, ApplicationDomainEx.CurrentPage.Layer);
                });
        }

        #endregion

        #region ContinueCommand -- 继续命令

        /// <summary>
        /// 继续命令
        /// </summary>
        public VCommand ContinueCommand { get; set; }

        /// <summary>
        /// 继续
        /// </summary>
        private void Continue()
        {
            this.Execute((obj, view, conn) =>
                {
                    this.vizCommandService.TakeContinue(conn, ApplicationDomainEx.CurrentPage.Layer);
                    view?.TakeContinue(conn);
                });
        }

        #endregion

        #region TakeOutCommand -- 下版命令

        /// <summary>
        /// 下版命令
        /// </summary>
        public VCommand TakeOutCommand { get; set; }

        /// <summary>
        /// 下版
        /// </summary>
        private void TakeOut()
        {
            this.Execute((obj, view, conn) =>
                {
                    this.vizCommandService.TakeOut(conn, ApplicationDomainEx.CurrentPage.Layer);
                    view?.TakeOut(conn);
                });
        }

        #endregion

        #region UpdateCommand -- 更新命令

        /// <summary>
        /// 更新命令
        /// </summary>
        public VCommand UpdateCommand { get; set; }

        /// <summary>
        /// 更新
        /// </summary>
        private void Update()
        {
            // 更新控制字段List的值
            IFieldTreeService service = ApplicationDomainEx.ServiceManager.GetService<IFieldTreeService>(ViewServiceKeys.FIELD_TREE_SERVICE);
            if (service == null)
                return;

            // 尝试更新控制字段List的值
            service.TryUpdateControlFieldListValue();

            // 执行更新流程
            this.Execute((obj, view, conn) =>
                {
                    if (obj != null)
                    {
                        this.vizCommandControlObjectService.SetControlObject(conn, obj);
                    }
                    view?.TakeUpdate(conn);
                });
        }

        #endregion

        // ==============================================================
        // Private Function
        // ==============================================================

        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="action">行为</param>
        private void Execute(Action<ControlObjectModel, IPluginView, ConnModel> action)
        {
            // 是否拥有打开的页或模板页
            if (ApplicationDomainEx.CurrentPage == null)
                return;

            // 插件服务
            IPluginService pluginService = ApplicationDomainEx.ServiceManager.GetService<IPluginService>(ViewServiceKeys.PLUGIN_SERVICE);
            if (pluginService == null)
                return;

            // 控制字段树服务
            IFieldTreeService fieldTreeService = ApplicationDomainEx.ServiceManager.GetService<IFieldTreeService>(ViewServiceKeys.FIELD_TREE_SERVICE);
            if (fieldTreeService == null)
                return;

            ControlObjectModel controlObject = fieldTreeService.GetControlObject();

            // 模板
            if (ApplicationDomainEx.CurrentPage is PageTemplateModel template)
            {
                // 模板上版等操作使用默认分组
                ConnGroupModel group = ApplicationDomainEx.ConnGroups.FirstOrDefault(p => p.IsDefault);
                // 如果没有默认分组，那么采用第一个可用分组
                if (group == null)
                {
                    group = ApplicationDomainEx.ConnGroups.FirstOrDefault(p => p.IsEnabled);
                }

                // 如果没有分组可用，那么不处理
                if (group == null)
                    return;

                foreach (var item in group.Items)
                {
                    if (!item.IsEnabled || !item.IsConnected)
                        continue;

                    try
                    {
                        action(controlObject, null, item);
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex);
                    }
                }
            }
            // 页
            else if (ApplicationDomainEx.CurrentPage is PageModel page)
            {
                // 模板上版等操作使用默认分组
                ConnGroupModel group = ApplicationDomainEx.ConnGroups.FirstOrDefault(p => p.GroupID == page.ConnGroupID);
                if (group == null)
                {
                    // 记录日志
                    log.Error($"ConnGroupID: {page.ConnGroupID} is not found.");

                    return;
                }

                IPluginView view = pluginService.GetCurrentPluginView() as IPluginView;

                foreach (var item in group.Items)
                {
                    if (!item.IsEnabled || !item.IsConnected)
                        continue;

                    try
                    {
                        action(controlObject, view, item);
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex);
                    }
                }
            }
        }
    }
}