using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Npgsql;
using NpgsqlTypes;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Skyscraper.Scraper.Storage.Utilities;
using static skyscraper5.Dvb.Descriptors.ServiceListDescriptor;
using static skyscraper5.src.InteractionChannel.Model.Rmt;

namespace skyscraper5.Data.PostgreSql
{
    public partial class PostgresqlDataStore
    {
        private HashSet<DatabaseKeyBatBouquet> _knownBatBouquets;
        public bool TestForBatBouquet(BatBouquet batBouquet)
        {
            if (_knownBatBouquets == null)
                _knownBatBouquets = new HashSet<DatabaseKeyBatBouquet>();
            DatabaseKeyBatBouquet key = new DatabaseKeyBatBouquet(batBouquet.BouquetId);
            if (_knownBatBouquets.Contains(key))
                return true;

            bool result = false;
            using (NpgsqlConnection connection = new NpgsqlConnection(connectionStringBuilder.ToString()))
            {
                connection.Open();
                NpgsqlCommand command = connection.CreateCommand();
                command.CommandText = "SELECT dateadded FROM dvb_bat WHERE id = @id";
                command.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)batBouquet.BouquetId);
                NpgsqlDataReader dataReader = command.ExecuteReader();
                result = dataReader.Read();
                dataReader.Close();
                command.Dispose();
                connection.Close();
            }

            if (result)
                _knownBatBouquets.Add(key);

