using AIStudio.Wpf.DiagramDesigner.Additionals.Commands;
using AIStudio.Wpf.Flowchart;
using AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels;
using AIStudio.Wpf.DiagramDesigner.Additionals;
using AIStudio.Wpf.DiagramApp.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using AIStudio.Wpf.DiagramDesigner;
using ZXing;
using AIStudio.Wpf.DiagramDesigner.Helpers;
using AIStudio.Wpf.DiagramDesigner.ViewModels;
using AIStudio.Wpf.DiagramDesigner.ViewModels.BaseViewModel;
using System.Threading.Tasks;

namespace AIStudio.Wpf.DiagramApp.ViewModels
{
    public partial class PageViewModel : BindableBase
    {
        #region 初始化
        protected IDiagramServiceProvider _service
        {
            get
            {
                return DiagramServicesProvider.Instance.Provider;
            }
        }


        public PageViewModel(string title, string status, DiagramType diagramType, string subType = null)
        {
            Title = title;
            Status = status;
            DiagramType = diagramType;
            SubType = subType;

        }
        public PageViewModel(string filename)
        {
            FileName = filename;
            string ext = Path.GetExtension(filename);
            DiagramDocument = OpenFile(filename, ext);
        }

        public PageViewModel(string filename, DiagramDocument diagramDocument)
        {
            FileName = filename;
            DiagramDocument = diagramDocument;
        }

        DiagramDocument DiagramDocument;
        public virtual void View_Loaded(object sender, EventArgs e)
        {
            //await Task.Run(() => {
                //Application.Current.Dispatcher.Invoke(() => {
                    if (string.IsNullOrEmpty(FileName))
                    {
                        Init(true);
                    }
                    else
                    {
                        string ext = Path.GetExtension(FileName);
                        OpenFile(DiagramDocument, ext);
                    }
                //});
            //});

        }


        protected virtual void InitDiagramViewModel()
        {

        }

        protected virtual void Init(bool initNew)
        {
            DiagramViewModels = new ObservableCollection<IDiagramViewModel>()
            {
                GetDiagramViewModel("页-1", DiagramType,initNew),
            };
            DiagramViewModel = DiagramViewModels.FirstOrDefault();

            InitDiagramViewModel();
        }
        #endregion

        #region 属性
        public string FileName
        {
            get; set;
        }

