using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Npgsql;
using NpgsqlTypes;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Mpeg2.Psi.Model;
using skyscraper5.Skyscraper.Scraper.Storage.Utilities;

namespace skyscraper5.Data.PostgreSql
{
    public partial class PostgresqlDataStore
    {
        public bool StoreEitEvent(EitEvent eitEvent)
        {
            if (knownEitEvents == null)
                knownEitEvents = new HashSet<DatabaseKeyEitEvent>();
            DatabaseKeyEitEvent key = new DatabaseKeyEitEvent(eitEvent.ServiceId, eitEvent.TransportStreamId, eitEvent.OriginalNetworkId, eitEvent.EventId, eitEvent.StartTime);
            if (knownEitEvents.Contains(key))
                return false;
            if (TestForEitEvent(key))
            {
                knownEitEvents.Add(key);
                return false;
            }

            EnqueueTask(x => WriteEitEvent(x, eitEvent));
            knownEitEvents.Add(key);
            return true;
        }

        public void Ping()
        {
	        using (NpgsqlConnection conn = new NpgsqlConnection(connectionStringBuilder.ToString()))
	        {
		        conn.Open();
		        NpgsqlCommand command = conn.CreateCommand();
		        command.CommandText = "SELECT relname FROM pg_catalog.pg_class";
		        NpgsqlDataReader dataReader = command.ExecuteReader();
		        bool hasDsmCcTables = false;
		        bool hasDvbTables = false;
		        bool hasScte35Tables = false;
		        bool hasSkyscraper5Tables = false;
		        while (dataReader.Read())
		        {
			        string tableName = dataReader.GetString(0);
			        if (tableName.StartsWith("dsmcc_"))
				        hasDsmCcTables = true;
					if (tableName.StartsWith("dvb_"))
				        hasDvbTables = true;
					if (tableName.StartsWith("scte35_"))
						hasScte35Tables = true;
					if (tableName.StartsWith("skyscraper5_"))
						hasSkyscraper5Tables = true;
		        }
                dataReader.Close();
                command.Dispose();
                conn.Close();
                if (!hasDsmCcTables || !hasDvbTables || !hasScte35Tables || !hasSkyscraper5Tables)
                {
	                throw new SchemaMissingException("The PostgreSQL schema does not seem to be installed.");
                }
	        }
        }

        public IEnumerable<Tuple<int, int, ProgramMapping>> SelectAllPmt()
        {
	        throw new NotImplementedException();
        }

        public SdtService SelectSdtById(int networkId, int tsId, ushort programMappingProgramNumber)
        {
	        throw new NotImplementedException();
        }

        public IEnumerable<Tuple<int, int, SdtService>> SelectAllSdt()
        {
	        throw new NotImplementedException();
        }


        private HashSet<DatabaseKeyEitEvent> knownEitEvents;

        private bool TestForEitEvent(DatabaseKeyEitEvent eitEvent)
        {
            using (NpgsqlConnection conn = new NpgsqlConnection(connectionStringBuilder.ToString()))
			{
				conn.Open();
				return TestForEitEventEx(eitEvent, conn);
			}
		}

		private static bool TestForEitEventEx(DatabaseKeyEitEvent eitEvent, NpgsqlConnection conn)
		{
			NpgsqlCommand command = conn.CreateCommand();
			command.CommandText =
				"SELECT dateadded FROM dvb_eit WHERE sid = @sid AND tsid = @tsid AND onid = @onid AND event_id = @event_id AND start_time = @start_time";
			command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
			command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
			command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
			command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
			command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
			NpgsqlDataReader dataReader = command.ExecuteReader();
			bool result = dataReader.Read();
			dataReader.Close();
			return result;
		}

