using System;
using System.IO;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

namespace MasterDetailWeb
{
    /// <summary>
    /// Summary description for DataService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService]
    public class DataService : System.Web.Services.WebService
    {
        [WebMethod]
        public byte[] GetData(string tables)
        {
            // create DataSet with connection string
            var ds = GetDataSet();

            // load data into DataSet
            ds.Fill(tables.Split(','));

            // persist to stream
            var ms = new MemoryStream();
            ds.WriteXml(ms, XmlWriteMode.WriteSchema);

            // return stream data
            return ms.ToArray();
        }

#if true // use transactions
        [WebMethod]
        public string UpdateData(byte[] dtAdded, byte[] dtModified, byte[] dtDeleted)
        {
            SmartDataSet ds = GetDataSet();
            string errorMessage = null;
            using (ds.Connection)
            {
                // open connection, begin transaction
                ds.Connection.Open();
                var transaction = ds.Connection.BeginTransaction();
                try
                {
                    // apply changes
                    UpdateData(dtAdded, DataRowState.Added);
                    UpdateData(dtModified, DataRowState.Modified);
                    UpdateData(dtDeleted, DataRowState.Deleted);

                    // commit transaction
                    transaction.Commit();
                }
                catch (Exception x)
                {
                    // error detected, rollback entire transaction
                    errorMessage = x.Message;
                    transaction.Rollback();
                }
            }

            // done
            return errorMessage;
        }
#else
        [WebMethod]
        public string UpdateData(byte[] dtAdded, byte[] dtModified, byte[] dtDeleted)
        {
            try
            {
                UpdateData(dtAdded, DataRowState.Added);
                UpdateData(dtModified, DataRowState.Modified);
                UpdateData(dtDeleted, DataRowState.Deleted);
                return null;
            }
            catch (Exception x)
            {
                return x.Message;
            }
        }
#endif
        void UpdateData(byte[] data, DataRowState state)
        {
            // no changes, no work
            if (data == null)
                return;

            // load data into dataset
            var ds = GetDataSet();
            var ms = new MemoryStream(data);
            ds.ReadXml(ms);
            ds.AcceptChanges();

            // update row states with changes
            foreach (DataTable dt in ds.Tables)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    switch (state)
                    {
                        case DataRowState.Added:
                            dr.SetAdded();
                            break;
                        case DataRowState.Modified:
                            dr.SetModified();
                            break;
                        case DataRowState.Deleted:
                            dr.Delete();
                            break;
                    }
                }
            }

            // update the database
            ds.Update();
        }

        SmartDataSet GetDataSet()
        {
            // get physical location of the mdb file
            string mdb = Path.Combine(
                Context.Request.PhysicalApplicationPath, @"App_Data\nwind.mdb");

            // check that the file exists
            if (!File.Exists(mdb))
            {
                string msg = string.Format("Cannot find database file {0}.", mdb);
                throw new FileNotFoundException(msg);
            }

            // make sure file is not read-only (source control often does this...)
            FileAttributes att = File.GetAttributes(mdb);
            if ((att & FileAttributes.ReadOnly) != 0)
            {
                att &= ~FileAttributes.ReadOnly;
                File.SetAttributes(mdb, att);
            }

            // use SmartDataSet helper class
            string connString = "provider=microsoft.jet.oledb.4.0;data source=" + mdb;

            // sample connection string for SQL Server Express (replace Initial Catalog value by the valid catalog name
            // string connString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=test;Data Source=.\\SQLEXPRESS";

            return new SmartDataSet(connString);
        }
    }
}
