using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HydroDesktop.Interfaces;
using HydroDesktop.Interfaces.ObjectModel;
using System.Data;
using System.Data.Common;
using System.Globalization;

namespace HydroDesktop.Database
{
	/// <summary>
	/// This class is responsible for communication with the 'Metadata Cache' database
    /// This is an alternative implementation internally using SQL queries instead of NHibernate.
    /// This is to compare saving speed.
	/// </summary>
	public class MetadataCacheManagerSQL
	{
		#region Variables

        //helper class which communicates with the database
        private DbOperations _db;

		// lookup caches used by the SaveSeries method
		private Dictionary<string, Site> _siteCache = new Dictionary<string, Site> ();
		private Dictionary<string, Variable> _variableCache = new Dictionary<string, Variable> ();
		private Dictionary<string, Method> _methodCache = new Dictionary<string, Method> ();
		private Dictionary<string, QualityControlLevel> _qualControlCache = new Dictionary<string, QualityControlLevel> ();
		private Dictionary<string, Source> _sourcesCache = new Dictionary<string, Source> ();

		#endregion

		#region Constructor
		/// <summary>
		/// Creates a new instance of the manager given a connection string
		/// </summary>
		/// <param name="dbType">The type of the database (SQLite, SQLServer, ...)</param>
		/// <param name="connectionString">The connection string</param>
		public MetadataCacheManagerSQL ( DatabaseTypes dbType, string connectionString )
		{
            _db = new DbOperations(connectionString, dbType);
		}
        /// <summary>
        /// Creates a new instance of the manager using a DbOperations object
        /// </summary>
        /// <param name="db">The dbOperations object</param>
        public MetadataCacheManagerSQL(DbOperations db)
        {
            _db = db;
        }
		#endregion

		private bool NumberIsBetween ( double numberToCheck, double bounds1, double bounds2, bool inclusiveAtBounds )
		{
			double lowerBound, upperBound;

			if ( bounds1 > bounds2 )
			{
				lowerBound = bounds2;
				upperBound = bounds1;
			}
			else
			{
				lowerBound = bounds1;
				upperBound = bounds2;
			}

			if ( inclusiveAtBounds == true )
			{
				return (numberToCheck >= lowerBound && numberToCheck <= upperBound);
			}
			else
			{
				return (numberToCheck > lowerBound && numberToCheck < upperBound);
			}
		}

		private bool EnvelopesIntersect ( double env1xMin, double env1xMax, double env1yMin, double env1yMax, double env2xMin, double env2xMax, double env2yMin, double env2yMax )
		{
			return (((NumberIsBetween ( env1xMin, env2xMin, env2xMax, true ) || NumberIsBetween ( env1xMax, env2xMin, env2xMax, true )) && (NumberIsBetween ( env1yMin, env2yMin, env2yMax, true ) || NumberIsBetween ( env1yMax, env2yMin, env2yMax, true ))) ||
					((NumberIsBetween ( env2xMin, env1xMin, env1xMax, true ) || NumberIsBetween ( env2xMax, env1xMin, env1xMax, true )) && (NumberIsBetween ( env2yMin, env1yMin, env1yMax, true ) || NumberIsBetween ( env2yMax, env1yMin, env1yMax, true ))));
		}

		private bool PointIntersectsEnvelope ( double pointX, double pointY, double envXMin, double envXMax, double envYMin, double envYMax )
		{
			return (NumberIsBetween ( pointX, envXMin, envXMax, true ) && NumberIsBetween ( pointY, envYMin, envYMax, true ));
		}

		private bool DateRangesOverlap ( DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2 )
		{
			return (((startDate1 >= startDate2) && (startDate1 <= endDate2)) ||
					((endDate1 >= startDate2) && (endDate1 <= endDate2)) ||
					((startDate2 >= startDate1) && (startDate2 <= endDate1)) ||
					((endDate2 >= startDate1) && (endDate2 <= endDate1)));
		}

        

		#region Public Methods



		/// <summary>
		/// Get all data services saved in the metadata cache database
		/// </summary>
		public IList<DataServiceInfo> GetAllServices ()
		{
			string sql = "SELECT * FROM DataServices";

            System.Data.DataTable tbl = _db.LoadTable("services", sql);

            IList<DataServiceInfo> services = null;

			services = new List<DataServiceInfo> ();
			if ( tbl.Rows.Count > 0 )
            {
                foreach(System.Data.DataRow row in tbl.Rows)
                {
                    services.Add(ServiceFromDataRow(row));
                }
            }
            return services;
		}

        /// <summary>
        /// Get data service by serviceUrl
        /// </summary>
        /// <param name="serviceURL">ServiceUrl</param>
        /// <returns>Data service or null (if not found)</returns>
        public DataServiceInfo GetServiceByServiceUrl(string serviceURL)
        {
            var sql = string.Format("SELECT * FROM DataServices where ServiceID = '{0}'", serviceURL);
            var tbl = _db.LoadTable("services", sql);
            return tbl.Rows.Count == 1 ? ServiceFromDataRow(tbl.Rows[0]) : null;
        }