		private void WriteEitEvent(NpgsqlConnection conn, EitEvent eitEvent)
        {
            DatabaseKeyEitEvent key = new DatabaseKeyEitEvent(eitEvent.ServiceId, eitEvent.TransportStreamId, eitEvent.OriginalNetworkId, eitEvent.EventId, eitEvent.StartTime);
            if (TestForEitEventEx(key, conn))
            {
                return;
            }
            NpgsqlCommand command = conn.CreateCommand();
            command.CommandText =
                "INSERT INTO dvb_eit " +
                "(sid, tsid, onid, event_id, start_time, running_status, free_ca, iso_639_language_code, event_name, text, extended_text, pdc, private_data_specifier, vps_string, reference_service_id, reference_event_id, control_remote_access_over_internet, do_not_apply_revocation, do_not_scramble) " +
                "VALUES " +
                "(@sid, @tsid, @onid, @event_id, @start_time, @running_status, @free_ca, @iso_639_language_code, @event_name, @text, @extended_text, @pdc, @private_data_specifier, @vps_string, @reference_service_id, @reference_event_id, @control_remote_access_over_internet, @do_not_apply_revocation, @do_not_scramble)";

            command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
            command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
            command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
            command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
            command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            command.Parameters.AddWithValue("@running_status", NpgsqlDbType.Integer, (int)eitEvent.RunningStatus);
            command.Parameters.AddWithValue("@free_ca", NpgsqlDbType.Boolean, eitEvent.FreeCa);
            command.Parameters.AddWithValue("@iso_639_language_code", NpgsqlDbType.Varchar, eitEvent.Iso639LanguageCode);
            command.Parameters.AddWithValue("@event_name", NpgsqlDbType.Text, eitEvent.EventName.TrimJunk());
            command.Parameters.AddWithValue("@text", NpgsqlDbType.Text, eitEvent.Text.TrimJunk());


            if (eitEvent.ExtendedText != null)
            {
                StringBuilder sb = new StringBuilder();
                foreach (string s in eitEvent.ExtendedText)
                    if (s != null)
						sb.Append(s.Trim('\0'));

                
                command.Parameters.AddWithValue("@extended_text", NpgsqlDbType.Text, sb.ToString().TrimJunk());
            }
            else
            {
                command.Parameters.AddWithValue("@extended_text", NpgsqlDbType.Text, DBNull.Value);
            }

            command.Parameters.AddWithValue("@pdc", NpgsqlDbType.Timestamp, eitEvent.Pdc);

            if (eitEvent.PrivateDataSpecifier.HasValue)
                command.Parameters.AddWithValue("@private_data_specifier", NpgsqlDbType.Bigint, (long)eitEvent.PrivateDataSpecifier);
            else
                command.Parameters.AddWithValue("@private_data_specifier", NpgsqlDbType.Bigint, DBNull.Value);

            command.Parameters.AddWithValue("@vps_string", NpgsqlDbType.Text, eitEvent.VpsString);

            if (eitEvent.ReferenceServiceId.HasValue)
                command.Parameters.AddWithValue("@reference_service_id", NpgsqlDbType.Integer, eitEvent.ReferenceServiceId);
            else
                command.Parameters.AddWithValue("@reference_service_id", NpgsqlDbType.Integer, DBNull.Value);

            if (eitEvent.ReferenceEventId.HasValue)
                command.Parameters.AddWithValue("@reference_event_id", NpgsqlDbType.Integer, eitEvent.ReferenceEventId);
            else
                command.Parameters.AddWithValue("@reference_event_id", NpgsqlDbType.Integer, DBNull.Value);

            if (eitEvent.ControlRemoteAccessOverInternet.HasValue)
                command.Parameters.AddWithValue("@control_remote_access_over_internet", NpgsqlDbType.Integer, eitEvent.ControlRemoteAccessOverInternet);
            else
                command.Parameters.AddWithValue("@control_remote_access_over_internet", NpgsqlDbType.Integer, DBNull.Value);

            if (eitEvent.DoNotApplyRevocation.HasValue)
                command.Parameters.AddWithValue("@do_not_apply_revocation", NpgsqlDbType.Boolean, eitEvent.DoNotApplyRevocation);
            else
                command.Parameters.AddWithValue("@do_not_apply_revocation", NpgsqlDbType.Boolean, DBNull.Value);

            if (eitEvent.DoNotScramble.HasValue)
                command.Parameters.AddWithValue("@do_not_scramble", NpgsqlDbType.Boolean, eitEvent.DoNotScramble);
            else
                command.Parameters.AddWithValue("@do_not_scramble", NpgsqlDbType.Boolean, DBNull.Value);
            
            command.Parameters.CheckNulls();
            command.ExecuteNonQuery();

            WriteEitCaSystems(conn, eitEvent);
            WriteEitComponents(conn, eitEvent);
            WriteEitContent(conn, eitEvent);
            WriteEitCrids(conn, eitEvent);
            WriteEitItems(conn, eitEvent);
            WriteEitLinkages(conn, eitEvent);
            WriteEitParentalRatings(conn, eitEvent);
        }