        private string _title;
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                SetProperty(ref _title, value);
            }
        }

        private string _status;
        public string Status
        {
            get
            {
                return _status;
            }
            set
            {
                SetProperty(ref _status, value);
            }
        }

        //private bool _showGrid;
        //public bool ShowGrid
        //{
        //    get
        //    {
        //        return _showGrid;
        //    }
        //    set
        //    {
        //        if (SetProperty(ref _showGrid, value))
        //        {
        //            foreach (var item in DiagramViewModels)
        //            {
        //                item.DiagramOption.LayoutOption.ShowGrid = _showGrid;
        //            }
        //        }
        //    }
        //}

        public DiagramType DiagramType
        {
            get; set;
        }

        public string SubType
        {
            get; set;
        }

        private ObservableCollection<IDiagramViewModel> _diagramViewModels;
        public ObservableCollection<IDiagramViewModel> DiagramViewModels
        {
            get
            {
                return _diagramViewModels;
            }
            set
            {
                SetProperty(ref _diagramViewModels, value);
            }
        }

        private IDiagramViewModel _diagramViewModel;
        public IDiagramViewModel DiagramViewModel
        {
            get
            {
                return _diagramViewModel;
            }
            set
            {
                if (_diagramViewModel != value)
                {
                    if (_diagramViewModel != null)
                    {
                        _diagramViewModel.PropertyChanged -= DiagramViewModel_PropertyChanged;
                        _diagramViewModel.SaveThumbnail();
                    }
                    SetProperty(ref _diagramViewModel, value);
                    if (_diagramViewModel != null)
                    {
                        _diagramViewModel.PropertyChanged += DiagramViewModel_PropertyChanged;
                    }
                }
            }
        }
        #endregion

        #region 命令
        private ICommand _addPageCommand;
        public ICommand AddPageCommand
        {
            get
            {
                return this._addPageCommand ?? (this._addPageCommand = new DelegateCommand<object>(para => this.AddPageExecuted(para)));
            }
        }


        private ICommand _addCopyPageCommand;
        public ICommand AddCopyPageCommand
        {
            get
            {
                return this._addCopyPageCommand ?? (this._addCopyPageCommand = new DelegateCommand<object>(para => this.AddCopyPageExecuted(para)));
            }
        }

        private ICommand _renamePageCommand;
        public ICommand RenamePageCommand
        {
            get
            {
                return this._renamePageCommand ?? (this._renamePageCommand = new DelegateCommand<object>(para => this.RenamePageExecuted(para)));
            }
        }

        private ICommand _endRenamePageCommand;
        public ICommand EndRenamePageCommand
        {
            get
            {
                return this._endRenamePageCommand ?? (this._endRenamePageCommand = new DelegateCommand<object>(para => this.EndRenamePageExecuted(para)));
            }
        }

        private ICommand _deletePageCommand;
        public ICommand DeletePageCommand
        {
            get
            {
                return this._deletePageCommand ?? (this._deletePageCommand = new DelegateCommand<object>(para => this.DeletePageExecuted(para)));
            }
        }

        private ICommand _addImageCommand;
        public ICommand AddImageCommand
        {
            get
            {
                return this._addImageCommand ?? (this._addImageCommand = new DelegateCommand<object>(para => this.AddImageExecuted(para)));
            }
        }

        private ICommand _editImageCommand;
        public ICommand EditImageCommand
        {
            get
            {
                return this._editImageCommand ?? (this._editImageCommand = new DelegateCommand<object>(para => this.EditImageExecuted(para)));
            }
        }

        private ICommand _resizeImageCommand;
        public ICommand ResizeImageCommand
        {
            get
            {
                return this._resizeImageCommand ?? (this._resizeImageCommand = new DelegateCommand<object>(para => this.ResizeImageExecuted(para)));
            }
        }

        private ICommand _resetImageCommand;
        public ICommand ResetImageCommand
        {
            get
            {
                return this._resetImageCommand ?? (this._resetImageCommand = new DelegateCommand<object>(para => this.ResetImageExecuted(para)));
            }
        }

        private ICommand _addVideoCommand;
        public ICommand AddVideoCommand
        {
            get
            {
                return this._addVideoCommand ?? (this._addVideoCommand = new DelegateCommand<object>(para => this.AddVideoExectued(para)));
            }
        }


        private ICommand _addOutLineTextCommand;
        public ICommand AddOutLineTextCommand
        {
            get
            {
                return this._addOutLineTextCommand ?? (this._addOutLineTextCommand = new DelegateCommand<object>(para => this.AddOutLineTextExecuted(para)));
            }
        }

        private ICommand _addBarcodeCommand;
        public ICommand AddBarcodeCommand
        {
            get
            {
                return this._addBarcodeCommand ?? (this._addBarcodeCommand = new DelegateCommand<object>(para => this.AddBarcodeExecuted(para)));
            }
        }
        #endregion

        #region 属性改变
        private void DiagramViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                _service.SelectedItemViewModel = CopyHelper.Mapper(DiagramViewModel?.SelectedItem);
                return;
            }

            var property = sender.GetType().GetProperty(e.PropertyName);
            var attr = property.GetCustomAttributes(typeof(BrowsableAttribute), true);
            if (attr != null && attr.OfType<BrowsableAttribute>().FirstOrDefault()?.Browsable != true)
            {
                return;
            }

            Status = "*";
        }

        #endregion

        #region 方法
        protected virtual bool AddVerify(SelectableDesignerItemViewModelBase arg)
        {
            return true;
        }

        public static DiagramDocument OpenFile(string filename, string ext)
        {
            try
            {
                DiagramDocument diagramDocument = null;

                if (ext == ".xml")
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(DiagramDocument));
                    FileInfo fileInfo = new FileInfo(filename);

                    using (TextReader reader = fileInfo.OpenText())
                    {
                        diagramDocument = (DiagramDocument)serializer.Deserialize(reader);
                    }
                }
                else
                {
                    diagramDocument = JsonConvert.DeserializeObject<DiagramDocument>(File.ReadAllText(filename));
                }

                return diagramDocument;
            }
            catch (System.IO.FileNotFoundException fnfe)
            {
                throw new FileNotFoundException("The system document could not be found ", fnfe);
            }
            catch (System.IO.DirectoryNotFoundException dnfe)
            {
                throw new DirectoryNotFoundException("A required directory was nt found", dnfe);
            }
            catch (System.IO.IOException ioe)
            {
                throw new IOException("A file system error occurred", ioe);
            }
            catch (System.UnauthorizedAccessException uae)
            {
                throw new UnauthorizedAccessException("The requested file system access wasnot granted", uae);
            }
            catch (System.Security.SecurityException se)
            {
                throw new System.Security.SecurityException("The security policy prevents access to a file system resource", se);
            }
            catch (System.Exception e)
            {
                throw new System.Exception(
                    string.Format("The database format vc  invalid \r\n Exception:{0} \r\n InnerException:{1}", e.Message, e.InnerException.Message));
            }
        }

        protected virtual void OpenFile(DiagramDocument diagramDocument, string ext)
        {
            Title = diagramDocument.Title;
            DiagramType = diagramDocument.DiagramType;

            List<DiagramViewModel> viewModels = new List<DiagramViewModel>();
            foreach (var diagramItem in diagramDocument.DiagramItems)
            {
                var viewModel = GetDiagramViewModel(diagramItem, ext);
                viewModels.Add(viewModel);
            }
            DiagramViewModels = new ObservableCollection<IDiagramViewModel>(viewModels);
            foreach (var vm in DiagramViewModels)
            {
                vm.Init(false);
            }
            DiagramViewModel = DiagramViewModels.FirstOrDefault();
        }

        public bool SaveFile(bool isSaveAs = false)
        {
            string filter = "Files (*.xml)|*.xml|Files (*.json)|*.json|All Files (*.*)|*.*";

            if (string.IsNullOrEmpty(FileName) || isSaveAs == true)
            {
                Microsoft.Win32.SaveFileDialog saveFile = new Microsoft.Win32.SaveFileDialog();
                saveFile.Filter = filter;
                if (saveFile.ShowDialog() == true)
                {
                    FileName = saveFile.FileName;
                    Title = Path.GetFileNameWithoutExtension(FileName);
                }
                else
                {
                    return false;
                }
            }

            var ext = Path.GetExtension(FileName);

            DiagramDocument diagramDocument = new DiagramDocument();
            diagramDocument.DiagramItems = new List<DiagramItem>();
            diagramDocument.Title = Title;
            diagramDocument.DiagramType = DiagramType;

            foreach (var viewModel in DiagramViewModels)
            {
                DiagramItem diagramItem = new DiagramItem(viewModel, ext);        
                diagramDocument.DiagramItems.Add(diagramItem);
            }

            if (ext == ".xml")
            {
                FileInfo file = new FileInfo(FileName);
                diagramDocument.Save(file);
            }
            else
            {
                File.WriteAllText(FileName, JsonConvert.SerializeObject(diagramDocument));
            }
            Status = "";

            return true;
        }

        public virtual void AddPageExecuted(object para)
        {
            int index = 0;
            if (para is DiagramViewModel oldpage)
            {
                index = DiagramViewModels.IndexOf(oldpage) + 1;
            }
            else
            {
                index = DiagramViewModels.Count;
            }
            var page = GetDiagramViewModel(null, DiagramType, true);
            DiagramViewModels.Insert(index, page);
            DiagramViewModel = page;
            InitDiagramViewModel();
        }

        protected virtual DiagramViewModel GetDiagramViewModel(DiagramItem diagramItem, string ext)
        {
            return new BlockDiagramViewModel(diagramItem, ext);
        }

        protected virtual DiagramViewModel GetDiagramViewModel(string name, DiagramType diagramType, bool initNew)
        {
            return new BlockDiagramViewModel() { Name = name ?? NewNameHelper.GetNewName(DiagramViewModels.Select(p => p.Name), "页-"), DiagramType = diagramType };
        }

        public void AddCopyPageExecuted(object para)
        {
            if (DiagramViewModel != null)
            {
                var viewModel = DiagramViewModel;
                DiagramItem diagramItem = new DiagramItem(viewModel);
                diagramItem.Name = NewNameHelper.GetNewName(DiagramViewModels.Select(p => p.Name), "页-");

                viewModel = GetDiagramViewModel(diagramItem, ".json");      

                DiagramViewModels.Add(viewModel);
                DiagramViewModel = viewModel;
                InitDiagramViewModel();
            }
        }

        public void DeletePageExecuted(object para)
        {
            if (para is DiagramViewModel oldpage)
            {
                int index = DiagramViewModels.IndexOf(oldpage) - 1;
                DiagramViewModels.Remove(oldpage);
                if (index > 0)
                {
                    DiagramViewModel = DiagramViewModels[index];
                }
                else
                {
                    DiagramViewModel = DiagramViewModels.FirstOrDefault();
                }
            }

        }

        public void RenamePageExecuted(object para)
        {
            if (para is DiagramViewModel oldpage)
            {
                oldpage.IsEditName = true;
            }
        }

        public void EndRenamePageExecuted(object para)
        {
            if (para is DiagramViewModel oldpage)
            {
                oldpage.IsEditName = false;
            }
        }

        public void AddImageExecuted(object para)
        {
            ImageItemViewModel itemBase = new ImageItemViewModel();
            DiagramViewModel?.AddCommand.Execute(itemBase);
            if (itemBase.Root != null)
            {
                _service.DrawModeViewModel.CursorMode = CursorMode.Move;
            }
        }

        public void EditImageExecuted(object para)
        {
            if (para == null)
            {
                para = DiagramViewModel.SelectedItem;
            }

            ImageItemViewModel itemBase = para as ImageItemViewModel;
            if (itemBase != null)
            {
                itemBase.EditData();
            }
        }

        public void ResizeImageExecuted(object para)
        {
            if (para == null)
            {
                para = DiagramViewModel.SelectedItem;
            }

            ImageItemViewModel itemBase = para as ImageItemViewModel;
            if (itemBase != null)
            {
                itemBase.StartResize();
            }
        }

        public void ResetImageExecuted(object para)
        {
            if (para == null)
            {
                para = DiagramViewModel.SelectedItem;
            }
            ImageItemViewModel itemBase = para as ImageItemViewModel;
            if (itemBase != null)
            {
                itemBase.Reset();
            }
        }

        public void AddVideoExectued(object para)
        {
            VideoItemViewModel itemBase = new VideoItemViewModel();
            DiagramViewModel?.AddCommand.Execute(itemBase);
            if (itemBase.Root != null)
            {
                _service.DrawModeViewModel.CursorMode = CursorMode.Move;
            }
        }

        public void AddOutLineTextExecuted(object para)
        {
            OutLineTextDesignerItemViewModel itemBase = new OutLineTextDesignerItemViewModel();
            DiagramViewModel?.AddCommand.Execute(itemBase);
            if (itemBase.Root != null)
            {
                _service.DrawModeViewModel.CursorMode = CursorMode.Move;
            }
        }

        public void AddBarcodeExecuted(object para)
        {
            BarcodeDesignerItemViewModel itemBase = new BarcodeDesignerItemViewModel() { Format = (BarcodeFormat)Enum.Parse(typeof(BarcodeFormat), para.ToString()), Text = "AIStudio.Wpf.DiagramApp" };
            DiagramViewModel?.AddCommand.Execute(itemBase);
            if (itemBase.Root != null)
            {
                _service.DrawModeViewModel.CursorMode = CursorMode.Move;
            }
        }
        #endregion       

        public virtual void Dispose()
        {
        }
    }
}