	    #endregion
        /// <summary>
        /// Gets all sites in box (not implemented)
        /// </summary>
        /// <param name="xMin">minimum x (longitude)</param>
        /// <param name="xMax">maximum x (lognitude)</param>
        /// <param name="yMin">minimum y (latitude)</param>
        /// <param name="yMax">maximum y (latitude)</param>
		public void GetSitesInBox ( double xMin, double xMax, double yMin, double yMax )
		{
			throw new System.NotImplementedException ();
		}
        /// <summary>
        /// Gets a list of all services within the bounding box
        /// </summary>
        /// <param name="xMin">minimum x (longitude)</param>
        /// <param name="xMax">maximum x (lognitude)</param>
        /// <param name="yMin">minimum y (latitude)</param>
        /// <param name="yMax">maximum y (latitude)</param>
        /// <returns>the list of serviceInfo objects matching the criteria</returns>
		public IList<DataServiceInfo> GetServicesInBox ( double xMin, double xMax, double yMin, double yMax )
		{
			//IList<DataServiceInfo> services = null;

            string sql = "SELECT * FROM DataServicesCache WHERE " +
                String.Format("EastLongitude BETWEEN {0} AND {1}", xMin, xMax) +
                String.Format("OR WestLongitude BETWEEN {0} AND {1}", xMin, xMax) +
                String.Format("OR NorthLatitude BETWEEN {0} AND {1}", yMin, yMax) +
                String.Format("OR SouthLatitude BETWEEN {0} AND {1}", yMin, yMax);

            DataTable tbl = _db.LoadTable(sql);

            IList<DataServiceInfo> services = null;

            if (tbl.Rows.Count > 0)
            {
                services = new List<DataServiceInfo>();
                foreach (System.Data.DataRow row in tbl.Rows)
                {
                    services.Add(ServiceFromDataRow(row));
                }
            }
            return services;
		}

        private string DetailedSeriesSQLQuery()
        {
            string sql = "SELECT SeriesID, " +
                "SiteName, SiteCode, Latitude, Longitude, " +
                "VariableName, VariableCode, DataType, ValueType, Speciation, SampleMedium, " +
                "TimeSupport, GeneralCategory, " +
                "TimeUnitsName, " +
                "BeginDateTime, EndDateTime, DataSeriesCache.ValueCount, ServiceTitle, ServiceEndpointURL " +
                "FROM DataSeriesCache " +
                "LEFT JOIN SitesCache ON DataSeriesCache.SiteID = SitesCache.SiteID " +
                "LEFT JOIN VariablesCache ON DataSeriesCache.VariableID = VariablesCache.VariableID " + 
                "LEFT JOIN DataServices ON DataSeriesCache.ServiceID = DataServices.ServiceID";
            return sql;
        }

        private DataServiceInfo ServiceFromDataRow(System.Data.DataRow row)
        {
            DataServiceInfo dsi = new DataServiceInfo();
            dsi.Id = DataReader.ReadInteger(row["ServiceID"]);
            dsi.ServiceCode = DataReader.ReadString(row["ServiceCode"]);
            dsi.ServiceName = DataReader.ReadString(row["ServiceName"]);
            dsi.ServiceType = DataReader.ReadString(row["ServiceType"]);
            dsi.Version = DataReader.ReadDouble(row["ServiceVersion"]);
            dsi.Protocol = DataReader.ReadString(row["ServiceProtocol"]);
            dsi.EndpointURL = DataReader.ReadString(row["ServiceEndpointURL"]);
            dsi.DescriptionURL = DataReader.ReadString(row["ServiceDescriptionURL"]);
            dsi.NorthLatitude = DataReader.ReadDouble(row["NorthLatitude"]);
            dsi.SouthLatitude = DataReader.ReadDouble(row["SouthLatitude"]);
            dsi.EastLongitude = DataReader.ReadDouble(row["EastLongitude"]);
            dsi.WestLongitude = DataReader.ReadDouble(row["WestLongitude"]);
            dsi.Abstract = DataReader.ReadString(row["Abstract"]);
            dsi.ContactEmail = DataReader.ReadString(row["ContactEmail"]);
            dsi.ContactName = DataReader.ReadString(row["ContactName"]);
            dsi.Citation = DataReader.ReadString(row["Citation"]);
            dsi.IsHarvested = DataReader.ReadBoolean(row["IsHarvested"]);
            dsi.HarveDateTime = DataReader.ReadDateTime(row["HarveDateTime"]);
            dsi.ServiceTitle = DataReader.ReadString(row["ServiceTitle"]);
            return dsi;
        }

        private Variable VariableFromDataRow(DataRow row)
        {
            Variable v = new Variable();
            v.Name = Convert.ToString(row["VariableName"]);
            v.Code = Convert.ToString(row["VariableCode"]);
            v.DataType = Convert.ToString(row["DataType"]);
            v.ValueType = Convert.ToString(row["ValueType"]);
            v.Speciation = Convert.ToString(row["Speciation"]);
            v.SampleMedium = Convert.ToString(row["SampleMedium"]);
            v.TimeSupport = Convert.ToDouble(row["TimeSupport"]);
            v.GeneralCategory = Convert.ToString(row["GeneralCategory"]);
            v.VariableUnit = Unit.Unknown;
            v.VariableUnit.Name = Convert.ToString(row["VariableUnitsName"]);
            v.VariableUnit.Abbreviation = Convert.ToString(row["VariableUnitsAbbreviation"]);
            v.TimeUnit = Unit.UnknownTimeUnit;
            v.TimeUnit.Name = Convert.ToString(row["TimeUnitsName"]);
            v.IsRegular = Convert.ToBoolean(row["IsRegular"]);
            v.NoDataValue = Convert.ToDouble(row["NoDataValue"]);
            v.Id = Convert.ToInt32(row["VariableID"]);
            return v;
        }

