using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace skyscraper5.src.Skyscraper.IO.PortableExecutables
{
	public class PeSectionStream : Stream
	{
		internal PeSectionStream(PeFile peFile, PeSection section, Stream parentStream)
		{
			PeFile = peFile;
			Section = section;
			this.parentStream = parentStream;
		}

		public PeFile PeFile { get; }
		public PeSection Section { get; }
		private int internalPosition;
		private readonly Stream parentStream;

		public override bool CanRead => true;

		public override bool CanSeek => true;

		public override bool CanWrite => false;

		public override long Length => Section.virtualSize;

		public override long Position 
		{ 
			get => internalPosition; 
			set 
			{
				if (value < 0) 
					throw new ArgumentOutOfRangeException(nameof(value));
				if (value > Section.virtualSize)
					throw new ArgumentOutOfRangeException(nameof(value));
				internalPosition = (int)value;
			}
		}

		public override void Flush()
		{
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			int endAddress = internalPosition + count;
			if (endAddress > Length)
			{
				count = (int)Length - internalPosition;
				if (count == 0)
					throw new EndOfStreamException();
			}

			parentStream.Position = Section.pointerToRawData + internalPosition;
			int result = parentStream.Read(buffer, offset, count);
			internalPosition += result;
			return result;
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			switch(origin)
			{
				case SeekOrigin.Begin:
					Position = offset;
					break;
				case SeekOrigin.Current:
					Position += offset;
					break;
				case SeekOrigin.End:
					Position = Length + offset;
					break;
			}
			return Position;
		}

		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			throw new NotSupportedException();
		}
	}
}