        private void WriteEitParentalRatings(NpgsqlConnection conn, EitEvent eitEvent)
        {
            if (eitEvent.ParentalRatings == null)
                return;

            NpgsqlCommand command = conn.CreateCommand();
            command.CommandText = "INSERT INTO dvb_eit_parental_ratings " +
                                  "(sid,tsid,onid,event_id,start_time,ordinal,k,v) " +
                                  "VALUES " +
                                  "(@sid,@tsid,@onid,@event_id,@start_time,@ordinal,@k,@v)";
            command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
            command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
            command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
            command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
            command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            command.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
            command.Parameters.Add("@k", NpgsqlDbType.Varchar);
            command.Parameters.Add("@v", NpgsqlDbType.Integer);
            for (int i = 0; i < eitEvent.ParentalRatings.Length; i++)
            {
	            if (eitEvent.ParentalRatings[i] == null)
		            continue;
                command.Parameters["@ordinal"].Value = i;
                command.Parameters["@k"].Value = eitEvent.ParentalRatings[i].Item1;
                command.Parameters["@v"].Value = eitEvent.ParentalRatings[i].Item2;
                command.ExecuteNonQuery();
            }
        }

        private void WriteEitLinkages(NpgsqlConnection conn, EitEvent eitEvent)
        {
			if (eitEvent.Linkages == null)
				return;

			NpgsqlCommand command = conn.CreateCommand();
			command.CommandText =
				"insert into dvb_eit_linkages (sid, tsid, onid, event_id, start_time, 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 " +
				"(@sid,@tsid,@onid,@event_id,@start_time,@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("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
			command.Parameters.AddParameter("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
			command.Parameters.AddParameter("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
			command.Parameters.AddParameter("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
			command.Parameters.AddParameter("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
			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 < eitEvent.Linkages.Count; i++)
			{
				LinkageDescriptor linkage = eitEvent.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 ? (int)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 ? (int)linkage.HandoverNetworkId.Value : DBNull.Value;
				command.Parameters["@handover_initial_service_id"].Value = linkage.HandoverInitialServiceId.HasValue ? (int)linkage.HandoverInitialServiceId.Value : DBNull.Value;
				command.Parameters["@target_event_id"].Value = linkage.TargetEventId.HasValue ? (int)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 ? (int)linkage.BouquetId.Value : DBNull.Value;
				command.ExecuteNonQuery();

				WriteEitLinkageExtendedEventLinkages(conn, eitEvent, i);
				WriteEitLinkageIpmacLinkages(conn, eitEvent, i);
				WriteEitLinkageSsuLinkStructure(conn, eitEvent, i);
			}
        }

        private void WriteEitLinkageSsuLinkStructure(NpgsqlConnection conn, EitEvent eitEvent, int i)
        {
	        if (eitEvent.Linkages[i].SystemSoftwareUpdateLinkStructure == null)
		        return;

	        for (int j = 0; j < eitEvent.Linkages[i].SystemSoftwareUpdateLinkStructure.Count; j++)
	        {
		        LinkageDescriptor.OuiPrivateData ssuLinkStruct = eitEvent.Linkages[i].SystemSoftwareUpdateLinkStructure[j];
		        throw new NotImplementedException();
	        }
        }

        private void WriteEitLinkageIpmacLinkages(NpgsqlConnection conn, EitEvent eitEvent, int i)
        {
	        if (eitEvent.Linkages[i].IpMacNotificationLinkages == null)
		        return;

	        for (int j = 0; i < eitEvent.Linkages[i].IpMacNotificationLinkages.Count; j++)
	        {
		        LinkageDescriptor.IpMacNotificationLinkage ipMacNotificationLinkage = eitEvent.Linkages[i].IpMacNotificationLinkages[j];
		        throw new NotImplementedException();
	        }
        }

        private void WriteEitLinkageExtendedEventLinkages(NpgsqlConnection conn, EitEvent eitEvent, int i)
        {
	        if (eitEvent.Linkages[i].ExtendedEventLinkages == null)
		        return;

	        for (int j = 0; i < eitEvent.Linkages[i].ExtendedEventLinkages.Length; j++)
	        {
		        LinkageDescriptor.ExtendedEventLinkageInfo extendedEventLinkage = eitEvent.Linkages[i].ExtendedEventLinkages[j];
		        throw new NotImplementedException();
	        }
        }

        private void WriteEitItems(NpgsqlConnection conn, EitEvent eitEvent)
        {
            if (eitEvent.Items == null)
                return;

            NpgsqlCommand command = conn.CreateCommand();
            command.CommandText =
	            "INSERT INTO dvb_eit_items (sid, tsid, onid, event_id, start_time, description, item, ordinal) " +
	            "VALUES (@sid, @tsid, @onid, @event_id, @start_time, @description, @item, @ordinal)";
            command.Parameters.AddParameter("@sid", NpgsqlDbType.Integer, eitEvent.ServiceId);
            command.Parameters.AddParameter("@tsid", NpgsqlDbType.Integer, eitEvent.TransportStreamId);
            command.Parameters.AddParameter("@onid", NpgsqlDbType.Integer, eitEvent.OriginalNetworkId);
            command.Parameters.AddParameter("@event_id", NpgsqlDbType.Integer, eitEvent.EventId);
            command.Parameters.AddParameter("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            command.Parameters.Add("@description", NpgsqlDbType.Text);
            command.Parameters.Add("@item", NpgsqlDbType.Text);
            command.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
			for (int i = 0; i < eitEvent.Items.Count; i++)
            {
	            EitEvent.EitEventItem item = eitEvent.Items[i];
	            command.Parameters["@description"].Value = item.Description;
	            command.Parameters["@item"].Value = item.Item;
	            command.Parameters["@ordinal"].Value = i;
                command.Parameters.CheckNulls();
                command.ExecuteNonQuery();
            }
            command.Dispose();
        }

        private void WriteEitCrids(NpgsqlConnection conn, EitEvent eitEvent)
        {
            if (eitEvent.Crids == null)
                return;

            NpgsqlCommand command = conn.CreateCommand();
            command.CommandText = "INSERT INTO dvb_eit_crids " +
                                  "(sid, tsid, onid, event_id, start_time, ordinal, crid_type, crid_location, crid_bytes, crid_ref) " +
                                  "VALUES " +
                                  "(@sid, @tsid, @onid, @event_id, @start_time, @ordinal, @crid_type, @crid_location, @crid_bytes, @crid_ref)";

            command.Parameters.AddParameter("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
            command.Parameters.AddParameter("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
            command.Parameters.AddParameter("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
            command.Parameters.AddParameter("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
            command.Parameters.AddParameter("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            command.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
            command.Parameters.Add("@crid_type", NpgsqlDbType.Integer);
            command.Parameters.Add("@crid_location", NpgsqlDbType.Integer);
            command.Parameters.Add("@crid_bytes", NpgsqlDbType.Bytea);
            command.Parameters.Add("@crid_ref", NpgsqlDbType.Integer);
			int ordinal = 0;
            foreach (ContentIdentifierDescriptor.Crid eitEventCrid in eitEvent.Crids)
            {
	            command.Parameters["@ordinal"].Value = ordinal++;
	            command.Parameters["@crid_type"].Value = (int)eitEventCrid.CridType;
	            command.Parameters["@crid_location"].Value = (int)eitEventCrid.CridLocation;
	            command.Parameters["@crid_bytes"].Value = eitEventCrid.CridBytes;
	            command.Parameters["@crid_ref"].Value = (int?)eitEventCrid.CridRef;
                command.Parameters.CheckNulls();
            }
        }

        private void WriteEitContent(NpgsqlConnection conn, EitEvent eitEvent)
        {
            if (eitEvent.Content == null)
                return;

            NpgsqlCommand command = conn.CreateCommand();
            command.CommandText = "INSERT INTO dvb_eit_content " +
                                  "(sid,tsid,onid,event_id,start_time,ordinal,l,m,r) " +
                                  "VALUES " +
                                  "(@sid,@tsid,@onid,@event_id,@start_time,@ordinal,@l,@m,@r)";
            command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
            command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
            command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
            command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
            command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            command.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
            command.Parameters.Add("@l", NpgsqlDbType.Integer);
            command.Parameters.Add("@m", NpgsqlDbType.Integer);
            command.Parameters.Add("@r", NpgsqlDbType.Integer);
            for (int i = 0; i < eitEvent.Content.Length; i++)
            {
                command.Parameters["@ordinal"].Value = i;
                command.Parameters["@l"].Value = eitEvent.Content[i].Item1;
                command.Parameters["@m"].Value = eitEvent.Content[i].Item2;
                command.Parameters["@r"].Value = eitEvent.Content[i].Item3;
                command.ExecuteNonQuery();
            }
        }

        private void WriteEitComponents(NpgsqlConnection conn, EitEvent eitEvent)
        {
            if (eitEvent.Components == null)
                return;

            NpgsqlCommand command = conn.CreateCommand();
            command.CommandText = "INSERT INTO dvb_eit_components " +
                                  "(sid, tsid, onid, event_id, start_time, ordinal, stream_content_ext, stream_content, component_type, component_tag, iso_639_language_code, text) " +
                                  "VALUES " +
                                  "(@sid, @tsid, @onid, @event_id, @start_time, @ordinal, @stream_content_ext, @stream_content, @component_type, @component_tag, @iso_639_language_code, @text)";
            command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
            command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
            command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
            command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
            command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            command.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
            command.Parameters.Add("@stream_content_ext", NpgsqlDbType.Integer);
            command.Parameters.Add("@stream_content", NpgsqlDbType.Integer);
            command.Parameters.Add("@component_type", NpgsqlDbType.Integer);
            command.Parameters.Add("@component_tag", NpgsqlDbType.Integer);
            command.Parameters.Add("@iso_639_language_code", NpgsqlDbType.Varchar);
            command.Parameters.Add("@text", NpgsqlDbType.Text);
            int ordinal = 0;
            foreach (ComponentDescriptor component in eitEvent.Components)
            {
                command.Parameters["@ordinal"].Value = ordinal++;
                command.Parameters["@stream_content_ext"].Value = component.StreamContentExt;
                command.Parameters["@stream_content"].Value = component.StreamContent;
                command.Parameters["@component_type"].Value = component.ComponentType;
                command.Parameters["@component_tag"].Value = component.ComponentTag;
                command.Parameters["@iso_639_language_code"].Value = component.Iso639LanguageCode;
                string text = component.Text;
                if (text != null)
	                text = component.Text.Trim('\0');
                command.Parameters["@text"].Value = text;
                command.Parameters.CheckNulls();
                command.ExecuteNonQuery();
            }
        }

        private void WriteEitCaSystems(NpgsqlConnection conn, EitEvent eitEvent)
        {
            if (eitEvent.CaSystems == null)
                return;

            NpgsqlCommand cmd = conn.CreateCommand();
            cmd.CommandText = "insert into dvb_eit_ca_systems (sid, tsid, onid, event_id, start_time, ordinal, caid)\r\nvalues (@sid, @tsid, @onid, @event_id, @start_time, @ordinal, @caid)";
            cmd.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
            cmd.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
            cmd.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
            cmd.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
            cmd.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
            cmd.Parameters.Add("@ordinal", NpgsqlDbType.Integer);
            cmd.Parameters.Add("@caid", NpgsqlDbType.Integer);
            for (int i = 0; i < eitEvent.CaSystems.Length; i++)
            {
                cmd.Parameters["@ordinal"].Value = i;
                cmd.Parameters["@caid"].Value = (int)eitEvent.CaSystems[i];
                cmd.ExecuteNonQuery();
            }
        }

	}
}
