using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.DNS.Protocol.ResourceRecords
{
	internal class ResourceRecord : IResourceRecord
	{
		public TimeSpan TimeToLive
		{
			get { return ttl; }
		}

		public int DataLength
		{
			get { return data.Length; }
		}

		public byte[] Data
		{
			get { return data; }
		}

		public Domain Name
		{
			get { return domain; }
		}

		public RecordType Type
		{
			get { return type; }
		}


		public RecordClass Class
		{
			get { return klass; }
		}

		public int Size
		{
			get { return domain.Size + Tail.SIZE + data.Length; }
		}


		public byte[] ToArray() { 
			throw new NotImplementedException();
		}

		private Domain domain;
		private RecordType type;
		private RecordClass klass;
		private TimeSpan ttl;
		private byte[] data;

		[Marshalling.Endian(Marshalling.Endianness.Big)]
		[StructLayout(LayoutKind.Sequential, Pack = 2)]
		private struct Tail
		{
			public const int SIZE = 10;

			private ushort type;
			private ushort klass;
			private uint ttl;
			private ushort dataLength;

			public RecordType Type
			{
				get { return (RecordType)type; }
				set { type = (ushort)value; }
			}

			public RecordClass Class
			{
				get { return (RecordClass)klass; }
				set { klass = (ushort)value; }
			}

			public TimeSpan TimeToLive
			{
				get { return TimeSpan.FromSeconds(ttl); }
				set { ttl = (uint)value.TotalSeconds; }
			}

			public int DataLength
			{
				get { return dataLength; }
				set { dataLength = (ushort)value; }
			}
		}

		public static ResourceRecord FromArray(byte[] message, int offset, out int endOffset)
		{
			Domain domain = Domain.FromArray(message, offset, out offset);
			Tail tail = Marshalling.Struct.GetStruct<Tail>(message, offset, Tail.SIZE);

			byte[] data = new byte[tail.DataLength];

			offset += Tail.SIZE;
			Array.Copy(message, offset, data, 0, data.Length);

			endOffset = offset + data.Length;

			return new ResourceRecord(domain, data, tail.Type, tail.Class, tail.TimeToLive);
		}

		public ResourceRecord(Domain domain, byte[] data, RecordType type,
				RecordClass klass = RecordClass.IN, TimeSpan ttl = default(TimeSpan))
		{
			this.domain = domain;
			this.type = type;
			this.klass = klass;
			this.ttl = ttl;
			this.data = data;
		}
	}
}