        private SeriesMetadata SeriesFromDataRow(DataRow row)
        {
            Site site = new Site();
            site.Name = Convert.ToString(row["SiteName"]);
            site.Code = Convert.ToString(row["SiteCode"]);
            site.Latitude = Convert.ToDouble(row["Latitude"]);
            site.Longitude = Convert.ToDouble(row["Longitude"]);

            Variable v = new Variable();
            v.Name = Convert.ToString(row["VariableName"]);
            v.Code = Convert.ToString(row["VariableCode"]);
            v.DataType = Convert.ToString(row["DataType"]);
            v.ValueType = Convert.ToString(row["ValueType"]);
            v.Speciation = Convert.ToString(row["Speciation"]);
            v.SampleMedium = Convert.ToString(row["SampleMedium"]);
            v.TimeSupport = Convert.ToDouble(row["TimeSupport"]);
            v.GeneralCategory = Convert.ToString(row["GeneralCategory"]);
            v.VariableUnit = Unit.Unknown;
            v.VariableUnit.Name = Convert.ToString(row["VariableUnitsName"]);
            v.TimeUnit = Unit.UnknownTimeUnit;
            v.TimeUnit.Name = Convert.ToString(row["TimeUnitsName"]);

            Method m = Method.Unknown;
            //m.Description = Convert.ToString(row["MethodDescription"]);

            Source src = Source.Unknown;
            //src.Description = Convert.ToString(row["SourceDescription"]);
            src.Organization = Convert.ToString(row["Organization"]);
            src.Citation = Convert.ToString(row["Citation"]);

            QualityControlLevel qc = QualityControlLevel.Unknown;
            //qc.Code = Convert.ToString(row["QualityControlLevelCode"]);
            //qc.Definition = Convert.ToString(row["QualityControlLevelDefinition"]);

            SeriesMetadata newSeries = new SeriesMetadata(site, v, m, qc, src);
            newSeries.BeginDateTime = Convert.ToDateTime(row["BeginDateTime"]);
            newSeries.EndDateTime = Convert.ToDateTime(row["EndDateTime"]);
            newSeries.BeginDateTimeUTC = Convert.ToDateTime(row["BeginDateTimeUTC"]);
            newSeries.EndDateTimeUTC = Convert.ToDateTime(row["EndDateTimeUTC"]);
            newSeries.ValueCount = Convert.ToInt32(row["ValueCount"]);

            DataServiceInfo servInfo = new DataServiceInfo();
            servInfo.EndpointURL = Convert.ToString(row["ServiceEndpointURL"]);
            //servInfo.ServiceCode = Convert.ToString(row["ServiceCode"]);
            newSeries.DataService = servInfo;

            return newSeries;
        }

        /// <summary>
        /// Converts DataRow into SeriesDataCart
        /// </summary>
        /// <param name="row">DataRow to convert</param>
        /// <returns>SeriesDataCart</returns>
        public SeriesDataCart SeriesDataCartFromRow(DataRow row)
        {
            var result = new SeriesDataCart();
            result.SiteName = Convert.ToString(row["SiteName"]);
            result.SiteCode = Convert.ToString(row["SiteCode"]);
            result.Latitude = Convert.ToDouble(row["Latitude"], CultureInfo.InvariantCulture);
            result.Longitude = Convert.ToDouble(row["Longitude"], CultureInfo.InvariantCulture);

            //Variable v = new Variable();
            result.VariableName = Convert.ToString(row["VariableName"]);
            result.VariableCode = Convert.ToString(row["VariableCode"]);
            result.DataType = Convert.ToString(row["DataType"]);
            result.ValueType = Convert.ToString(row["ValueType"]);
            
            result.SampleMedium = Convert.ToString(row["SampleMedium"]);
            result.TimeSupport = Convert.ToDouble(row["TimeSupport"], CultureInfo.InvariantCulture);
            result.GeneralCategory = Convert.ToString(row["GeneralCategory"]);
            result.TimeUnit = Convert.ToString(row["TimeUnitsName"]);

            result.BeginDate = Convert.ToDateTime(row["BeginDateTime"], CultureInfo.InvariantCulture);
            result.EndDate = Convert.ToDateTime(row["EndDateTime"], CultureInfo.InvariantCulture);
            result.ValueCount = Convert.ToInt32(row["ValueCount"]);

            result.ServURL = Convert.ToString(row["ServiceEndpointURL"]);
            result.ServCode = Convert.ToString(row["ServiceTitle"]);

            return result;
        }
        /// <summary>
        /// Gets a list of all data series within the bounding box
        /// </summary>
        /// <param name="xMin">minimum X (longitude)</param>
        /// <param name="xMax">maximum X (longitude)</param>
        /// <param name="yMin">minimum Y (latitude)</param>
        /// <param name="yMax">maximum Y (latitude)</param>
        /// <returns>the list of data series metadata matching the search criteria</returns>
		public IList<SeriesDataCart> GetSeriesListInBox ( double xMin, double xMax, double yMin, double yMax )
		{
            string sql1 = DetailedSeriesSQLQuery();
            string sqlWhere = " WHERE Latitude > @minlat AND Latitude <= @maxlat AND Longitude > @minlon AND Longitude <= @maxlon";
            string sql = sql1 + sqlWhere;

            DbCommand cmd = _db.CreateCommand(sql);
            //lat, lon parameters
            _db.AddParameter(cmd, "@minlat", DbType.Double);
            _db.AddParameter(cmd, "@maxlat", DbType.Double);
            _db.AddParameter(cmd, "@minlon", DbType.Double);
            _db.AddParameter(cmd, "@maxlon", DbType.Double);

            cmd.Parameters[0].Value = yMin;
            cmd.Parameters[1].Value = yMax;
            cmd.Parameters[2].Value = xMin;
            cmd.Parameters[3].Value = xMax;

            DataTable seriesTable = _db.LoadTable("seriesTable", cmd);
            
            //DataTable seriesTable = _db.LoadTable("seriesTable", sql);

            IList<SeriesDataCart> lst = new List<SeriesDataCart>();
            foreach (DataRow row in seriesTable.Rows)
            {
                SeriesDataCart newSeries = SeriesDataCartFromRow(row);
                lst.Add(newSeries);
            }

            return lst;
		}

