using Catel;
using Catel.Logging;
using CatelSample.ViewModels.Interfaces;
using CatelSample.Views.Base.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using TabItem = CatelSample.Views.Base.Controls.TabItem;

namespace CatelSample.Views.Services
{
    public class TabService : ITabService
    {
        private static readonly ILog Log = LogManager.GetCurrentClassLogger();

        private TabControl _tabControl;

        public TabService()
        {
        }

        public IEnumerable<ITabItem> Tabs
        {
            get
            {
                if (_tabControl == null)
                {
                    return new List<TabItem>();
                }

                return (from tab in _tabControl.Items.Cast<object>()
                        where tab is ITabItem
                        select (ITabItem)tab).ToList();
            }
        }

        public ITabItem SelectedTab
        {
            get
            {
                if (_tabControl == null)
                {
                    return null;
                }

                var tabItem = _tabControl.SelectedItem as ITabItem;
                return tabItem;
            }
        }

        public event EventHandler<TabItemEventArgs> SelectedTabChanged;

        public void SetTabControl(object tabControl)
        {
            if(tabControl is TabControl)
            {
                Argument.IsNotNull(() => tabControl);

                if (_tabControl != null)
                {
                    _tabControl.SelectionChanged -= OnTabControlSelectionChanged;
                }

                _tabControl = (TabControl)tabControl;
                _tabControl.SelectionChanged += OnTabControlSelectionChanged;
            }
        }

        public bool IsVisible(ITabItem tabItem)
        {
            Argument.IsNotNull(() => tabItem);

            if (_tabControl == null)
            {
                return false;
            }

            var isVisible = (from item in _tabControl.Items.Cast<object>()
                             where ReferenceEquals(tabItem, item)
                             select true).Any();

            return isVisible;
        }

        public bool IsActive(ITabItem tabItem)
        {
            Argument.IsNotNull(() => tabItem);

            if (_tabControl == null)
            {
                return false;
            }

            var selectedTab = SelectedTab;
            var isActive = ReferenceEquals(selectedTab, tabItem);

            return isActive;
        }

        public void Clear()
        {
            if (_tabControl == null)
            {
                return;
            }

            _tabControl.Dispatcher.BeginInvoke(new Action(() => _tabControl.Items.Clear()));
        }

        public void Add(ITabItem tabItem)
        {
            Argument.IsNotNull(() => tabItem);

            if (_tabControl == null)
            {
                return;
            }

            Insert(_tabControl.Items.Count, tabItem);
        }

        public void Insert(int index, ITabItem tabItem)
        {
            Argument.IsNotNull(() => tabItem);

            if (_tabControl == null)
            {
                return;
            }

            var isVisible = IsVisible(tabItem);

            if (isVisible)
            {
                return;
            }

            tabItem.Closed += OnTabItemClosed;

            _tabControl.Dispatcher.BeginInvoke(new Action(() => _tabControl.Items.Insert(index, tabItem)));
        }

        public void Activate(ITabItem tabItem)
        {
            Argument.IsNotNull(() => tabItem);

            if (_tabControl == null)
            {
                return;
            }

            //Commented out: generates random errors because tabitem would be not visible.
            //var isVisible = IsVisible(tabItem);

            //if (!isVisible)
            //{
            //    throw Log.ErrorAndCreateException<InvalidOperationException>("Tab item is not visible, use the Show() method first");
            //}

            _tabControl.Dispatcher.BeginInvoke(new Action(() => _tabControl.SelectedItem = tabItem));
        }

        public void Remove(ITabItem tabItem)
        {
            Argument.IsNotNull(() => tabItem);

            if (_tabControl == null)
            {
                return;
            }

            tabItem.Closed -= OnTabItemClosed;

            _tabControl.RemoveAndUpdateSelection(tabItem);
        }

        private void OnTabItemClosed(object sender, EventArgs e)
        {
            var tabItem = sender as TabItem;

            if (tabItem != null)
            {
                tabItem.Closed -= OnTabItemClosed;

                if (_tabControl == null)
                {
                    return;
                }

                _tabControl.Dispatcher.BeginInvoke(new Action(() => Remove(tabItem)));
            }
        }

        private void OnTabControlSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var handler = SelectedTabChanged;

            if (handler != null)
            {
                var selectedTab = SelectedTab;
                handler(this, new TabItemEventArgs(selectedTab));
            }
        }
    }
}
