/***************************************************************************
 *                               ByteQueue.cs
 *                            -------------------
 *   begin                : May 1, 2002
 *   copyright            : (C) The RunUO Software Team
 *   email                : info@runuo.com
 *
 *   $Id: ByteQueue.cs 4 2006-06-15 04:28:39Z mark $
 *
 ***************************************************************************/

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

using System;
using System.IO;

namespace Server.Network
{
	public class ByteQueue
	{
		private int m_Head;
		private int m_Tail;
		private int m_Size;

		private byte[] m_Buffer;

		public int Length{ get{ return m_Size; } }

		public ByteQueue()
		{
			m_Buffer = new byte[2048];
		}

		public void Clear()
		{
			m_Head = 0;
			m_Tail = 0;
			m_Size = 0;
		}

		private void SetCapacity( int capacity ) 
		{
			byte[] newBuffer = new byte[capacity];

			if ( m_Size > 0 )
			{
				if ( m_Head < m_Tail )
				{
					Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Size );
				}
				else
				{
					Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Buffer.Length - m_Head );
					Buffer.BlockCopy( m_Buffer, 0, newBuffer, m_Buffer.Length - m_Head, m_Tail );
				}
			}

			m_Head = 0;
			m_Tail = m_Size;
			m_Buffer = newBuffer;
		}

		public byte GetPacketID()
		{
			if ( m_Size >= 1 )
				return m_Buffer[m_Head];

			return 0xFF;
		}

		public int GetPacketLength()
		{
			if ( m_Size >= 3 )
				return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length];

			return 0;
		}

		public int Dequeue( byte[] buffer, int offset, int size )
		{
			if ( size > m_Size )
				size = m_Size;

			if ( size == 0 )
				return 0;

			if ( m_Head < m_Tail )
			{
				Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size );
			}
			else
			{
				int rightLength = ( m_Buffer.Length - m_Head );

				if ( rightLength >= size )
				{
					Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size );
				}
				else
				{
					Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, rightLength );
					Buffer.BlockCopy( m_Buffer, 0, buffer, offset + rightLength, size - rightLength );
				}
			}

			m_Head = ( m_Head + size ) % m_Buffer.Length;
			m_Size -= size;

			if ( m_Size == 0 )
			{
				m_Head = 0;
				m_Tail = 0;
			}

			return size;
		}

		public void Enqueue( byte[] buffer, int offset, int size )
		{
			if ( (m_Size + size) > m_Buffer.Length )
				SetCapacity( (m_Size + size + 2047) & ~2047 );

			if ( m_Head < m_Tail )
			{
				int rightLength = ( m_Buffer.Length - m_Tail );

				if ( rightLength >= size )
				{
					Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size );
				}
				else
				{
					Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, rightLength );
					Buffer.BlockCopy( buffer, offset + rightLength, m_Buffer, 0, size - rightLength );
				}
			}
			else
			{
				Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size );
			}

			m_Tail = ( m_Tail + size ) % m_Buffer.Length;
			m_Size += size;
		}
	}
}