using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using TaskIt.Core;
using TaskIt.Infrastructure;
using TaskIt.Modules.Tasks.Assets.Resources;
using TaskIt.Modules.Tasks.Core;
using TaskIt.Web;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.DragDrop;

namespace TaskIt.Modules.Tasks.ViewModels
{
    [Export]
    public class TreeViewModel : TasksViewModelBase
    {
        private static Entity _selectedItem;
        private static object _rightClickedItem;
        private bool _isTaskCategoriesNodeExpanded;
        private bool _isProjectsNodeExpanded;
        private bool _isContextsNodeExpanded;
        private bool _isContactsNodeExpanded;
        private IEnumerable<object> _treeViewData;

        public TreeViewModel()
        {            
            Messenger.Default.Register<DataLoadedArgs>(this, OnDataLoaded);           
        }

        public void OnDataLoaded(DataLoadedArgs args)
        {            
            TreeViewData = Models.TreeViewData.GetTreeViewData();
            // Initially select the 'Actions' node
            //SelectedItem = TaskCategories.ToList().Where(o => o.ID == 2).FirstOrDefault();
            //IsTaskCategoriesNodeExpanded = true;
            NotifyFirstLoad();
        }

        public void OnNew()
        {
            Mode = ItemMode.Add;
            var entityType = GetRightClickedItemEntityType();
            Messenger.Default.Send(new NewEntityArgs(entityType));
            Messenger.Default.Send(new ViewEntityFormArgs(entityType));
        }

        public void OnEdit()
        {
            Mode = ItemMode.Edit;
            var entityType = GetRightClickedItemEntityType();
            Messenger.Default.Send(new EditEntityArgs(entityType, GetID(entityType)));
            Messenger.Default.Send(new ViewEntityFormArgs(entityType));
        }

        public void ContextMenuOpened(RadTreeViewItem treeViewItem)
        {
            RightClickedTreeViewItem = treeViewItem;
            RightClickedItem = treeViewItem.Item;
            if (IsTaskCategoryNodeRightClicked)
            {
                return;
            }
            NotifyNodeRightClicked();
        }

        public void HandleTreeViewItemDrop(DragDropEventArgs e, object treeViewItemSource)
        {
            var payload = e.Options.Payload as DragDropViewModel;
            if (payload == null)
            {
                return;
            }

            switch (e.Options.Status)
            {
                case DragStatus.DropPossible:
                    //var name = GetNodeName(treeViewItem.Item);
                    //cue.DragActionContent = String.Format("Add to {0}", name);
                    break;
                case DragStatus.DropImpossible:
                    //cue.DragActionContent = null;
                    break;
                case DragStatus.DropComplete:
                    var task = payload.DraggedItems[0] as Task;
                    HandleDrop(task, treeViewItemSource);
                    break;
            }
        }

        public void HandleDrop(Task task, object dropItem)
        {
            if (dropItem is TaskCategory)
            {
                HandleTaskCategoryDrop(task, dropItem);
            }
            else if (dropItem is Project)
            {
                HandleProjectDrop(task, dropItem);
            }
            else if (dropItem is Context)
            {
                HandleContextDrop(task, dropItem);
            }
            else if (dropItem is Contact)
            {
                HandleContactDrop(task, dropItem);
            }
        }

        public void HandleTaskCategoryDrop(Task task, object dropItem)
        {
            var category = (TaskCategory)dropItem;
            switch (category.Name)
            {
                case "Inbox":
                    task.TaskCategoryID = 1;
                    break;
                case "Actions":
                    task.TaskCategoryID = 2;
                    break;
                case "Waiting":
                    task.TaskCategoryID = 3;
                    break;
                case "Someday":
                    task.TaskCategoryID = 4;
                    break;
                case "Ticklers":
                    task.TaskCategoryID = 5;
                    break;
                case "Reference":
                    task.TaskCategoryID = 6;
                    break;
            }
            SubmitChanges();
        }

        public void HandleProjectDrop(Task task, object dropItem)
        {
            var project = (Project)dropItem;
            if (task.ProjectID == project.ID)
            {
                return;
            }
            task.ProjectID = project.ID;
            SubmitChanges();
        }

        public void HandleContextDrop(Task task, object dropItem)
        {
            var context = (Context)dropItem;
            if (task.ContextID == context.ID)
            {
                return;
            }
            task.ContextID = context.ID;
            SubmitChanges();
        }

        public void HandleContactDrop(Task task, object dropItem)
        {
            var contact = (Contact)dropItem;
            if (task.ContactID == contact.ID)
            {
                return;
            }
            task.ContactID = contact.ID;
            SubmitChanges();
        }

        //private static string GetNodeName(object item)
        //{
        //    if (item is TreeViewNodeModelBase)
        //    {
        //        return ((TreeViewNodeModelBase)item).Name;
        //    }
        //    if (item is TaskCategory)
        //    {
        //        return ((TaskCategory)item).Name;
        //    }
        //    if (item is Project)
        //    {
        //        return ((Project)item).Name;
        //    }
        //    if (item is Context)
        //    {
        //        return ((Context)item).Name;
        //    }
        //    if (item is Contact)
        //    {
        //        return ((Contact)item).Name;
        //    }
        //    return null;
        //}

