using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using apiwrappercli;

using Prism.Commands;
using Prism.Events;
using SPTrader.Common;

namespace SPTrader.BusinessLayer
{
    public abstract class SPBindableBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            OnPropertyChanged(propertyName);
        }

        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (!EqualityComparer<T>.Default.Equals(storage, value))
            {
                storage = value;
                OnPropertyChanged(propertyName);
                return true;
            }
            return false;
        }
    }

    public abstract class SPBindableWindow : SPWindow, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            OnPropertyChanged(propertyName);
        }

        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (!EqualityComparer<T>.Default.Equals(storage, value))
            {
                storage = value;
                OnPropertyChanged(propertyName);
                return true;
            }
            return false;
        }

        // abstract methods all child must implement
        public abstract void SaveDesktop();

        // API related properties
        protected IEventAggregator ea = EventService.Instance.EventAggregator;
        protected SPApiProxyWrapper apiProxy { get; private set; }
        protected string winName { get; private set; }
        public string windowId { get; protected set; }

        public SPBindableWindow()
        {
            apiProxy = SPCLI.Instance.ApiProxyWrapper;

            winName = this.GetType().Name;
            windowId = string.Format("{0}_{1}", winName, DateTime.Now.ToEpochTime());
        }
    }

    public abstract class SPBindableUserControl : SPUserControl, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            OnPropertyChanged(propertyName);
        }

        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (!EqualityComparer<T>.Default.Equals(storage, value))
            {
                storage = value;
                OnPropertyChanged(propertyName);
                return true;
            }
            return false;
        }

        protected IEventAggregator ea = EventService.Instance.EventAggregator;
        protected SPApiProxyWrapper apiProxy { get; private set; }

        public SPBindableUserControl()
        {
            apiProxy = SPCLI.Instance.ApiProxyWrapper;
        }
    }

    public abstract class SPBindableCustomWindow : SPBindableWindow
    {
        public DelegateCommand BarDoubleClickCommand { get; set; }
        public DelegateCommand CloseCommand { get; set; }
        public DelegateCommand MinCommand { get; set; }
        public DelegateCommand MinMaxCommand { get; set; }
        public DelegateCommand DragCommand { get; set; }

        public SPBindableCustomWindow()
        {
            DataContext = this;

            BarDoubleClickCommand = new DelegateCommand(() => {
                if (WindowState == WindowState.Normal)
                    WindowState = WindowState.Maximized;
                else
                    WindowState = WindowState.Normal;
            });

            MinMaxCommand = new DelegateCommand(() => { BarDoubleClickCommand.Execute(); });
            MinCommand = new DelegateCommand(() => { WindowState = WindowState.Minimized; });
            CloseCommand = new DelegateCommand(Close);
            DragCommand = new DelegateCommand(DragMove);
        }
    }

    public abstract class SPBindableWindowChrome : SPBindableWindow
    {
        protected Border _MainWindowBorder { get; set; }
        protected Button _RestoreButton { get; set; }
        protected Button _MaximizeButton { get; set; }

        public SPBindableWindowChrome()
        {
            StateChanged += WindowStateChanged;
            Initialized += WindowInitialized;
        }

        // inherited window classes implement this to initialize/map named elements
        protected virtual void WindowInitialized(object sender, EventArgs e)
        {
            _MainWindowBorder = this.FindName("MainWindowBorder") as Border;
            _MaximizeButton = this.FindName("MaximizeButton") as Button;
            _RestoreButton = this.FindName("RestoreButton") as Button;
        }

        // Can execute
        protected void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        // Minimize
        protected void CommandBinding_Executed_Minimize(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.MinimizeWindow(this);
        }

        // Maximize
        protected void CommandBinding_Executed_Maximize(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.MaximizeWindow(this);
        }

        // Restore
        protected void CommandBinding_Executed_Restore(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.RestoreWindow(this);
        }

        // Close
        protected void CommandBinding_Executed_Close(object sender, ExecutedRoutedEventArgs e)
        {
            SystemCommands.CloseWindow(this);
        }

        // State change
        protected virtual void WindowStateChanged(object sender, EventArgs e)
        {
            if (_MainWindowBorder == null) return;

            if (WindowState == WindowState.Maximized)
            {
                _MainWindowBorder.BorderThickness = new Thickness(8);

                if (_RestoreButton != null)
                    _RestoreButton.Visibility = Visibility.Visible;

                if (_MaximizeButton != null)
                    _MaximizeButton.Visibility = Visibility.Collapsed;
            }
            else
            {
                _MainWindowBorder.BorderThickness = new Thickness(0);

                if (_RestoreButton != null)
                    _RestoreButton.Visibility = Visibility.Collapsed;

                if (_MaximizeButton != null)
                    _MaximizeButton.Visibility = Visibility.Visible;
            }
        }
    }
}