//===============================================================================
// Microsoft patterns & practices
// Web Service Software Factory
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using Microsoft.Practices.SoftwareFactories.ServiceFactory.Editors.Grid.Design;
using System.Reflection;
using System.Windows.Forms.Design;

namespace Microsoft.Practices.SoftwareFactories.ServiceFactory.Editors.Grid
{
    /// <summary/>
    public class DataGridViewBinding<T> where T : new()
    {
        private bool bound = false;
        private DataGridView dataGridView;
        private IList<T> boundList;
        
        /// <summary/>
        public event EventHandler DataChanged;

        /// <summary>
        /// Binds the specified data grid view.
        /// </summary>
        /// <param name="dataGridView">The data grid view.</param>
        /// <param name="boundList">The bound list.</param>
        public void Bind(DataGridView dataGridView, IList<T> boundList)
        {
            this.dataGridView = dataGridView;
            this.boundList = boundList;

            foreach (DataGridViewColumn column in dataGridView.Columns)
            {
                PropertyDescriptor propDescr = TypeDescriptor.GetProperties(typeof(T))[column.DataPropertyName];
                column.ValueType = propDescr.PropertyType;
                DesignerColumn designerColumn = column as DesignerColumn;
                if (designerColumn != null)
                {
                    designerColumn.PropertyDescriptor = propDescr;
                }
            }

            if (bound)
                UnwireEvents();

            WireEvents();
            bound = true;
        }

        private void UnwireEvents()
        {
            dataGridView.UserAddedRow -= OnUserAddedRow;
            dataGridView.UserDeletingRow -= OnUserDeletingRow;
            dataGridView.CellValueChanged -= OnCellValueChanged;
            dataGridView.DataError -= OnCellDataError;
        }

        private void WireEvents()
        {
            dataGridView.UserAddedRow += OnUserAddedRow;
            dataGridView.UserDeletingRow += OnUserDeletingRow;
            dataGridView.CellValueChanged += OnCellValueChanged;
            dataGridView.DataError += OnCellDataError;
        }

        private void OnUserAddedRow(object sender, DataGridViewRowEventArgs e)
        {
            T item = new T();
            boundList.Add(item);

            foreach (DataGridViewCell cell in dataGridView.Rows[e.Row.Index - 1].Cells)
            {
                if (cell.Value != null && !string.IsNullOrEmpty(cell.OwningColumn.DataPropertyName))
                {
                    PropertyInfo prop = typeof(T).GetProperty(cell.OwningColumn.DataPropertyName);
                    prop.SetValue(item, cell.Value, null);
                }
            }
            FireDataChanged();
        }

        private void OnUserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            boundList.RemoveAt(e.Row.Index);
            FireDataChanged();
        }

        private void OnCellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < boundList.Count)
            {
                DataGridViewColumn column = dataGridView.Columns[e.ColumnIndex];
                if (!string.IsNullOrEmpty(column.DataPropertyName))
                {
                    T item = boundList[e.RowIndex];
                    if (Validation.ExecuteConfigurationValidatorAttributes(dataGridView[e.ColumnIndex, e.RowIndex], typeof(T), dataGridView.Site))
                    {
                        PropertyInfo prop = typeof(T).GetProperty(column.DataPropertyName);
                        prop.SetValue(item, dataGridView[e.ColumnIndex, e.RowIndex].Value, null);
                    }
                }
            }

            FireDataChanged();
        }

        private void OnCellDataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            if (e.Exception != null)
            {
                //IUIService svc = (IUIService)this.GetsGetSercice
                MessageBox.Show(e.Exception.Message, 
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, 
                    MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
                e.ThrowException = false;
            }
        }

        private void FireDataChanged()
        {
            if (DataChanged != null)
                DataChanged(this, EventArgs.Empty);
        }
    }
}
