using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Services.Client;
using System.Linq;
using C1.Silverlight.DataGrid;
using C1DataGrid_WCF_DS.AdventureWorksDataService;

namespace C1DataGrid_WCF_DS
{
    /// <summary>
    /// A specialized ICollectionView class which performs sorting and filtering on the server through
    /// a WCF data service. The main entity handled by the ICollectionView is Product.
    /// </summary>
    public class WCFCollectionView : WCFCollectionViewBase<Product>
    {
        /// <summary>
        /// The data context to get the data from.
        /// </summary>
        private AdventureWorksEntities _dataContext;

        /// <summary>
        /// Used to keep track of the current new item on the ICollectionView.
        /// </summary>
        private Product _newItem;

        /// <summary>
        /// Used to keep track of the current editing item on the ICollectionView.
        /// </summary>
        private Product _editItem;

        /// <summary>
        /// Initializes a new instance of the WCFCollectionView class.
        /// </summary>
        /// <param name="dataContext">The data context.</param>
        /// <param name="owner">The C1DataGrid owner.</param>
        public WCFCollectionView(AdventureWorksEntities dataContext, C1DataGrid owner)
            : base(from p in dataContext.Product select p, owner)
        {
            _dataContext = dataContext;
        }

        /// <summary>
        /// Adds a new item to the underlying collection.
        /// </summary>
        /// <returns>The new item that is added to the collection.</returns>
        public override object AddNew()
        {
            _newItem = new Product();
            return _newItem;
        }

        /// <summary>
        /// Gets a value that indicates whether a new item can be added to the collection.
        /// </summary>
        /// <value>true if a new item can be added to the collection; otherwise, false.</value>
        public override bool CanAddNew
        {
            get { return true; }
        }

        /// <summary>
        /// Gets a value that indicates whether the collection view can discard pending
        /// changes and restore the original values of an edited object.
        /// </summary>
        /// <value>
        /// true if the collection view can discard pending changes and restore the original
        /// values of an edited object; otherwise, false.
        /// </value>
        public override bool CanCancelEdit
        {
            get { return true; }
        }

        /// <summary>
        /// Gets a value that indicates whether an item can be removed from the collection.
        /// </summary>
        /// <value>true if an item can be removed from the collection; otherwise, false.</value>
        public override bool CanRemove
        {
            get { return true; }
        }

        /// <summary>
        /// Ends the edit transaction and, if possible, restores the original value of
        /// the item.
        /// </summary>
        public override void CancelEdit()
        {
            IEditableObject editableItem = _editItem as IEditableObject;
            if (editableItem != null)
            {
                editableItem.CancelEdit();
            }
            _editItem = null;
        }

        /// <summary>
        /// Ends the add transaction and discards the pending new item.
        /// </summary>
        public override void CancelNew()
        {
            IEditableObject editableItem = _newItem as IEditableObject;
            if (editableItem != null)
            {
                editableItem.CancelEdit();
            }
            _newItem = null;
        }

        /// <summary>
        /// Ends the edit transaction and saves the pending changes.
        /// </summary>
        public override void CommitEdit()
        {
            if (_editItem != null)
            {
                IEditableObject editableItem = _editItem as IEditableObject;
                if (editableItem != null)
                {
                    editableItem.EndEdit();
                }
                _dataContext.UpdateObject(_editItem);
                SaveChanges();
                _editItem = null;
            }
        }

        /// <summary>
        /// Ends the add transaction and saves the pending new item.
        /// </summary>
        public override void CommitNew()
        {
            if (_newItem != null)
            {
                IEditableObject editableItem = _newItem as IEditableObject;
                if (editableItem != null)
                {
                    editableItem.EndEdit();
                }
                _dataContext.AddToProduct(_newItem);
                SaveChanges();
                _newItem = null;
            }
        }

        /// <summary>
        /// Gets the item that is being added during the current add transaction.
        /// </summary>
        /// <value>
        /// The item that is being added if System.ComponentModel.IEditableCollectionView.IsAddingNew
        /// is true; otherwise, null.
        /// </value>
        public override object CurrentAddItem
        {
            get { return _newItem; }
        }

        /// <summary>
        /// Gets the item in the collection that is being edited.
        /// </summary>
        /// <value>The item that is being edited if System.ComponentModel.IEditableCollectionView.IsEditingItem
        ///     is true; otherwise, null.</value>
        public override object CurrentEditItem
        {
            get { return _editItem; }
        }

        /// <summary>
        /// Begins an edit transaction on the specified item.
        /// </summary>
        /// <param name="item">The item to edit.</param>
        public override void EditItem(object item)
        {
            if (item != null)
            {
                IEditableObject editableItem = _editItem as IEditableObject;
                if (editableItem != null)
                {
                    editableItem.EndEdit();
                }
                _editItem = item as Product;
            }
        }

        /// <summary>
        /// Gets a value that indicates whether an add transaction is in progress.
        /// </summary>
        /// <value>true if an add transaction is in progress; otherwise, false.</value>
        public override bool IsAddingNew
        {
            get { return _newItem != null; }
        }

        /// <summary>
        /// Gets a value that indicates whether an edit transaction is in progress.
        /// </summary>
        /// <value>true if an edit transaction is in progress; otherwise, false.</value>
        public override bool IsEditingItem
        {
            get { return _editItem != null; }
        }

        /// <summary>
        /// Removes the specified item from the collection.
        /// </summary>
        /// <param name="item">The item to remove.</param>
        public override void Remove(object item)
        {
            _dataContext.DeleteObject(item);
            SaveChanges();
        }

        /// <summary>
        /// Removes the item at the specified position from the collection.
        /// </summary>
        /// <param name="index">Index of item to remove.</param>
        public override void RemoveAt(int index)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Saves the changes on the server.
        /// </summary>
        private void SaveChanges()
        {
            _dataContext.SaveChangesDefaultOptions = SaveChangesOptions.Batch;
            _dataContext.BeginSaveChanges(
                result =>
                {
                    _dataContext.EndSaveChanges(result);
                    Refresh();
                }, null);
        }
    }
}
