using System;
// supports generic IList
using System.Collections.Generic;
// supports "AddingNewEventArgs"
using System.ComponentModel;
// supports LINQ query for contacts
using System.Linq;
// supports "Assembly" class
using System.Reflection;
using System.Windows.Forms;
using Model;
using Telerik.WinControls.UI;
using System.ServiceModel;
using WinFormClient.ServiceReference1;

namespace WinFormClient
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    #region private fields

    // reference to our WCF service client    
    private ServiceReference1.Service1Client _client =
      new ServiceReference1.Service1Client();

    // wrapper for OpenAccess Container and ChangeSets
    private ContainerHelper _containerHelper = new ContainerHelper();

    #endregion

    #region properties

    // currently selected group name
    private string CurrentGroupName
    {
      get
      {
        int index = cbContactGroups.SelectedIndex;
        if (index != -1)
        {
          return cbContactGroups.Items[index].Text;
        }
        return String.Empty;
      }
    }

    #endregion

    #region helper methods

    // load contact groups to combo
    private void LoadCombo()
    {
      // get all contact groups as a ChangeSet from the service,
      // load the ChangeSet to the container and return an
      // IList of ContactGroup
      IList<ContactGroup> contactGroups =
        _containerHelper.Load<ContactGroup>(_client.GetContactGroups());

      // bind to the grid and display the ContactGroupName 
      // in the combo
      cbContactGroups.DataSource = contactGroups;
      cbContactGroups.DisplayMember = "ContactGroupName";
    }

    // load all contacts for a group to grid
    private void LoadGrid()
    {
      // get all Contacts as a ChangeSet from the service,
      // load the ChangeSet to the container and return
      // an IList of Contacts
      IList<Contact> contacts =
        _containerHelper.Load<Contact>(_client.GetContacts());

      // filter the contacts for only those with the currently selected
      // group name
      List<Contact> filteredContacts =
        contacts.Where(c => c.ContactGroup.ContactGroupName.Equals(
          this.CurrentGroupName)).ToList();

      RemovableBindingList<Contact> bindingList =
        new RemovableBindingList<Contact>(filteredContacts);
      bindingList.AddingNew +=
        new AddingNewEventHandler(bindingList_AddingNew);
      bindingList.RemovingItem += new
        EventHandler<RemovingItemEventArgs>(bindingList_RemovingItem);

      // bind to the grid
      gvContacts.DataSource = bindingList;

      // hide the contact group column and fit the remaining columns
      if (gvContacts.MasterGridViewTemplate.Columns.Count > 1)
        gvContacts.MasterGridViewTemplate.Columns[2].IsVisible = false;
      gvContacts.MasterGridViewTemplate.BestFitColumns();
    }

    void bindingList_RemovingItem(object sender, RemovingItemEventArgs args)
    {
      _containerHelper.Remove(args.Item);
    }

    // create a new contact and add to the grid and to the container.
    // Note: e.NewObject shows up in the "add new row" before being added
    // to the grid data.
    void bindingList_AddingNew(object sender, AddingNewEventArgs e)
    {
      ContactGroup contactGroup =
        (cbContactGroups.SelectedItem as RadComboBoxItem).Tag as ContactGroup;

      e.NewObject = new Contact
      {
        ContactName = "New " + contactGroup.ContactGroupName,
        ContactGroup = contactGroup,
        Phone = String.Empty
      };
      _containerHelper.Add(e.NewObject);
    }

    #endregion

    #region event handlers

    private void Form1_Load(object sender, EventArgs e)
    {
      LoadCombo();
      LoadGrid();
    }

    private void cbContactGroups_SelectedIndexChanged(
      object sender, EventArgs e)
    {
      LoadGrid();
    }

    // save off currently selected ContactGroup
    private void cbContactGroups_ItemDataBound(object sender,
      ItemDataBoundEventArgs e)
    {
      e.DataBoundItem.Tag = e.DataItem as ContactGroup;
    }

// send current changes to service
private void btnSave_Click(object sender, EventArgs e)
{
  try
  {
    // pass SaveContacts as a delegate
    _containerHelper.Save(_client.SaveContacts);
  }
  catch (FaultException<ContactFault> ex)
  {
    // construct an error message that lists the invalid
    // contact names
    const string format = "{0}. Rolling back changes for \"{1}\""; 
    string contactNames = 
      string.Join(",", (ex.Detail as ContactFault).ContactNames);
    string message = String.Format(format,
      ex.Reason.GetMatchingTranslation().Text, contactNames); 

    // use the FaultException to get the reason, code, subcode and respond.
    MessageBox.Show(ex.Reason.GetMatchingTranslation().Text +
      ". Rolling back changes for " + contactNames);        

    // remove "new" Contact objects and reload grid
    _containerHelper.Reset<Contact>();
    LoadGrid();
  }
}

    #endregion
  }
}