        /// <summary>
        /// Gets a data table of all data series within the bounding box
        /// </summary>
        /// <param name="xMin">minimum X (longitude)</param>
        /// <param name="xMax">maximum X (longitude)</param>
        /// <param name="yMin">minimum Y (latitude)</param>
        /// <param name="yMax">maximum Y (latitude)</param>
        /// <param name="conceptCodes">array of Concept keywords</param>
        /// <param name="startDate">start date</param>
        /// <param name="endDate">end date</param>
        /// <param name="networkIDs">larray of service codes</param>
        /// <returns>the list of data series metadata matching the search criteria</returns>
		public DataTable GetSeriesDataTableInBox ( double xMin, double xMax, double yMin, double yMax, string[] conceptCodes, DateTime startDate, DateTime endDate, int[] networkIDs )
		{
            string sql1 = DetailedSeriesSQLQuery();
            string sqlWhere1 = " WHERE Latitude > @minlat AND Latitude < @maxlat AND Longitude > @minlon AND Longitude < @maxlon";
            string sqlWhere2 = "";

            //concept keywords | variable names
            if (conceptCodes == null)
            {
                sqlWhere2 = "";
            }
            else if (conceptCodes.Length == 0)
            {
                sqlWhere2 = "";
            }
            else if (string.IsNullOrEmpty(conceptCodes[0]))
            {
                sqlWhere2 = "";
            }
            else if (conceptCodes.Length == 1)
            {
                sqlWhere2 = " AND VariableName = '" + conceptCodes[0] + "'";
            }
            else if (conceptCodes.Length > 1)
            {
                sqlWhere2 = " AND VariableName IN (";
                foreach (string keyword in conceptCodes)
                {
                    sqlWhere2 += "'" + keyword + "',";
                }
                if (sqlWhere2.EndsWith(","))
                {
                    sqlWhere2 = sqlWhere2.Substring(0, sqlWhere2.Length - 1);
                }
                sqlWhere2 += ")";
            }

            //date and time
            string sqlWhere3 = " AND ( (BeginDateTime < @p1 AND EndDateTime > @p2) OR (BeginDateTime > @p1 AND BeginDateTime <= @p2) OR (EndDateTime > @p1 AND EndDateTime <= @p2) )";
            
            //network IDs
            string sqlWhere4 = "";

            if (networkIDs != null)
            {
                if (networkIDs.Length == 1)
                {
                    sqlWhere4 = " AND DataSeriesCache.ServiceID = " + networkIDs[0];
                }
                else if (networkIDs.Length > 1)
                {
                    sqlWhere4 = " AND DataSeriesCache.ServiceID IN (";
                    foreach (int servID in networkIDs)
                    {
                        sqlWhere4 += servID.ToString() + ",";
                    }
                    if (sqlWhere4.EndsWith(","))
                    {
                        sqlWhere4 = sqlWhere4.Substring(0, sqlWhere4.Length - 1);
                    }
                    sqlWhere4 += ")";
                }
            }

            string sql = sql1 + sqlWhere1 + sqlWhere2 + sqlWhere3 + sqlWhere4;
            DbCommand cmd = _db.CreateCommand(sql);
            //lat, lon parameters
            _db.AddParameter(cmd, "@minlat", DbType.Double);
            _db.AddParameter(cmd, "@maxlat", DbType.Double);
            _db.AddParameter(cmd, "@minlon", DbType.Double);
            _db.AddParameter(cmd, "@maxlon", DbType.Double);
            
            _db.AddParameter(cmd, "@p1", DbType.DateTime);
            _db.AddParameter(cmd, "@p2", DbType.DateTime);
            cmd.Parameters[0].Value = yMin;
            cmd.Parameters[1].Value = yMax;
            cmd.Parameters[2].Value = xMin;
            cmd.Parameters[3].Value = xMax;
            cmd.Parameters[4].Value = startDate;
            cmd.Parameters[5].Value = endDate;
            
            var seriesTable = _db.LoadTable("seriesTable", cmd);
            return seriesTable;
		}

        /// <summary>
        /// Gets a list of all data series within the bounding box
        /// </summary>
        /// <param name="xMin">minimum X (longitude)</param>
        /// <param name="xMax">maximum X (longitude)</param>
        /// <param name="yMin">minimum Y (latitude)</param>
        /// <param name="yMax">maximum Y (latitude)</param>
        /// <param name="conceptCodes">array of Concept keywords</param>
        /// <param name="startDate">start date</param>
        /// <param name="endDate">end date</param>
        /// <param name="networkIDs">larray of service codes</param>
        /// <returns>the list of data series metadata matching the search criteria</returns>
        public IList<SeriesDataCart> GetSeriesListInBox(double xMin, double xMax, double yMin, double yMax, string[] conceptCodes, DateTime startDate, DateTime endDate, int[] networkIDs)
        {
            var dt = GetSeriesDataTableInBox(xMin, xMax, yMin, yMax, conceptCodes, startDate, endDate, networkIDs);
            return (from DataRow row in dt.Rows select SeriesDataCartFromRow(row)).ToList();
        }

	    /// <summary>
		/// Gets all variables that are currently stored in the metadata cache database
		/// </summary>
		public IList<Variable> GetVariables()
		{
            string sql = "SELECT * FROM VariablesCache";

            DataTable tbl = _db.LoadTable(sql);
            List<Variable> variables = new List<Variable>();
            foreach (DataRow row in tbl.Rows)
            {
                Variable v = VariableFromDataRow(row);
                variables.Add(v);
            }
            return variables;
		}

        /// <summary>
        /// Gets all variables that are currently stored in the metadata cache database
        /// </summary>
        public IList<Variable> GetVariablesByService(int serviceID)
        {
            string sql = "SELECT * FROM VariablesCache WHERE serviceID=" + serviceID;

            DataTable tbl = _db.LoadTable(sql);
            List<Variable> variables = new List<Variable>();
            foreach (DataRow row in tbl.Rows)
            {
                Variable v = VariableFromDataRow(row);
                variables.Add(v);
            }
            return variables;
        }

        /// <summary>
        /// Gets the names of all variables accessible by the specific web service
        /// </summary>
        /// <returns></returns>
        public IList<string> GetVariableNamesByService(int serviceID)
        {
            string sql = "SELECT DISTINCT VariableName FROM VariablesCache WHERE ServiceID = " + serviceID;
            DataTable tbl = _db.LoadTable(sql);
            List<string> variableNames = new List<string>();
            foreach (DataRow row in tbl.Rows)
            {
                variableNames.Add(row["VariableName"].ToString());
            }
            return variableNames;
        }

