using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using C1.Silverlight.Data;
using MasterDetail.DataService;

namespace MasterDetail
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();

            // get data from server
            LoadData();

            // hook up event handlers
            _gridCategories.SelectionChanged += _gridCategories_SelectionChanged;
            _btnAdd.Click += _btnAdd_Click;
            _btnRemove.Click += _btnRemove_Click;
            _btnCommit.Click += _btnCommit_Click;
        }

        // show products for the selected category
        void _gridCategories_SelectionChanged(object sender, EventArgs e)
        {
            var drv = _gridCategories.SelectedItem as DataRowView;
            if (drv != null)
            {
                var dv = _ds.Tables["Products"].DefaultView;
                if (dv.IsEditingItem) 
                {
                    dv.CommitEdit();
                }
                dv.RowFilter = string.Format("CategoryID = {0}", drv.GetData("CategoryID"));
            }
        }

        // add a new row
        private void _btnAdd_Click(object sender, RoutedEventArgs e)
        {
            DataTable dt = _ds.Tables["Categories"];
            DataRow newRow = dt.NewRow();
            newRow["CategoryName"] = "New category";
            newRow["Description"] = "This is a new category...";
            dt.Rows.Add(newRow);
        }

        // delete a row
        private void _btnRemove_Click(object sender, RoutedEventArgs e)
        {
            DataRowView drv = _gridCategories.SelectedItem as DataRowView;
            if (drv != null)
            {
                DataRow dr = drv.GetRow();
                dr.Delete();
            }
        }

        // commit changes to server
        private void _btnCommit_Click(object sender, RoutedEventArgs e)
        {
#if true
            string msg =
                "This functionality is disabled to prevent changes to the database on our site.\r\n" +
                "To see it in action, please download the Studio, edit your local copy of \r\n" +
                "MasterDetail.Page.btnCommit_Click method according to the comments in code and run the sample locally.\r\n" +
                "To see a commented version of the source code, please download the 'ComponentOne Data for Silverlight' document.";
            MessageBox.Show(msg, "Functionality Disabled", MessageBoxButton.OK);
#else
            SaveData();
#endif
        }

        // save data back into the database
        void SaveData()
        {
            if (_ds != null)
            {
                // get changes of each type
                byte[] dtAdded = GetChanges(DataRowState.Added);
                byte[] dtModified = GetChanges(DataRowState.Modified);
                byte[] dtDeleted = GetChanges(DataRowState.Deleted);

                // invoke service
                var svc = GetDataService();
                svc.UpdateDataCompleted += svc_UpdateDataCompleted;
                svc.UpdateDataAsync(dtAdded, dtModified, dtDeleted);
            }
        }
        byte[] GetChanges(DataRowState state)
        {
            DataSet ds = _ds.GetChanges(state);
            if (ds != null)
            {
                MemoryStream ms = new MemoryStream();
                ds.WriteXml(ms);
                return ms.ToArray();
            }
            return null;
        }
        void svc_UpdateDataCompleted(object sender, UpdateDataCompletedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Result))
            {
                throw new Exception("Error updating data on the server: " + e.Result);
            }
            _tbStatus.Text = "Changes accepted by server.";
            _ds.AcceptChanges();
        }

        // load data from server
        DataSet _ds = null;
        void LoadData()
        {
            // invoke web service
            var svc = GetDataService();
            svc.GetDataCompleted += svc_GetDataCompleted;
            svc.GetDataAsync("Categories,Products");
        }
        void svc_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
        {
            // handle errors
            if (e.Error != null)
            {
                _tbStatus.Text = "Error downloading data...";
                return;
            }

            // parse data stream from server (DataSet as XML)
            _tbStatus.Text = string.Format(
              "Got data, {0:n0} kBytes", e.Result.Length / 1024);
            var ms = new MemoryStream(e.Result);
            _ds = new DataSet();
            _ds.EnforceConstraints = false;
            _ds.ReadXml(ms);
            _ds.EnforceConstraints = true;

            // got the data, bind controls to it
            BindData();
        }
        // get data service relative to current host/domain
        DataServiceSoapClient GetDataService()
        {
            // increase buffer size
            var binding = new System.ServiceModel.BasicHttpBinding();
            binding.MaxReceivedMessageSize = 2147483647; // int.MaxValue
            binding.MaxBufferSize = 2147483647; // int.MaxValue

            // get absolute service address
            Uri uri = GetAbsoluteUri("DataService.asmx");
            var address = new System.ServiceModel.EndpointAddress(uri);

            // return new service client
            return new DataServiceSoapClient(binding, address);
        }
        public static Uri GetAbsoluteUri(string relativeUri)
        {
            Uri uri = System.Windows.Browser.HtmlPage.Document.DocumentUri;
            string uriString = uri.AbsoluteUri;
            int ls = uriString.LastIndexOf('/');
            return new Uri(uriString.Substring(0, ls + 1) + relativeUri);
        }
        void BindData()
        {
            // get the tables we want
            DataTable dtCategories = _ds.Tables["Categories"];
            DataTable dtProducts = _ds.Tables["Products"];

            // populate categories grid
            _gridCategories.ItemsSource =
                new DataView(dtCategories,
                    "CategoryID", "CategoryName", "Description");

            // populate products categories grid
            _gridProducts.ItemsSource = dtProducts.DefaultView;
        }
    }
}