            return result;
        }

        public void StoreBatBouquet(BatBouquet batBouquet)
        {
			DatabaseKeyBatBouquet key = new DatabaseKeyBatBouquet(batBouquet.BouquetId);
			EnqueueTask(x => WriteBatBouquet(x, batBouquet));
			_knownBatBouquets.Add(key);
			if (_updatedBats == null)
				_updatedBats = new HashSet<DatabaseKeyBatBouquet>();
			_updatedBats.Add(key);
        }

        private void WriteBatBouquet(NpgsqlConnection conn, BatBouquet bouquet)
        {
	        NpgsqlCommand command = conn.CreateCommand();
	        command.CommandText =
		        "insert into dvb_bat (id, bouquet_name, private_data_specifier, uri_linkage_type, uri, min_polling_interval, control_remote_access_over_internet, do_not_apply_revocation, do_not_scramble) " +
		        "values " +
		        "(@id, @bouquet_name, @private_data_specifier, @uri_linkage_type, @uri, @min_polling_interval, @control_remote_access_over_internet, @do_not_apply_revocation, @do_not_scramble)";
	        command.Parameters.AddParameter("@id", NpgsqlDbType.Integer, (int)bouquet.BouquetId);
	        command.Parameters.AddParameter("@bouquet_name", NpgsqlDbType.Text, bouquet.BouquetName);
	        command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, bouquet.PrivateDataSpecifier);
	        command.Parameters.AddParameter("@uri_linkage_type", NpgsqlDbType.Integer, bouquet.UriLinkageType);
	        command.Parameters.AddParameter("@uri", NpgsqlDbType.Text, bouquet.Uri);
	        command.Parameters.AddParameter("@min_polling_interval", NpgsqlDbType.Integer, bouquet.MinPollingInterval);
	        command.Parameters.AddParameter("@control_remote_access_over_internet", NpgsqlDbType.Integer, bouquet.ControlRemoteAccessOverInternet);
	        command.Parameters.AddParameter("@do_not_apply_revocation", NpgsqlDbType.Boolean, bouquet.DoNotApplyRevocation);
	        command.Parameters.AddParameter("@do_not_scramble", NpgsqlDbType.Boolean, bouquet.DoNotScramble);
	        command.ExecuteNonQuery();
            command.Dispose();

            WriteBatCountryAvailability(conn, bouquet);
            WriteBatLinkage(conn, bouquet);
            WriteBatMultilingualBouquetNames(conn, bouquet);
        }

        private void WriteBatMultilingualBouquetNames(NpgsqlConnection conn, BatBouquet bouquet)
        {
	        if (bouquet.MultilingualBouquetName == null)
		        return;
	        if (bouquet.MultilingualBouquetName.MultilingualBouquetName == null)
		        return;

			NpgsqlCommand cmd = conn.CreateCommand();
			cmd.CommandText = "insert into dvb_bat_multilingual_bouquet_names (id, k, v)\r\nvalues (@id,@k,@v)";
			cmd.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)bouquet.BouquetId);
			cmd.Parameters.Add("@k", NpgsqlDbType.Varchar);
            cmd.Parameters.Add("@v", NpgsqlDbType.Text);

            foreach (KeyValuePair<string, string> keyValuePair in bouquet.MultilingualBouquetName.MultilingualBouquetName)
	        {
				cmd.Parameters["@k"].Value = keyValuePair.Key;
				cmd.Parameters["@v"].Value = keyValuePair.Value;
				cmd.ExecuteNonQuery();
	        }
        }

        private void WriteBatLinkage(NpgsqlConnection conn, BatBouquet bouquet)
        {
	        if (bouquet.Linkages == null)
		        return;

	        NpgsqlCommand command = conn.CreateCommand();
	        command.CommandText =
		        "insert into dvb_bat_linkages (id, ordinal, l_tsid, l_onid, l_sid, linkage_type, handover_type, handover_origin_type, handover_network_id, handover_initial_service_id, target_event_id, target_event_listed, target_event_simulcasted, table_type, private_data_bytes, bouquet_id) " +
		        "values " +
		        "(@id,@ordinal,@l_tsid,@l_onid,@l_sid,@linkage_type,@handover_type,@handover_origin_type,@handover_network_id,@handover_initial_service_id,@target_event_id,@target_event_listed,@target_event_simulcasted,@table_type,@private_data_bytes,@bouquet_id)";
	        command.Parameters.AddParameter("@id", NpgsqlDbType.Integer,bouquet.BouquetId);
	        command.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
	        command.Parameters.Add("@l_tsid", NpgsqlDbType.Integer);
	        command.Parameters.Add("@l_onid", NpgsqlDbType.Integer);
	        command.Parameters.Add("@l_sid", NpgsqlDbType.Integer);
	        command.Parameters.Add("@linkage_type", NpgsqlDbType.Integer);
	        command.Parameters.Add("@handover_type", NpgsqlDbType.Integer);
	        command.Parameters.Add("@handover_origin_type", NpgsqlDbType.Boolean);
	        command.Parameters.Add("@handover_network_id", NpgsqlDbType.Integer);
	        command.Parameters.Add("@handover_initial_service_id", NpgsqlDbType.Integer);
	        command.Parameters.Add("@target_event_id", NpgsqlDbType.Integer);
	        command.Parameters.Add("@target_event_listed", NpgsqlDbType.Boolean);
	        command.Parameters.Add("@target_event_simulcasted", NpgsqlDbType.Boolean);
			//@table_type,@private_data_bytes,@bouquet_id)";
			command.Parameters.Add("@table_type", NpgsqlDbType.Integer);
			command.Parameters.Add("@private_data_bytes", NpgsqlDbType.Bytea);
			command.Parameters.Add("@bouquet_id", NpgsqlDbType.Integer);

			for (int i = 0; i < bouquet.Linkages.Count; i++)
	        {
		        LinkageDescriptor linkage = bouquet.Linkages[i];
		        command.Parameters["@ordinal"].Value = i;
				command.Parameters["@l_tsid"].Value = (int)linkage.TransportStreamId;
				command.Parameters["@l_onid"].Value = (int)linkage.OriginalNetworkId;
				command.Parameters["@l_sid"].Value = (int)linkage.ServiceId;
				command.Parameters["@linkage_type"].Value = (int)linkage.LinkageType;
				command.Parameters["@handover_type"].Value = linkage.HandoverType.HasValue ? linkage.HandoverType.Value : DBNull.Value;
				command.Parameters["@handover_origin_type"].Value = linkage.HandoverOriginType.HasValue ? linkage.HandoverOriginType.Value : DBNull.Value;
				command.Parameters["@handover_network_id"].Value = linkage.HandoverNetworkId.HasValue ? linkage.HandoverNetworkId.Value : DBNull.Value;
				command.Parameters["@handover_initial_service_id"].Value = linkage.HandoverInitialServiceId.HasValue ? linkage.HandoverInitialServiceId.Value : DBNull.Value;
				command.Parameters["@target_event_id"].Value = linkage.TargetEventId.HasValue ? linkage.TargetEventId.Value : DBNull.Value;
				command.Parameters["@target_event_listed"].Value = linkage.TargetEventListed.HasValue ? linkage.TargetEventListed.Value : DBNull.Value;
				command.Parameters["@target_event_simulcasted"].Value = linkage.TargetEventSimulcasted.HasValue ? linkage.TargetEventSimulcasted.Value : DBNull.Value;
				command.Parameters["@table_type"].Value = linkage.TableType.HasValue ? (int)linkage.TableType.Value : DBNull.Value;
				command.Parameters["@private_data_bytes"].Value = linkage.PrivateDataBytes != null ? linkage.PrivateDataBytes : DBNull.Value;
				command.Parameters["@bouquet_id"].Value = linkage.BouquetId.HasValue ? linkage.BouquetId : DBNull.Value;
				command.ExecuteNonQuery();

				WriteBatLinkageExtendedLinkages(conn, bouquet, i);
				WriteBatLinkageIpmacLinkage(conn, bouquet, i);
				WriteBatLinkageSsuLinkStructure(conn, bouquet, i);
	        }
        }
		
        private void WriteBatLinkageSsuLinkStructure(NpgsqlConnection conn, BatBouquet bouquet, int ordinal)
        {
			if (bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure == null)
				return;

			NpgsqlCommand command = conn.CreateCommand();
			command.CommandText =
				"INSERT INTO dvb_bat_linkages_ssu_link_structure (id, ordinal, subordinal, oui, selector) " +
				"VALUES (@id, @ordinal, @subordinal, @oui, @selector)";
			command.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)bouquet.BouquetId);
			command.Parameters.AddWithValue("@ordinal", NpgsqlDbType.Integer, ordinal);
			command.Parameters.Add("@subordinal", NpgsqlDbType.Integer);
			command.Parameters.Add("@oui", NpgsqlDbType.Varchar);
			command.Parameters.AddWithValue("@selector", NpgsqlDbType.Bytea);
			for (int i = 0; i < bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure.Count; i++)
			{
				command.Parameters["@subordinal"].Value = i;
				command.Parameters["@oui"].Value = BitConverter.ToString(bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure[i].OUI);
				command.Parameters["@selector"].Value = bouquet.Linkages[ordinal].SystemSoftwareUpdateLinkStructure[i].Selector;
				command.ExecuteNonQuery();
			}
		}

        private void WriteBatLinkageIpmacLinkage(NpgsqlConnection conn, BatBouquet bouquet, int ordinal)
        {
			if (bouquet.Linkages[ordinal].IpMacNotificationLinkages == null)
				return;

			for (int i = 0; i < bouquet.Linkages[ordinal].IpMacNotificationLinkages.Count; i++)
			{
				throw new NotImplementedException();
			}
		}

        private void WriteBatLinkageExtendedLinkages(NpgsqlConnection conn, BatBouquet bouquet, int ordinal)
        {
	        if (bouquet.Linkages[ordinal].ExtendedEventLinkages == null)
		        return;

	        for (int i = 0; i < bouquet.Linkages[ordinal].ExtendedEventLinkages.Length; i++)
	        {
		        throw new NotImplementedException();
	        }
        }

        private void WriteBatCountryAvailability(NpgsqlConnection conn, BatBouquet bouquet)
        {
	        if (bouquet.CountryAvailabilityDictionary == null)
		        return;

	        NpgsqlCommand command = conn.CreateCommand();
	        command.CommandText = "INSERT INTO dvb_bat_country_availability (id,k,v) " +
	                              "VALUES (@id,@k,@v)";
	        command.Parameters.AddWithValue("@id", (int)bouquet.BouquetId);
	        command.Parameters.Add("@k", NpgsqlDbType.Varchar);
	        command.Parameters.Add("@v", NpgsqlDbType.Boolean);
	        foreach (KeyValuePair<string, bool> keyValuePair in bouquet.CountryAvailabilityDictionary)
	        {
		        command.Parameters["@k"].Value = keyValuePair.Key;
		        command.Parameters["@v"].Value = keyValuePair.Value;
		        command.ExecuteNonQuery();
	        }
        }

        private HashSet<DatabaseKeyBatBouquet> _updatedBats;
        public bool UpdateBatBouquet(BatBouquet batBouquet)
        {
	        if (_updatedBats == null)
		        _updatedBats = new HashSet<DatabaseKeyBatBouquet>();
	        DatabaseKeyBatBouquet key = new DatabaseKeyBatBouquet(batBouquet.BouquetId);
	        if (_updatedBats.Contains(key))
		        return false;
	        EnqueueTask(x => WriteBatBouquetUpdate(x, batBouquet));
	        _updatedBats.Add(key);
	        return true;
        }

        private void WriteBatBouquetUpdate(NpgsqlConnection connection, BatBouquet newer)
        {
	        BatBouquet older = SelectBat(connection, newer.BouquetId);
	        if (!older.NeedUpdate(newer))
		        return;

	        NpgsqlCommand command = connection.CreateCommand();
	        command.CommandText =
		        "UPDATE dvb_bat\r\nSET bouquet_name = @bouquet_name,\r\n    private_data_specifier = @private_data_specifier,\r\n    uri_linkage_type = @uri_linkage_type,\r\n    uri = @uri,\r\n    min_polling_interval = @min_polling_interval,\r\n    control_remote_access_over_internet = @control_remote_access_over_internet,\r\n    do_not_apply_revocation = @do_not_apply_revocation,\r\n    do_not_scramble = @do_not_scramble,\r\n    updated_counter = updated_counter + 1,\r\n    updated_timestamp = CURRENT_TIMESTAMP\r\nWHERE id = @id";
	        command.Parameters.AddParameter("@id", NpgsqlDbType.Integer, (int)newer.BouquetId);
	        command.Parameters.AddParameter("@bouquet_name", NpgsqlDbType.Text, newer.BouquetName);
	        command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, newer.PrivateDataSpecifier);
	        command.Parameters.AddParameter("@uri_linkage_type", NpgsqlDbType.Integer, newer.UriLinkageType);
	        command.Parameters.AddParameter("@uri", NpgsqlDbType.Text, newer.Uri);
	        command.Parameters.AddParameter("@min_polling_interval", NpgsqlDbType.Integer, newer.MinPollingInterval);
	        command.Parameters.AddParameter("@control_remote_access_over_internet", NpgsqlDbType.Integer, newer.ControlRemoteAccessOverInternet);
	        command.Parameters.AddParameter("@do_not_apply_revocation", NpgsqlDbType.Boolean, newer.DoNotApplyRevocation);
	        command.Parameters.AddParameter("@do_not_scramble", NpgsqlDbType.Boolean, newer.DoNotScramble);
	        command.ExecuteNonQuery();
        }

        private BatBouquet SelectBat(NpgsqlConnection connection, int id)
        {
	        NpgsqlCommand command = connection.CreateCommand();
	        command.CommandText = "SELECT * FROM dvb_bat WHERE id = @id";
	        command.Parameters.AddWithValue("@id", id);
	        NpgsqlDataReader dataReader = command.ExecuteReader();
	        BatBouquet result = null;
	        if (dataReader.Read())
	        {
		        ushort id2 = (ushort)dataReader.GetInt32(0);
		        result = new BatBouquet(id2);
		        DateTime dateadded = dataReader.GetDateTime(1);
		        result.BouquetName = dataReader.IsDBNull(2) ? null : dataReader.GetString(2);
		        result.PrivateDataSpecifier = dataReader.IsDBNull(3) ? null : (ushort)dataReader.GetInt64(3);
		        result.UriLinkageType = dataReader.IsDBNull(4) ? null : (byte)dataReader.GetInt32(4);
		        result.Uri = dataReader.IsDBNull(5) ? null : dataReader.GetString(5);
		        result.MinPollingInterval = dataReader.IsDBNull(6) ? null : (ushort)dataReader.GetInt32(6);
		        result.ControlRemoteAccessOverInternet = dataReader.IsDBNull(7) ? null : dataReader.GetInt32(7);
		        result.DoNotApplyRevocation = dataReader.IsDBNull(8) ? null : dataReader.GetBoolean(8);
		        result.DoNotScramble = dataReader.IsDBNull(9) ? null : dataReader.GetBoolean(9);
		        int updateCounter = dataReader.GetInt32(10);
				DateTime? updatedTimestamp = dataReader.IsDBNull(11) ? null : dataReader.GetDateTime(11);
	        }
			dataReader.Close();
			command.Dispose();
			return result;
        }

        private HashSet<DatabaseKeyBatTs> _knownBatTs;
        public bool TestForBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child)
        {
	        if (_knownBatTs == null)
		        _knownBatTs = new HashSet<DatabaseKeyBatTs>();

	        DatabaseKeyBatTs ts = new DatabaseKeyBatTs(batBouquetBouquetId, child.TransportStreamId, child.OriginalNetworkId);
	        if (_knownBatTs.Contains(ts))
		        return true;

	        bool result = false;
	        using (NpgsqlConnection conn = new NpgsqlConnection(connectionStringBuilder.ToString()))
	        {
				conn.Open();
		        NpgsqlCommand command = conn.CreateCommand();
		        command.CommandText = "SELECT dateAdded FROM dvb_bat_transport_stream WHERE bid = @bid AND tsid = @tsid AND onid = @onid";
		        command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)batBouquetBouquetId);
		        command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)child.TransportStreamId);
		        command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)child.OriginalNetworkId);
		        NpgsqlDataReader dataReader = command.ExecuteReader();
		        result = dataReader.Read();
				dataReader.Close();
				command.Dispose();
				conn.Close();
	        }

	        if (result)
		        _knownBatTs.Add(ts);
			return result;
        }
		
        public void StoreBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child)
        {
	        EnqueueTask(x => WriteBatTransportStream(x, batBouquetBouquetId, child));
	        DatabaseKeyBatTs key = new DatabaseKeyBatTs(batBouquetBouquetId, child.TransportStreamId, child.OriginalNetworkId);
	        _knownBatTs.Add(key);
	        if (_updatedBatTs == null)
		        _updatedBatTs = new HashSet<DatabaseKeyBatTs>();
	        _updatedBatTs.Add(key);
        }

        private void WriteBatTransportStream(NpgsqlConnection connection, ushort bouquetId, BatTransportStream transportStream)
        {
	        NpgsqlCommand command = connection.CreateCommand();
	        command.CommandText =
		        "INSERT INTO dvb_bat_transport_stream (bid, tsid, onid, private_data_specifier, default_authority) " +
		        "VALUES (@bid, @tsid, @onid, @private_data_specifier, @default_authority)";
	        command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)bouquetId);
	        command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId);
	        command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)transportStream.OriginalNetworkId);
	        command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, transportStream.PrivateDataSpecifier);
	        command.Parameters.AddParameter("@default_authority", NpgsqlDbType.Text, transportStream.DefaultAuthority);
	        command.ExecuteNonQuery();

			WriteBatTransportStreamCountryAvailability(connection, bouquetId, transportStream);
			WriteBatTransportStreamServiceList(connection, bouquetId, transportStream);
        }

		private bool TestForBatTransportStreamServiceList(NpgsqlConnection connection, int bouquetId, int transportStreamId, int originalNetworkId, int serviceId)
		{
            NpgsqlCommand command = connection.CreateCommand();
			command.CommandText = "SELECT dateadded FROM dvb_bat_transport_stream_service_list WHERE bid = @bid AND tsid = @tsid AND onid = @onid AND sid = @sid";
            command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, bouquetId);
            command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, transportStreamId);
            command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, originalNetworkId);
            command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, serviceId);
            NpgsqlDataReader dataReader = command.ExecuteReader();
			bool result = dataReader.Read();
			dataReader.Close();
			command.Dispose();
			return result;
        }

        private void WriteBatTransportStreamServiceList(NpgsqlConnection connection, ushort bouquetId, BatTransportStream transportStream)
        {
	        if (transportStream.ServiceList == null)
		        return;

	        NpgsqlCommand command = connection.CreateCommand();
	        command.CommandText = "INSERT INTO dvb_bat_transport_stream_service_list (bid,tsid,onid,sid,service_type)" +
	                              "VALUES (@bid,@tsid,@onid,@sid,@service_type)";
	        command.Parameters.AddWithValue("@bid",  NpgsqlDbType.Integer, (int)bouquetId);
	        command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId);
	        command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)transportStream.OriginalNetworkId);
	        command.Parameters.Add("@sid", NpgsqlDbType.Integer);
	        command.Parameters.Add("@service_type", NpgsqlDbType.Integer);

			foreach (ServiceListDescriptor.Service service in transportStream.ServiceList)
			{
				if (TestForBatTransportStreamServiceList(connection,(int)bouquetId,(int)transportStream.TransportStreamId,(int)transportStream.OriginalNetworkId,service.ServiceId))
				{
					continue;
				}
				command.Parameters["@sid"].Value = (int)service.ServiceId;
				command.Parameters["@service_type"].Value = (int)service.ServiceType;
				command.ExecuteNonQuery();
			}
        }

        private void WriteBatTransportStreamCountryAvailability(NpgsqlConnection connection, ushort bouquetId, BatTransportStream transportStream)
        {
	        if (transportStream.CountryAvailability == null)
		        return;

	        foreach (KeyValuePair<string, bool> keyValuePair in transportStream.CountryAvailability)
	        {
		        throw new NotImplementedException();
	        }
        }

        private HashSet<DatabaseKeyBatTs> _updatedBatTs;
        public bool UpdateBatTransportStream(ushort batBouquetBouquetId, BatTransportStream child)
        {
	        if (_updatedBatTs == null)
		        _updatedBatTs = new HashSet<DatabaseKeyBatTs>();

	        DatabaseKeyBatTs key = new DatabaseKeyBatTs(batBouquetBouquetId, child.TransportStreamId, child.OriginalNetworkId);
	        if (_updatedBatTs.Contains(key))
		        return false;

	        EnqueueTask(x => WriteUpdateBatTs(x, batBouquetBouquetId, child));
	        _updatedBatTs.Add(key);
	        return true;
        }

        private void WriteUpdateBatTs(NpgsqlConnection connection, ushort batBouquetBouquetId, BatTransportStream transportStream)
        {
	        DatabaseKeyBatTs key = new DatabaseKeyBatTs(batBouquetBouquetId, transportStream.TransportStreamId, transportStream.OriginalNetworkId);
	        BatTransportStream older = SelectBatTs(connection, batBouquetBouquetId, transportStream.TransportStreamId, transportStream.OriginalNetworkId);
	        if (!older.NeedsUpdate(transportStream))
	        {
				return;
	        }

	        NpgsqlCommand command = connection.CreateCommand();
	        command.CommandText =
		        "UPDATE dvb_bat_transport_stream " +
		        "SET private_data_specifier = @private_data_specifier,\r\n    default_authority = @default_authority " +
		        "WHERE bid = @bid AND tsid = @tsid AND onid = @onid\r\n";
	        command.Parameters.AddWithValue("@bid", NpgsqlDbType.Integer, (int)batBouquetBouquetId);
	        command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId);
	        command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)transportStream.OriginalNetworkId);
	        command.Parameters.AddParameter("@private_data_specifier", NpgsqlDbType.Bigint, transportStream.PrivateDataSpecifier);
	        command.Parameters.AddParameter("@default_authority", NpgsqlDbType.Text, transportStream.DefaultAuthority);
	        command.ExecuteNonQuery();
		}

        private BatTransportStream SelectBatTs(NpgsqlConnection conn, ushort bouquetId, ushort transportStreamId, ushort originalNetworkId)
        {
	        NpgsqlCommand command = conn.CreateCommand();
	        command.CommandText = "SELECT * FROM dvb_bat_transport_stream WHERE bid = @bid AND tsid = @tsid AND onid = @onid";
	        command.Parameters.AddParameter("@bid", NpgsqlDbType.Integer, (int)bouquetId);
	        command.Parameters.AddParameter("@tsid", NpgsqlDbType.Integer, (int)transportStreamId);
	        command.Parameters.AddParameter("@onid", NpgsqlDbType.Integer, (int)originalNetworkId);
	        NpgsqlDataReader dataReader = command.ExecuteReader();
	        BatTransportStream result = null;
	        if (dataReader.Read())
	        {
		        ushort bid = (ushort)dataReader.GetInt32(0);
		        ushort tsid = (ushort)dataReader.GetInt32(1);
		        ushort onid = (ushort)dataReader.GetInt32(2);
		        DateTime dateadded = dataReader.GetDateTime(3);
		        result = new BatTransportStream(tsid, onid);
		        result.PrivateDataSpecifier = dataReader.IsDBNull(4) ? null : (uint)dataReader.GetInt64(4);
		        result.DefaultAuthority = dataReader.IsDBNull(5) ? null : dataReader.GetString(5);
	        }
			dataReader.Close();
			command.Dispose();
			return result;
        }
    }
}