        private void SubmitChanges()
        {
            Utils.ShowBusyIndicator();
            Utils.DataContext.SubmitChanges(OnSubmitCompleted, null);
        }

        public override void OnSubmitCompleted(SubmitOperation so)
        {
            Utils.HideBusyIndicator();
            if (so.HasError)
            {
                Utils.ShowErrorMessage(TasksErrorStrings.Message_SubmitFailed, so.Error.Message);
                so.MarkErrorAsHandled();
                return;
            }

            Utils.DataContext.RejectChanges();
            Messenger.Default.Send(new TaskUpdateCompletedArgs());            
        }

        public long GetID(EntityType entityType)
        {
            switch (entityType)
            {
                case EntityType.Project:
                    return ((Project) _rightClickedItem).ID;
                case EntityType.Context:
                    return ((Context)_rightClickedItem).ID;
                default:
                    return ((Contact)_rightClickedItem).ID;
            }
        }

        public virtual void OnTreeViewItemDelete()
        {
            Utils.ShowBusyIndicator();
            EntityToDelete = RightClickedItem as Entity;
            if (EntityToDelete is Project)
            {
                var project = EntityToDelete as Project;
                Utils.DataContext.GetTaskCountForProject(project.ID, OnIsDeleteAllowed, null);
            }
            else if (EntityToDelete is Context)
            {
                var context = EntityToDelete as Context;
                Utils.DataContext.GetTaskCountForContext(context.ID, OnIsDeleteAllowed, null);
            }
            else if (EntityToDelete is Contact)
            {
                var contact = EntityToDelete as Contact;
                Utils.DataContext.GetTaskCountForContact(contact.ID, OnIsDeleteAllowed, null);
            }
        }

        void OnIsDeleteAllowed(InvokeOperation<int> io)
        {
            if (io.HasError)
            {                
                // TODO: Ross - Move to resources
                Utils.ShowErrorMessage("Error obtaining count", io.Error.Message);
                io.MarkErrorAsHandled();
                return;
            }

            if (Convert.ToInt32(io.Value) > 0)
            {
                Utils.HideBusyIndicator();
                // TODO: Ross - Show resource message based on the EntityToDelete type
                Messenger.Default.Send(new ErrorArgs("Can't delete context"));
                return;
            }

            Messenger.Default.Send(new DeleteEntityArgs(RightClickedItem as Entity));
            Utils.HideBusyIndicator();
        }

        private static void FireFilterEvent(Entity entity, Type type)
        {
            var relationType = GetEntityType(type);
            var info = new EntityFilterArgs {EntityType = relationType};
            
            switch (relationType)
            {
                case EntityType.TaskCategory:
                    info.ID = ((TaskCategory) entity).ID;
                    break;
                case EntityType.Project:
                    info.ID = ((Project) entity).ID;
                    break;
                case EntityType.Context:
                    info.ID = ((Context) entity).ID;
                    break;
                case EntityType.Contact:
                    info.ID = ((Contact) entity).ID;
                    break;
            }

            Messenger.Default.Send(info);            
        }

        private static EntityType GetEntityType(Type type)
        {
            if (type == typeof(TaskCategory))
            {
                return EntityType.TaskCategory;
            }
            if (type == typeof(Project) || type == typeof(ProjectsTreeViewNodeModel))
            {
                return EntityType.Project;
            }
            if (type == typeof(Context) || type == typeof(ContextsTreeViewNodeModel))
            {
                return EntityType.Context;
            }
            if (type == typeof(Contact) || type == typeof(ContactsTreeViewNodeModel))
            {
                return EntityType.Contact;
            }
            return EntityType.Context;
        }

        # region Properties

        public IEnumerable<object> TreeViewData
        {
            get { return _treeViewData; }
            set { _treeViewData = value; this.OnPropertyChanged(p => p.TreeViewData); }
        }

