using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;

namespace XLAB
{
    internal sealed class SelectInstrumentsWindowViewModel : ObservableObject
    {
        private string _searchText;
        private string _statusText;

        public SelectInstrumentsWindowViewModel(string customerName, IReadOnlyList<AvailableInstrumentItem> instruments)
        {
            CustomerName = customerName ?? string.Empty;
            Instruments = new ObservableCollection<AvailableInstrumentItem>(instruments ?? new List<AvailableInstrumentItem>());
            InstrumentsView = System.Windows.Data.CollectionViewSource.GetDefaultView(Instruments);
            InstrumentsView.Filter = FilterInstruments;

            foreach (var instrument in Instruments)
            {
                instrument.PropertyChanged += InstrumentOnPropertyChanged;
            }

            ConfirmCommand = new RelayCommand(Confirm);
            CancelCommand = new RelayCommand(Cancel);
            UpdateStatus();
        }

        public event EventHandler<bool?> CloseRequested;

        public ICommand CancelCommand { get; private set; }

        public ICommand ConfirmCommand { get; private set; }

        public string CustomerName { get; private set; }

        public ObservableCollection<AvailableInstrumentItem> Instruments { get; private set; }

        public ICollectionView InstrumentsView { get; private set; }

        public string SearchText
        {
            get { return _searchText; }
            set
            {
                if (SetProperty(ref _searchText, value))
                {
                    InstrumentsView.Refresh();
                    UpdateStatus();
                }
            }
        }

        public string StatusText
        {
            get { return _statusText; }
            private set { SetProperty(ref _statusText, value); }
        }

        public IReadOnlyList<AvailableInstrumentItem> GetSelectedItems()
        {
            return Instruments.Where(delegate(AvailableInstrumentItem item) { return item.IsSelected; }).ToList();
        }

        private void Cancel(object parameter)
        {
            RaiseCloseRequested(false);
        }

        private void Confirm(object parameter)
        {
            RaiseCloseRequested(true);
        }

        private bool FilterInstruments(object item)
        {
            var instrument = item as AvailableInstrumentItem;
            if (instrument == null)
            {
                return false;
            }

            if (string.IsNullOrWhiteSpace(SearchText))
            {
                return true;
            }

            return Contains(instrument.RegistryNumber, SearchText)
                   || Contains(instrument.InstrumentName, SearchText)
                   || Contains(instrument.InstrumentType, SearchText)
                   || Contains(instrument.RangeText, SearchText)
                   || Contains(instrument.AccuracyText, SearchText)
                   || Contains(instrument.SerialNumber, SearchText);
        }

        private void InstrumentOnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                UpdateStatus();
            }
        }

        private static bool Contains(string source, string searchText)
        {
            return !string.IsNullOrWhiteSpace(source)
                   && source.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
        }

        private void RaiseCloseRequested(bool? dialogResult)
        {
            var handler = CloseRequested;
            if (handler != null)
            {
                handler(this, dialogResult);
            }
        }

        private void UpdateStatus()
        {
            var visibleCount = InstrumentsView.Cast<object>().Count();
            var selectedCount = Instruments.Count(delegate(AvailableInstrumentItem item) { return item.IsSelected; });
            StatusText = string.Format("Всего: {0}. По фильтру: {1}. Выбрано: {2}.", Instruments.Count, visibleCount, selectedCount);
        }
    }
}