        /// <summary>
        /// Gets the names of all variables that are currently stored in the metadata cache DB
        /// </summary>
        /// <returns></returns>
        public IList<string> GetVariableNames()
        {
            string sql = "SELECT DISTINCT VariableName FROM VariablesCache";
            DataTable tbl = _db.LoadTable(sql);
            List<string> variableNames = new List<string>();
            foreach (DataRow row in tbl.Rows)
            {
                variableNames.Add(row["VariableName"].ToString());
            }
            return variableNames;
        }

		/// <summary>
		/// Saves a new data service object to the database. If an entry with the same
		/// web service URL already exists in the database, update it.
		/// </summary>
		/// <param name="service">the ServiceInfo object to be saved to the DB</param>
		public void SaveDataService ( DataServiceInfo service )
		{
            string sqlInsert =
                "INSERT INTO DataServices(" +
                "ServiceCode, ServiceName, ServiceType, ServiceVersion, ServiceProtocol, " +
                "ServiceEndpointURL, ServiceDescriptionURL, NorthLatitude, SouthLatitude, EastLongitude, WestLongitude, " +
                "Abstract, ContactName, ContactEmail, Citation, IsHarvested, HarveDateTime, ServiceTitle) " +
                "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
            
            using (DbConnection conn = _db.CreateConnection())
            {
                conn.Open();

                using (DbTransaction tran = conn.BeginTransaction())
                {
                    using (DbCommand cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = sqlInsert;
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.ServiceCode));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.ServiceName));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.ServiceType));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, service.Version));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.Protocol));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.EndpointURL));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.DescriptionURL));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, service.NorthLatitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, service.SouthLatitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, service.EastLongitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, service.WestLongitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.Abstract));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.ContactName));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.ContactEmail));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.Citation));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Boolean, service.IsHarvested));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.DateTime, service.HarveDateTime));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, service.ServiceTitle));

                        cmd.ExecuteNonQuery();
                    }
                    tran.Commit();
                }
            }
		}

		/// <summary>
		/// Deletes all entries in the metadata cache database that were
		/// added by the data service
		/// </summary>
        /// <param name="service">The serviceInfo object to be deleted</param>
		/// <param name="deleteService">Set to true if the record in the DataServices
		/// table should also be deleted. Set to false if the record in the DataServices
		/// table should be kept</param>
		/// <returns>The total number of records deleted</returns>
		public int DeleteRecordsForService ( DataServiceInfo service, bool deleteService )
		{
            string serviceID = service.Id.ToString();

            string sqlDelete = "DELETE FROM DataSeriesCache WHERE ServiceID = " + serviceID + "; " +
                "DELETE FROM SitesCache WHERE ServiceID = " + serviceID + "; " +
                "DELETE FROM VariablesCache WHERE ServiceID = " + serviceID + "; " +
                "DELETE FROM SourcesCache WHERE ServiceID = " + serviceID + "; " +
                "DELETE FROM MethodsCache WHERE ServiceID = " + serviceID + "; " +
                "DELETE FROM QualityControlLevelsCache WHERE ServiceID = " + serviceID + ";" + 
				"DELETE FROM ISOMetadataCache WHERE ServiceID = " + serviceID + ";";

			if ( deleteService == true )
			{
				sqlDelete += "DELETE FROM DataServices WHERE ServiceID = " + serviceID + ";";
			}

            using (DbConnection conn = _db.CreateConnection())
            {
                conn.Open();

                using (DbTransaction tran = conn.BeginTransaction())
                {
                    using (DbCommand cmd01 = conn.CreateCommand())
                    {
                        cmd01.CommandText = sqlDelete;
                        cmd01.ExecuteNonQuery();
                    }
                    tran.Commit();
                }

            }
            return 0;
		}


        /// <summary>
        /// Deletes a series given it's ID. The series is only deleted when it belongs to one theme.
        /// </summary>
        /// <param name="seriesID">The database ID of the series</param>
        /// <returns>true if series was deleted, false otherwise</returns>
        public bool DeleteSeries(int seriesID)
        {
            int siteID = 0;
            int variableID = 0;
            int sourceID = 0;
            int qualityID = 0;
            int methodID = 0;


            string sqlSeries = "SELECT SiteID, VariableID, MethodID, SourceID, QualityControlLevelID " +
                "FROM DataSeriesCache WHERE SeriesID = " + seriesID;

            DataTable seriesTable = _db.LoadTable("seriesTable", sqlSeries);
            
            if (seriesTable.Rows.Count == 0) return false;

            DataRow seriesRow = seriesTable.Rows[0];
            siteID = Convert.ToInt32(seriesRow["SiteID"]);
            variableID = Convert.ToInt32(seriesRow["VariableID"]);
            methodID = Convert.ToInt32(seriesRow["MethodID"]);
            sourceID = Convert.ToInt32(seriesRow["SourceID"]);
            qualityID = Convert.ToInt32(seriesRow["QualityControlLevelID"]);

            //SQL Queries
            string sqlSite = "SELECT SiteID from DataSeriesCache where SiteID = " + siteID;
            string sqlVariable = "SELECT VariableID from DataSeriesCache where VariableID = " + variableID;
            string sqlSource = "SELECT SourceID from DataSeriesCache where SourceID = " + sourceID;
            string sqlMethod = "SELECT MethodID from DataSeriesCache where MethodID = " + methodID;
            string sqlQuality = "SELECT QualityControlLevelID from DataSeriesCache where QualityControlLevelID = " + qualityID;


            //SQL Delete Commands
            string sqlDeleteSeries = "DELETE FROM DataSeriesCache WHERE SeriesID = " + seriesID;

            string sqlDeleteSite = "DELETE FROM SitesCache WHERE SiteID = " + siteID;
            string sqlDeleteVariable = "DELETE FROM VariablesCache WHERE VariableID = " + variableID;
            string sqlDeleteMethod = "DELETE FROM MethodsCache WHERE MethodID = " + methodID;
            string sqlDeleteSource = "DELETE FROM SourcesCache WHERE SourceID = " + sourceID;
            string sqlDeleteQuality = "DELETE FROM QualityControlLevelsCache WHERE QualityControlLevelID = " + qualityID;

            DataTable tblSite = new DataTable();
            DataTable tblVariable = new DataTable();
            DataTable tblSource = new DataTable();
            DataTable tblMethod = new DataTable();
            DataTable tblQuality = new DataTable();

            //Begin Transaction
            using (DbConnection conn = _db.CreateConnection())
            {
                conn.Open();

                using (DbTransaction tran = conn.BeginTransaction())
                {
                    // get site IDs
                    using (DbCommand cmd01 = conn.CreateCommand())
                    {
                        cmd01.CommandText = sqlSite;
                        tblSite = _db.LoadTable("t1", cmd01);
                    }

                    // get variable IDs
                    using (DbCommand cmd02 = conn.CreateCommand())
                    {
                        cmd02.CommandText = sqlVariable;
                        tblVariable = _db.LoadTable("t2", cmd02);
                    }

                    // get source IDs
                    using (DbCommand cmd03 = conn.CreateCommand())
                    {
                        cmd03.CommandText = sqlSource;
                        tblSource = _db.LoadTable("t3", cmd03);
                    }

                    // get method IDs
                    using (DbCommand cmd04 = conn.CreateCommand())
                    {
                        cmd04.CommandText = sqlMethod;
                        tblMethod = _db.LoadTable("t4", cmd04);
                    }

                    // get qualityControl IDs
                    using (DbCommand cmd05 = conn.CreateCommand())
                    {
                        cmd05.CommandText = sqlQuality;
                        tblQuality = _db.LoadTable("t5", cmd05);
                    }

                    //delete the site
                    if (tblSite.Rows.Count == 1)
                    {
                        using (DbCommand cmdDeleteSite = conn.CreateCommand())
                        {
                            cmdDeleteSite.CommandText = sqlDeleteSite;
                            cmdDeleteSite.ExecuteNonQuery();
                        }
                    }

                    //delete the variable
                    if (tblVariable.Rows.Count == 1)
                    {
                        using (DbCommand cmdDeleteVariable = conn.CreateCommand())
                        {
                            cmdDeleteVariable.CommandText = sqlDeleteVariable;
                            cmdDeleteVariable.ExecuteNonQuery();
                        }
                    }

                    //delete the method
                    if (tblMethod.Rows.Count == 1)
                    {
                        using (DbCommand cmdDeleteMethod = conn.CreateCommand())
                        {
                            cmdDeleteMethod.CommandText = sqlDeleteMethod;
                            cmdDeleteMethod.ExecuteNonQuery();
                        }
                    }

                    //delete the source
                    if (tblSource.Rows.Count == 1)
                    {
                        using (DbCommand cmdDeleteSource = conn.CreateCommand())
                        {
                            cmdDeleteSource.CommandText = sqlDeleteSource;
                            cmdDeleteSource.ExecuteNonQuery();
                        }
                    }

                    //delete the quality control level
                    if (tblQuality.Rows.Count == 1)
                    {
                        using (DbCommand cmdDeleteQuality = conn.CreateCommand())
                        {
                            cmdDeleteQuality.CommandText = sqlDeleteQuality;
                            cmdDeleteQuality.ExecuteNonQuery();
                        }
                    }  

                    //finally delete the series
                    using (DbCommand cmdDeleteSeries = conn.CreateCommand())
                    {
                        cmdDeleteSeries.CommandText = sqlDeleteSeries;
                        cmdDeleteSeries.ExecuteNonQuery();
                    }

                    //commit transaction
                    tran.Commit();
                }
            }
            return true;
        }



		/// <summary>
		/// Check if the series with the same site, variable, method,
		/// source, quality control level and data service already
		/// exists in the database.
		/// </summary>
		/// <param name="seriesToCheck">the series to be checked</param>
		/// <returns>The series from the db, or NULL if it doesn't exist</returns>
        /// <remarks>Not implemented</remarks>
		private SeriesMetadata CheckIfSeriesExists ( SeriesMetadata seriesToCheck )
		{
            throw new NotImplementedException();
		}

		/// <summary>
		/// Saves the series metadata to the metadata cache database.
		/// This method also automatically saves the site, variable,
		/// method, source and quality control level of the series.
		/// </summary>
		/// <param name="series">The series to be saved</param>
		/// <param name="dataService">The web service containing the series</param>
		public void SaveSeries ( SeriesMetadata series, DataServiceInfo dataService )
		{
            string sqlSite = "SELECT SiteID FROM SitesCache WHERE SiteCode = ?";
            string sqlVariable = "SELECT VariableID FROM VariablesCache WHERE VariableCode = ?";            
            string sqlMethod = "SELECT MethodID FROM MethodsCache WHERE MethodDescription = ?";
            string sqlSource = "SELECT SourceID FROM SourcesCache WHERE Organization = ?";          
            string sqlQuality = "SELECT QualityControlLevelID FROM QualityControlLevelsCache WHERE Definition = ?";           
            string sqlRowID = "; SELECT LAST_INSERT_ROWID();";
            
            string sqlSaveSite = "INSERT INTO SitesCache(SiteCode, SiteName, Latitude, Longitude, LatLongDatumSRSID, LatLongDatumName, " +
                "Elevation_m, VerticalDatum, LocalX, LocalY, LocalProjectionSRSID, LocalProjectionName, " +
                "PosAccuracy_m, State, County, Comments, ServiceID) " +
                "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + sqlRowID;

            string sqlSaveVariable = "INSERT INTO variablesCache(VariableCode, VariableName, Speciation, " +
                "SampleMedium, ValueType, DataType, GeneralCategory, NoDataValue, VariableUnitsName, VariableUnitsType, VariableUnitsAbbreviation, " +
                "IsRegular, TimeSupport, TimeUnitsName, TimeUnitsType, TimeUnitsAbbreviation, ServiceID) " +
                "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + sqlRowID;

            string sqlSaveMethod = "INSERT INTO MethodsCache(OriginMethodID, MethodDescription, MethodLink, ServiceID) VALUES(?, ?, ?, ?)" + sqlRowID;

            string sqlSaveQualityControl = "INSERT INTO QualityControlLevelsCache(OriginQualityControlLevelID, QualityControlLevelCode, Definition, Explanation) " +
                "VALUES(?,?,?,?)" + sqlRowID;

            string sqlSaveSource = "INSERT INTO SourcesCache(OriginSourceID, Organization, SourceDescription, SourceLink, ContactName, Phone, " +
                                   "Email, Address, City, State, ZipCode, Citation, MetadataID) " +
                                   "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + sqlRowID;

            string sqlSaveISOMetadata = "INSERT INTO ISOMetadataCache(TopicCategory, Title, Abstract, ProfileVersion, MetadataLink) " +
                                    "VALUES(?, ?, ?, ?, ?)" + sqlRowID;

            string sqlSaveSeries = "INSERT INTO DataSeriesCache(SiteID, VariableID, MethodID, SourceID, QualityControlLevelID, " +
                "BeginDateTime, EndDateTime, BeginDateTimeUTC, EndDateTimeUTC, ValueCount, ServiceID) " +
                "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + sqlRowID;

            int siteID = 0;
            int variableID = 0;
            
            int methodID = 0;
            int qualityControlLevelID = 0;
            int sourceID = 0;
            int isoMetadataID = 0;
            int seriesID = 0;
            

            object siteIDResult = null;
           
            object variableIDResult = null;
            
            object methodIDResult = null;
            object qualityControlLevelIDResult = null;
            object sourceIDResult = null;
            
            object seriesIDResult = null;
            
            //check the ServiceID (must be already set)
            if (dataService.Id <= 0)
            {
                throw new ArgumentException("The DataServiceID must be set.");
            }


            //Step 1 Begin Transaction
            using (DbConnection conn = _db.CreateConnection())
            {
                conn.Open();

                using (DbTransaction tran = conn.BeginTransaction())
                {
                    //****************************************************************
                    //*** Step 2 Site
                    //****************************************************************
                    using (DbCommand cmd01 = conn.CreateCommand())
                    {
                        cmd01.CommandText = sqlSite;
                        cmd01.Parameters.Add(_db.CreateParameter(DbType.String, series.Site.Code));
                        siteIDResult = cmd01.ExecuteScalar();
                        if (siteIDResult != null)
                        {
                            siteID = Convert.ToInt32(siteIDResult);
                        }
                    }

                    if (siteID == 0) //New Site needs to be created
                    {
                        //Insert the site to the database
                        using (DbCommand cmd04 = conn.CreateCommand())
                        {
                            Site site = series.Site;

                            cmd04.CommandText = sqlSaveSite;
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.Code));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.Name));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Double, site.Latitude));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Double, site.Longitude));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Int32, site.SpatialReference.SRSID));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.SpatialReference.SRSName));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Double, site.Elevation_m));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.VerticalDatum));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Double, site.LocalX));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Double, site.LocalY));
                            if (site.LocalProjection != null)
                            {
                                cmd04.Parameters.Add(_db.CreateParameter(DbType.Int32, site.LocalProjection.SRSID));
                                cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.LocalProjection.SRSName));
                            }
                            else
                            {
                                cmd04.Parameters.Add(_db.CreateParameter(DbType.Int32, 0));
                                cmd04.Parameters.Add(_db.CreateParameter(DbType.String, "unknown"));
                            }
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Double, site.PosAccuracy_m));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.State));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.County));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.String, site.Comments));
                            cmd04.Parameters.Add(_db.CreateParameter(DbType.Int32, dataService.Id));

                            siteIDResult = cmd04.ExecuteScalar();
                            siteID = Convert.ToInt32(siteIDResult);
                        }
                    }

                    //****************************************************************
                    //*** Step 3 Variable
                    //****************************************************************
                    Variable variable = series.Variable;

                    using (DbCommand cmd05 = conn.CreateCommand())
                    {
                        cmd05.CommandText = sqlVariable;
                        cmd05.Parameters.Add(_db.CreateParameter(DbType.String, variable.Code));
                        cmd05.Parameters[0].Value = variable.Code;
                        variableIDResult = cmd05.ExecuteScalar();
                        if (variableIDResult != null)
                        {
                            variableID = Convert.ToInt32(variableIDResult);
                        }
                    }

                    if (variableID == 0) //New variable needs to be created
                    {
                        //Insert the variable to the database
                        using (DbCommand cmd09 = conn.CreateCommand())
                        {
                            cmd09.CommandText = sqlSaveVariable;
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.Code));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.Name));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.Speciation));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.SampleMedium));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.ValueType));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.DataType));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.GeneralCategory));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.Double, variable.NoDataValue));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.VariableUnit.Name));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.VariableUnit.UnitsType));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.VariableUnit.Abbreviation));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.Boolean, variable.IsRegular));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.Double, variable.TimeSupport));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.TimeUnit.Name));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.TimeUnit.UnitsType));
                            cmd09.Parameters.Add(_db.CreateParameter(DbType.String, variable.TimeUnit.Abbreviation));

                            cmd09.Parameters.Add(_db.CreateParameter(DbType.Int32, dataService.Id));

                            variableIDResult = cmd09.ExecuteScalar();
                            variableID = Convert.ToInt32(variableIDResult);
                        }
                    }

                    //****************************************************************
                    //*** Step 4 Method
                    //****************************************************************
                    Method method = series.Method;

                    using (DbCommand cmd10 = conn.CreateCommand())
                    {
                        cmd10.CommandText = sqlMethod;
                        cmd10.Parameters.Add(_db.CreateParameter(DbType.String, method.Description));
                        methodIDResult = cmd10.ExecuteScalar();
                        if (methodIDResult != null)
                        {
                            methodID = Convert.ToInt32(methodIDResult);
                        }
                    }

                    if (methodID == 0)
                    {
                        using (DbCommand cmd11 = conn.CreateCommand())
                        {
                            cmd11.CommandText = sqlSaveMethod;
                            cmd11.Parameters.Add(_db.CreateParameter(DbType.Int32, method.Code));
                            cmd11.Parameters.Add(_db.CreateParameter(DbType.String, method.Description));
                            cmd11.Parameters.Add(_db.CreateParameter(DbType.String, method.Link));
                            cmd11.Parameters.Add(_db.CreateParameter(DbType.Int32, dataService.Id));
                            methodIDResult = cmd11.ExecuteScalar();
                            methodID = Convert.ToInt32(methodIDResult);
                        }
                    }

                    //****************************************************************
                    //*** Step 5 Quality Control Level
                    //****************************************************************
                    QualityControlLevel qc = series.QualityControlLevel;

                    using (DbCommand cmd12 = conn.CreateCommand())
                    {
                        cmd12.CommandText = sqlQuality;
                        cmd12.Parameters.Add(_db.CreateParameter(DbType.String, qc.Definition));
                        qualityControlLevelIDResult = cmd12.ExecuteScalar();
                        if (qualityControlLevelIDResult != null)
                        {
                            qualityControlLevelID = Convert.ToInt32(qualityControlLevelIDResult);
                        }
                    }

                    if (qualityControlLevelID == 0)
                    {
                        //to set the code
                        int qcCode = 0;
                        int.TryParse(qc.Code, out qcCode);
                        
                        using (DbCommand cmd13 = conn.CreateCommand())
                        {
                            cmd13.CommandText = sqlSaveQualityControl;
                            cmd13.Parameters.Add(_db.CreateParameter(DbType.Int32, qcCode));
                            cmd13.Parameters.Add(_db.CreateParameter(DbType.String, qc.Code));
                            cmd13.Parameters.Add(_db.CreateParameter(DbType.String, qc.Definition));
                            cmd13.Parameters.Add(_db.CreateParameter(DbType.String, qc.Explanation));
                            cmd13.Parameters.Add(_db.CreateParameter(DbType.Int32, dataService.Id));
                            qualityControlLevelIDResult = cmd13.ExecuteScalar();
                            qualityControlLevelID = Convert.ToInt32(qualityControlLevelIDResult);
                        }
                    }

                    //****************************************************************
                    //*** Step 6 Source
                    //****************************************************************
                    Source source = series.Source;

                    using (DbCommand cmd14 = conn.CreateCommand())
                    {
                        cmd14.CommandText = sqlSource;
                        cmd14.Parameters.Add(_db.CreateParameter(DbType.String, source.Organization));
                        sourceIDResult = cmd14.ExecuteScalar();
                        if (sourceIDResult != null)
                        {
                            sourceID = Convert.ToInt32(sourceIDResult);
                        }
                    }

                    if (sourceID == 0)
                    {
                        using (DbCommand cmd17 = conn.CreateCommand())
                        {
                            cmd17.CommandText = sqlSaveSource;
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.Int32, source.OriginId));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Organization));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Description));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Link));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.ContactName));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Phone));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Email));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Address));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.City));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.State));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.Int32, source.ZipCode));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, source.Citation));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.String, isoMetadataID));
                            cmd17.Parameters.Add(_db.CreateParameter(DbType.Int32, dataService.Id));
                            sourceIDResult = cmd17.ExecuteScalar();
                            sourceID = Convert.ToInt32(sourceIDResult);
                        }
                    }

                    //****************************************************************
                    //*** Step 7 Series
                    //****************************************************************
                    using (DbCommand cmd18 = conn.CreateCommand())
                    {
                        cmd18.CommandText = sqlSaveSeries;
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, siteID));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, variableID));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, methodID));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, sourceID));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, qualityControlLevelID));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.DateTime, series.BeginDateTime));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.DateTime, series.EndDateTime));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.DateTime, series.BeginDateTimeUTC));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.DateTime, series.EndDateTimeUTC));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, series.ValueCount));
                        cmd18.Parameters.Add(_db.CreateParameter(DbType.Int32, dataService.Id));
                        
                        seriesIDResult = cmd18.ExecuteScalar();
                        seriesID = Convert.ToInt32(seriesIDResult);
                    }

                    //Commit Transaction
                    tran.Commit();
                }
                conn.Close();
            }
		}

        /// <summary>
        /// updates the data row corresponding to the serviceInfo object
        /// The following parameters are updated:
        /// IsHarvested
        /// HarveDateTime
        /// ServiceName
        /// ServiceVersion
        /// ServiceType
        /// ServiceProtocol
        /// EastLongitude
        /// WestLongitude
        /// EastLatitude
        /// WestLatitude
        /// </summary>
        /// <param name="serviceInfo">the corresponding ServiceInfo</param>
        public void UpdateDataRow(DataServiceInfo serviceInfo)
        {
            string sql = "UPDATE DataServices SET " +
                "IsHarvested=?,HarveDateTime=?,ServiceName=?,ServiceVersion=?,ServiceType=?,ServiceProtocol=?," +
                "EastLongitude=?,WestLongitude=?,NorthLatitude=?,SouthLatitude=? WHERE ServiceID = ?";

            using (DbConnection conn = _db.CreateConnection())
            {
                conn.Open();

                using (DbTransaction tran = conn.BeginTransaction())
                {
                    using (DbCommand cmd = conn.CreateCommand())
                    {
                        cmd.CommandText = sql;
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Boolean, serviceInfo.IsHarvested));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.DateTime, serviceInfo.HarveDateTime));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, serviceInfo.ServiceName));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, serviceInfo.Version));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, serviceInfo.ServiceType));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.String, serviceInfo.Protocol));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, serviceInfo.EastLongitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, serviceInfo.WestLongitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, serviceInfo.NorthLatitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Double, serviceInfo.SouthLatitude));
                        cmd.Parameters.Add(_db.CreateParameter(DbType.Int32, serviceInfo.Id));

                        cmd.ExecuteNonQuery();
                    }
                                        
                    tran.Commit();
                }
            }
        }
	}
}