using System;
using Server;

namespace Server.Items
{
	public class RaisableItem : Item
	{
		private int m_MaxElevation;
		private int m_MoveSound;
		private int m_StopSound;
		private TimeSpan m_CloseDelay;

		[CommandProperty( AccessLevel.GameMaster )]
		public int MaxElevation
		{
			get{ return m_MaxElevation; }
			set
			{
				if ( value <= 0 )
					m_MaxElevation = 0;
				else if ( value >= 60 )
					m_MaxElevation = 60;
				else
					m_MaxElevation = value;
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public int MoveSound{ get{ return m_MoveSound; } set{ m_MoveSound = value; } }

		[CommandProperty( AccessLevel.GameMaster )]
		public int StopSound{ get{ return m_StopSound; } set{ m_StopSound = value; } }

		[CommandProperty( AccessLevel.GameMaster )]
		public TimeSpan CloseDelay{ get{ return m_CloseDelay; } set{ m_CloseDelay = value; } }

		[Constructable]
		public RaisableItem( int itemID ) : this( itemID, 20, -1, -1, TimeSpan.FromMinutes( 1.0 ) )
		{
		}

		[Constructable]
		public RaisableItem( int itemID, int maxElevation, TimeSpan closeDelay ) : this( itemID, maxElevation, -1, -1, closeDelay )
		{
		}

		[Constructable]
		public RaisableItem( int itemID, int maxElevation, int moveSound, int stopSound, TimeSpan closeDelay ) : base( itemID )
		{
			Movable = false;

			m_MaxElevation = maxElevation;
			m_MoveSound = moveSound;
			m_StopSound = stopSound;
			m_CloseDelay = closeDelay;
		}

		private int m_Elevation;
		private RaiseTimer m_RaiseTimer;

		public bool IsRaisable
		{
			get{ return m_RaiseTimer == null; }
		}

		public void Raise()
		{
			if ( !IsRaisable )
				return;

			m_RaiseTimer = new RaiseTimer( this );
			m_RaiseTimer.Start();
		}

		private class RaiseTimer : Timer
		{
			private RaisableItem m_Item;
			private DateTime m_CloseTime;
			private bool m_Up;
			private int m_Step;

			public RaiseTimer( RaisableItem item ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 0.5 ) )
			{
				m_Item = item;
				m_CloseTime = DateTime.UtcNow + item.CloseDelay;
				m_Up = true;

				Priority = TimerPriority.TenMS;
			}

			protected override void OnTick()
			{
				if ( m_Item.Deleted )
				{
					Stop();
					return;
				}

				if ( m_Step++ % 3 == 0 )
				{
					if ( m_Up )
					{
						m_Item.Z++;

						if ( ++m_Item.m_Elevation >= m_Item.MaxElevation )
						{
							Stop();

							if ( m_Item.StopSound >= 0 )
								Effects.PlaySound( m_Item.Location, m_Item.Map, m_Item.StopSound );

							m_Up = false;
							m_Step = 0;

							TimeSpan delay = m_CloseTime - DateTime.UtcNow;
							Timer.DelayCall( delay > TimeSpan.Zero ? delay : TimeSpan.Zero, new TimerCallback( Start ) );

							return;
						}
					}
					else
					{
						m_Item.Z--;

						if ( --m_Item.m_Elevation <= 0 )
						{
							Stop();

							if ( m_Item.StopSound >= 0 )
								Effects.PlaySound( m_Item.Location, m_Item.Map, m_Item.StopSound );

							m_Item.m_RaiseTimer = null;

							return;
						}
					}
				}

				if ( m_Item.MoveSound >= 0 )
					Effects.PlaySound( m_Item.Location, m_Item.Map, m_Item.MoveSound );
			}
		}

		public RaisableItem( Serial serial ) : base( serial )
		{
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );

			writer.WriteEncodedInt( (int) 0 ); // version

			writer.WriteEncodedInt( (int) m_MaxElevation );
			writer.WriteEncodedInt( (int) m_MoveSound );
			writer.WriteEncodedInt( (int) m_StopSound );
			writer.Write( (TimeSpan) m_CloseDelay );

			writer.WriteEncodedInt( (int) m_Elevation );
		}

		public override void Deserialize( GenericReader reader )
		{
			base.Deserialize( reader );

			int version = reader.ReadEncodedInt();

			m_MaxElevation = reader.ReadEncodedInt();
			m_MoveSound = reader.ReadEncodedInt();
			m_StopSound = reader.ReadEncodedInt();
			m_CloseDelay = reader.ReadTimeSpan();

			int elevation = reader.ReadEncodedInt();
			this.Z -= elevation;
		}
	}
}