        public Entity SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (!IsEntity(value) || value == _selectedItem)
                {
                    return; // Ignore left mouse clicks on top-level nodes
                }
                _selectedItem = value;
                FireFilterEvent(value, value.GetType());
                this.OnPropertyChanged(p => p.SelectedItem);
            }
        }

        public RadTreeViewItem RightClickedTreeViewItem { get; set; }

        public object RightClickedItem
        {
            get { return _rightClickedItem; }
            set
            {
                _rightClickedItem = value;
                // TODO: Ross - For some reason even though IsContextMenuAvailable is false when right-clicking on a task category node, the context
                // menu still appears. 
                this.OnPropertyChanged(p => p.IsContextMenuAvailable);
                this.OnPropertyChanged(p => p.IsNewContextItemAvailable);
                this.OnPropertyChanged(p => p.IsEditContextItemAvailable);
                this.OnPropertyChanged(p => p.IsDeleteContextItemAvailable);
            }
        }

        private static bool IsEntity(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            var itemType = obj.GetType();
            return itemType.IsSubclassOf(typeof(Entity));
        }

        public bool IsContextMenuAvailable
        {
            get { return !IsTaskCategoryNodeRightClicked; }
        }

        public bool IsNewContextItemAvailable
        {
            get { return !IsEntityNodeSelected; }
        }

        public bool IsEditContextItemAvailable
        {
            get { return IsEntityNodeSelected; }
        }

        public bool IsDeleteContextItemAvailable
        {
            get { return IsEntityNodeSelected && !IsNoItem; }
        }

        public bool IsNoItem
        {
            get
            {
                if (RightClickedItem is Project)
                {
                    var project = RightClickedItem as Project;
                    return project.ID == 1;
                }
                if (RightClickedItem is Context)
                {
                    var context = RightClickedItem as Context;
                    return context.ID == 1;
                }
                if (RightClickedItem is Contact)
                {
                    var contact = RightClickedItem as Contact;
                    return contact.ID == 1;
                }
                return false;
            }
        }

        private static bool IsEntityNodeSelected
        {
            get { return _rightClickedItem != null && IsEntity(_rightClickedItem); }
        }

        public bool IsTaskCategoryNodeRightClicked
        {
            get
            {
                return _rightClickedItem != null &&
                       (_rightClickedItem.GetType() == typeof(TaskCategory) ||
                        (_rightClickedItem.GetType() == typeof(CategoriesTreeViewNodeModel) && ((CategoriesTreeViewNodeModel)_rightClickedItem).Name == TasksStrings.Node_TaskCategories));
            }
        }

        private static EntityType GetRightClickedItemEntityType()
        {
            return GetEntityType(_rightClickedItem.GetType());
        }

        public bool IsTaskCategoriesNodeExpanded
        {
            get { return _isTaskCategoriesNodeExpanded; }
            set { _isTaskCategoriesNodeExpanded = value; this.OnPropertyChanged(p => p.IsTaskCategoriesNodeExpanded); }
        }

        public bool IsProjectsNodeExpanded
        {
            get { return _isProjectsNodeExpanded; }
            set { _isProjectsNodeExpanded = value; this.OnPropertyChanged(p => p.IsProjectsNodeExpanded); }
        }

        public bool IsContextsNodeExpanded
        {
            get { return _isContextsNodeExpanded; }
            set { _isContextsNodeExpanded = value; this.OnPropertyChanged(p => p.IsContextsNodeExpanded); }
        }

        public bool IsContactsNodeExpanded
        {
            get { return _isContactsNodeExpanded; }
            set { _isContactsNodeExpanded = value; this.OnPropertyChanged(p => p.IsContactsNodeExpanded); }
        }

        # endregion

        # region UI Events

        public event RoutedEventHandler FirstLoad;
        public void NotifyFirstLoad()
        {
            if (FirstLoad != null) { FirstLoad(this, new RoutedEventArgs()); }
        }

        public event RoutedEventHandler NodeRightClicked;
        public void NotifyNodeRightClicked()
        {
            if (NodeRightClicked != null) { NodeRightClicked(this, new RoutedEventArgs()); }
        }

        # endregion

        # region Commands

        private RelayCommand _newCommand;
        public RelayCommand NewCommand
        {
            get { return _newCommand ?? (_newCommand = new RelayCommand(OnNew)); }
        }

        private RelayCommand _editCommand;
        public RelayCommand EditCommand
        {
            get { return _editCommand ?? (_editCommand = new RelayCommand(OnEdit)); }
        }

        private RelayCommand _deleteTreeViewItemCommand;
        public RelayCommand DeleteTreeViewItemCommand
        {
            get { return _deleteTreeViewItemCommand ?? (_deleteTreeViewItemCommand = new RelayCommand(OnTreeViewItemDelete)); }
        }

        # endregion

        # region Icons

        public Uri IconTask
        {
            get { return GetIconUri("Task"); }
        }

        public Uri IconProject
        {
            get { return GetIconUri("Project"); }
        }

        public Uri IconContext
        {
            get { return GetIconUri("Context"); }
        }

        public Uri IconContact
        {
            get { return GetIconUri("Person"); }
        }

        public Uri IconCategories
        {
            get { return GetIconUri("Categories"); }
        }

        public Uri IconProjects
        {
            get { return GetIconUri("Projects"); }
        }

        public Uri IconContexts
        {
            get { return GetIconUri("Contexts"); }
        }

        public Uri IconContacts
        {
            get { return GetIconUri("People"); }
        }

        public Uri IconAllCategories
        {
            get { return GetIconUri("AllCategories"); }
        }

        # endregion

        # region Resource Strings

        public string ResourceNodeTaskCategories
        {
            get { return TasksStrings.Node_TaskCategories; }
        }

        public string ResourceNodeProjects
        {
            get { return TasksStrings.Node_Projects; }
        }

        public string ResourceNodeContexts
        {
            get { return TasksStrings.Node_Contexts; }
        }

        public string ResourceNodePeople
        {
            get { return TasksStrings.Node_Contacts; }
        }

        # endregion

    }
}