using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Data;
using System.Windows.Input;
using KellermanSoftware.ContactsModule.Controllers;
using KellermanSoftware.ContactsModule.DataAccess;
using KellermanSoftware.ContactsModule.Events;
using KellermanSoftware.ContactsModule.Models;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Unity;

namespace KellermanSoftware.ContactsModule.ViewModels
{
    public sealed class ContactHistoryListViewModel : IContactHistoryListViewModel
    {
        private readonly IUnityContainer _container;
        private readonly IRepository _repository;
        private readonly IEventAggregator _eventAggregator;
        private readonly IConfirmationController _confirmationController;
        private readonly IContactDetailsViewModel _contactDetailsViewModel;
        private Contact _contact;
        private readonly ListCollectionView _history;
        private readonly List<ContactHistoryViewModel> _historyList =
            new List<ContactHistoryViewModel>();
        private readonly DelegateCommand _addCommand;
        private readonly DelegateCommand _editCommand;
        private readonly DelegateCommand _deleteCommand;

        public ContactHistoryListViewModel(IUnityContainer container,
                                           IRepository repository,
                                           IEventAggregator eventAggregator,
                                           IConfirmationController confirmationController,
                                           IContactDetailsViewModel contactDetailsViewModel)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            if (repository == null)
            {
                throw new ArgumentNullException("repository");
            }
            if (eventAggregator == null)
            {
                throw new ArgumentNullException("eventAggregator");
            }
            if (confirmationController == null)
            {
                throw new ArgumentNullException("confirmationController");
            }
            if (contactDetailsViewModel == null)
            {
                throw new ArgumentNullException("contactDetailsViewModel");
            }

            _container = container;
            _repository = repository;
            _eventAggregator = eventAggregator;
            _confirmationController = confirmationController;
            _contactDetailsViewModel = contactDetailsViewModel;
            _contactDetailsViewModel.ContactChanged += OnContactChanged;

            // Initialize the CollectionView and track the current selection.
            _history = new ListCollectionView(_historyList);
            _history.CurrentChanged += OnCurrentHistoryChanged;

            _addCommand = new DelegateCommand(AddHistory, CanAddHistory);
            _editCommand = new DelegateCommand(EditHistory, CanEditHistory);
            _deleteCommand = new DelegateCommand(OnDeleteCommand, CanDeleteHistory);
        }
                
        public ICollectionView History
        {
            get { return _history; }
        }

        public ICommand AddCommand 
        {
            get { return _addCommand; }
        }

        public ICommand EditCommand
        {
            get { return _editCommand; }
        }

        public ICommand DeleteCommand
        {
            get { return _deleteCommand; }
        }

        #region IContactHistoryListViewModel Members

        public void SaveContactHistory(ContactHistory contactHistory)
        {
            if (contactHistory.ContactHistoryId == 0)
            {
                _contact.History.Add(contactHistory);
            }
            else
            {
                int index = 
                    _contact.History.FindIndex(x => x.ContactHistoryId == contactHistory.ContactHistoryId);
                if (index != -1)
                {
                    _contact.History[index] = contactHistory;
                }
            }

            _repository.SaveContact(_contact);

            UpdateHistoryList(contactHistory.ContactHistoryId);
        }

        #endregion IContactHistoryListViewModel Members

        private void OnContactChanged(object sender, ContactChangedEventArgs e)
        {
            _contact = e.Contact;
            UpdateHistoryList(null);
            _addCommand.RaiseCanExecuteChanged();
        }

        private void OnCurrentHistoryChanged(object sender, EventArgs e)
        {            
            _editCommand.RaiseCanExecuteChanged();
            _deleteCommand.RaiseCanExecuteChanged();
        }

        private void UpdateHistoryList(long? selectedHistoryId)
        {
            _historyList.Clear();
            _historyList.AddRange(LoadHistoryList());
            _history.Refresh();

            if (selectedHistoryId.HasValue)
            {
                foreach (ContactHistoryViewModel history in _history)
                {
                    if (history.ContactHistoryId == selectedHistoryId.Value)
                    {
                        _history.MoveCurrentTo(history);
                        break;
                    }
                }
            }
            else if (!_history.IsEmpty)
            {
                _history.MoveCurrentToFirst();
            }
        }

        private List<ContactHistoryViewModel> LoadHistoryList()
        {
            if (_contact == null)
            {
                return new List<ContactHistoryViewModel>();
            }

            return _contact.History.ConvertAll<ContactHistoryViewModel>(x => new ContactHistoryViewModel(x));
        }

        private void AddHistory()
        {
            AddEditHistory(new ContactHistory(_contact));
        }

        private bool CanAddHistory()
        {
            return _contact != null;
        }

        private void EditHistory()
        {
            Debug.Assert(_history.CurrentItem != null);
            ContactHistoryViewModel contactHistoryViewModel =
                _history.CurrentItem as ContactHistoryViewModel;
            if (contactHistoryViewModel == null)
            {
                Debug.Assert(false);
                return;
            }
            AddEditHistory(new ContactHistory(contactHistoryViewModel.History));
        }

        private bool CanEditHistory()
        {
            return _history.CurrentItem != null;
        }

        private void OnDeleteCommand()
        {           
            _confirmationController.Show("Delete confirmation",
                                         "Are you sure you want to delete selected history?",
                                         result =>
                                         {
                                             if (result)
                                             {
                                                 DeleteHistory();
                                             }
                                         });
        }

        private void DeleteHistory()
        {
            Debug.Assert(_history.CurrentItem != null);
            ContactHistoryViewModel contactHistoryViewModel =
                _history.CurrentItem as ContactHistoryViewModel;
            if (contactHistoryViewModel == null)
            {
                Debug.Assert(false);
                return;
            }

            _repository.DeleteHistory(contactHistoryViewModel.History);

            _history.Remove(_history.CurrentItem);
            _editCommand.RaiseCanExecuteChanged();
            _deleteCommand.RaiseCanExecuteChanged();
        }

        private bool CanDeleteHistory()
        {
            return _history.CurrentItem != null;
        }

        private void AddEditHistory(ContactHistory contactHistory)
        {
            // Create EditContactHistoryViewModel.
            ParameterOverride constructorParameter =
                new ParameterOverride("contactHistory", contactHistory);
            EditContactHistoryViewModel viewModel =
                _container.Resolve<EditContactHistoryViewModel>(constructorParameter);

            // Publish the EditContactHistoryEvent event.
            _eventAggregator.GetEvent<EditContactHistoryEvent>().Publish(viewModel);
        }
    }
}
