using log4net;
using skyscraper5.Skyscraper.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper8.DvbNip;

namespace skyscraper8.Ietf.Rfc4566_SDP
{
	public class SDP
	{
		private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);

		public static bool IsSDP(Stream ms)
		{
			if (ms.GetAvailableBytes() < 3)
				return false;

			byte byteA = ms.ReadUInt8();
			byte byteB = ms.ReadUInt8();
			ms.Position -= 2;

			if (byteA != 'v')
				return false;

			if (byteB != '=')
				return false;

			return true;
		}

		public static SDP Load(Stream stream)
		{
			StreamReader sr = new StreamReader(stream);
			SDP result = null;
			while (!sr.EndOfStream)
			{
				string line = sr.ReadLine();
				if (line[1] != '=')
				{
					logger.ErrorFormat("Invalid SDP description!");
					return result;
				}

				if (result == null)
					result = new SDP();
				char opcode = line[0];
				string args = line.Substring(2);
				switch (opcode)
				{
					case 'v':
						result.Version = new Version(int.Parse(args), 0);
						break;
					case 'o':
						result.Originator = new SdpOriginator(args.Split(' '));
						break;
					case 's':
						result.SessionName = args;
						break;
					case 't':
						result.Times = new SdpTimes(args.Split(' '));
						break;
					case 'a':
						if (result.Attributes == null)
							result.Attributes = new SdpAttributeCollection();
						result.Attributes.SetHint(args);
						break;
					case 'm':
						if (result._mediaAnnouncements == null)
							result._mediaAnnouncements = new List<SdpMedia>();
						result._mediaAnnouncements.Add(new SdpMedia(args.Split(' ')));
						break;
					case 'c':
						if (result._connections == null)
							result._connections = new List<SdpConnectionData>();
						result._connections.Add(new SdpConnectionData(args.Split(' ')));
						break;
					case 'b':
						string bandwidthType = args.Substring(0, 2);
						string bandwidthValue = args.Substring(3);
						switch (bandwidthType)
						{
							case "CT":
								result.ConferenceTotalBandwidth = long.Parse(bandwidthValue);
								break;
							case "AS":
								result.ApplicationSpecificMaximumBandwidth = long.Parse(bandwidthValue);
								break;
							default:
								logger.WarnFormat("Unknown bandwidth type: {0}", bandwidthType);
								break;
						}
						break;
					default:
						logger.ErrorFormat("Invalid SDP opcode \"{0}\", please consider sharing a sample of this stream for further analysis.", opcode);
						break;
				}
			}

			return result;
		}

		public long? ApplicationSpecificMaximumBandwidth { get; private set; }

		public long? ConferenceTotalBandwidth { get; private set; }


		private List<SdpMedia> _mediaAnnouncements;
		private List<SdpConnectionData> _connections;

		public IReadOnlyList<SdpConnectionData> ConnectionData
		{
			get
			{
				return _connections.AsReadOnly();
			}
		}
		public IReadOnlyList<SdpMedia> MediaAnnouncements
		{
			get
			{
				return _mediaAnnouncements.AsReadOnly();
			}
		}
		public SdpAttributeCollection Attributes { get; private set; }
		public SdpTimes Times { get; private set; }

		public string SessionName { get; private set; }

		public SdpOriginator Originator { get; private set; }

		public Version Version { get; private set; }

		public MulticastGatewayConfigurationType ToMulticastGatewayConfiguration()
		{
			MulticastGatewayConfigurationType result = new MulticastGatewayConfigurationType();
			result.MulticastSession = new MulticastSessionType[_connections.Count];

			for (int i = 0; i < _connections.Count; i++)
			{
				result.MulticastSession[i] = new MulticastSessionType();
				result.MulticastSession[i].serviceIdentifier = Originator.ToString();
				result.MulticastSession[i].MulticastTransportSession = new MulticastTransportSessionType[1];
				result.MulticastSession[i].MulticastTransportSession[0] = new MulticastTransportSessionType();
				result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress = new MulticastEndpointAddressType[1];
				result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0] = new MulticastEndpointAddressType();
				result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0].NetworkDestinationGroupAddress = _connections[i].DestinationAddress;
				result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0].NetworkSourceAddress = Originator.Address.ToString();
				result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0].TransportDestinationPort = _mediaAnnouncements[i].Port.ToString();
			}

			return result;
		}
	}

	
}
