using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Collections.ObjectModel;
using Wpf_Demo.DataAccess;

namespace Wpf_Demo.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public MainViewModel()
        {
            // Insert code required on object creation below this point
            if (DesignerProperties.GetIsInDesignMode(MainWindow.Instance))
            {
                // Designer Data
                Items = new ObservableCollection<GoalViewModel>() {
                                new GoalViewModel() { Goal = "Goal one", Priority =  GoalPriority.Medium, Cost = 300, Done = false},
                                new GoalViewModel() { Goal = "Goal two", Priority =  GoalPriority.Medium, Cost = 200, Done = false},
                                new GoalViewModel() { Goal = "Goal three", Priority =  GoalPriority.Medium, Cost = 150, Done = true},
                                new GoalViewModel() { Goal = "Goal four", Priority =  GoalPriority.High, Cost = 250, Done = true},
                                new GoalViewModel() { Goal = "Goal five", Priority =  GoalPriority.Medium, Cost = 10, Done = false},
                                new GoalViewModel() { Goal = "Goal six", Priority =  GoalPriority.Medium, Cost = 100, Done = true},
                            };
            }
            else
            {
               Items = DatabaseAccessLayer.Items;
               foreach (var item in Items)
               {
                   item.PropertyChanged += OnItemPropertyChanged;
               }

            }
            Items.CollectionChanged += OnItemsCollectionChanged;
            RefreshTotalCost();
            SortList(); // Sorting the list will cause the collection to fire the event Collection changed because the list will be erased and the items will be added in a sorted order.
        }

        void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
             // Updating the total cost.
             GoalViewModel goal = (GoalViewModel)sender;
             if (goal.ChangedProperties.Contains("Cost") || goal.ChangedProperties.Contains("Done"))
                 RefreshTotalCost();
        }

        void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (isSortingFlag) // Don't update anything when sorting is performed.
                return;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    GoalViewModel newItem = (GoalViewModel) e.NewItems[0];
                    newItem.PropertyChanged += OnItemPropertyChanged;

                    goto refreshLocalValues;
                case NotifyCollectionChangedAction.Remove:
                    GoalViewModel deletedItem = (GoalViewModel)e.OldItems[0];
                    deletedItem.PropertyChanged -= OnItemPropertyChanged;
            refreshLocalValues:
                    RefreshTotalCost();
                    // Is there any elements for deletion
                    var doneItem = Items.FirstOrDefault(i => i.Done);
                    break;
            }
        }

        private bool isSortingFlag;
        public void SortList()
        {            
            // Sorting the items
            isSortingFlag = true;
            var sortedList = Items.OrderByDescending(i => i.Priority).ThenBy(i => i.Goal).ToList();
            this.Items.Clear();
            foreach (var itemViewModel in sortedList)
            {
                this.Items.Add(itemViewModel);
            }
            isSortingFlag = false;
        }

        public const string ItemsPropertyName = "Items";

        public ObservableCollection<GoalViewModel> Items { get; private set; }

        private decimal totalCost = 0;
        public decimal TotalCost
        {
            get
            {
                return totalCost;
            }
            private set
            {
                if (value != totalCost)
                {
                    totalCost = value;
                    OnPropertyChanged("TotalCost");
                }
            }
        }

        public void RefreshTotalCost()
        {
            this.TotalCost = Items
                                .Where(i => !i.Done)
                                .Sum(i => i.Cost);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}