using FSI.Lib.MVVM;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;

namespace FSI.Lib.Guis.SetSizePosExWindow
{
    public class ViewModel : ViewModelBase
    {
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll")]
        static extern IntPtr PostMessage(IntPtr hwndParent, int msg, int wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWindowVisible(IntPtr hWnd);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetWindowPos(IntPtr hWnd,
           IntPtr hWndInsertAfter, int X, int Y, int cx, int cy,
           SetWindowPosFlags uFlags);

        // Define the SetWindowPosFlags enumeration.
        [Flags()]
        private enum SetWindowPosFlags : uint
        {
            SynchronousWindowPosition = 0x4000,
            DeferErase = 0x2000,
            DrawFrame = 0x0020,
            FrameChanged = 0x0020,
            HideWindow = 0x0080,
            DoNotActivate = 0x0010,
            DoNotCopyBits = 0x0100,
            IgnoreMove = 0x0002,
            DoNotChangeOwnerZOrder = 0x0200,
            DoNotRedraw = 0x0008,
            DoNotReposition = 0x0200,
            DoNotSendChangingEvent = 0x0400,
            IgnoreResize = 0x0001,
            IgnoreZOrder = 0x0004,
            ShowWindow = 0x0040,
        }

        private CancellationTokenSource tokenSource = null;
        private CancellationToken token;
        private Task task = null;

        private BackgroundWorker backgroundWorker;
        private ICommand _cmdStart;
        private ICommand _cmdStop;
        private ObservableCollection<IInterface> _windows;
        private int _updateIntervall;
        private bool _autoStart;
        private IInterface _selectedWindow;

        public ViewModel()
        {
            _windows = new ObservableCollection<IInterface>();

            _cmdStart = new RelayCommand<object>(ExecuteStart, CanExecuteStart);
            _cmdStop = new RelayCommand<object>(ExecuteStop, CanExecuteStop);

            backgroundWorker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            backgroundWorker.DoWork += BackgroundWorker_DoWork;
            backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
        }

        public IInterface Data { get; set; }

        public void Init()
        {
            if (Data.AutoStart)
            {
                ExecuteStart(null);
            }
        }

        public ObservableCollection<IInterface> Windows
        {
            get
            {
                return _windows;
            }
            set
            {
                if (_windows != value & _windows != null)
                {
                    _windows = value;
                    OnPropertyChanged();
                }
            }
        }

        public IInterface SelectedWindow
        {
            get
            {
                return _selectedWindow;
            }
            set
            {
                if (SelectedWindow != value & SelectedWindow != null)
                {
                    SelectedWindow = value;
                    OnPropertyChanged();
                }
            }
        }

        public int UpdateIntervall
        {
            get
            {
                return _updateIntervall;
            }
            set
            {
                if (_updateIntervall != value & _updateIntervall != null)
                {
                    _updateIntervall = value;
                    OnPropertyChanged();
                }
            }
        }

        public bool AutoStart
        {
            get
            {
                return _autoStart;
            }
            set
            {
                if (_autoStart != value & _autoStart != null)
                {
                    _autoStart = value;
                    OnPropertyChanged();
                }
            }
        }

        public ICommand CmdStart
        {
            get { return _cmdStart; }
            set => _cmdStart = value;
        }

        private bool CanExecuteStop(object obj)
        {
            return Status;
        }

        private void ExecuteStop(object obj)
        {
            if (backgroundWorker.WorkerSupportsCancellation == true)
            {
                backgroundWorker.CancelAsync();
            }
            Status = false;
        }

        public ICommand CmdStop
        {
            get { return _cmdStop; }
            set => _cmdStop = value;
        }

        private bool CanExecuteStart(object obj)
        {
            return !Status;
        }

        private void ExecuteStart(object obj)
        {
            if (backgroundWorker.IsBusy != true)
            {
                backgroundWorker.RunWorkerAsync();
            }
            Status = true;
        }

        private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            while (true)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    foreach (IInterface window in Windows)
                    {
                        // Perform a time consuming operation and report progress.
                        Thread.Sleep(UpdateIntervall);

                        // Find windos by Name
                        var windowHandle = FindWindow(window.ClassName, window.Name);

                        // Set windows size and position
                        SetWindowPos(windowHandle, IntPtr.Zero, window.X, window.Y, window.Width, window.Height, 0);
                    }
                }
            }
        }

        public bool Status { get; set; }
    }
}

