using System;
using System.Collections;
using Server;
using Server.Mobiles;

/*
 ** TimedLeverItem
 ** Version 1.00
 ** updated 8/31/06
 ** ArteGordon
 */
namespace Server.Items
{

	public class TimedLeverItem : XmlLatch, ILinkable
	{
		public enum leverType { Two_State, Three_State }
		private leverType m_LeverType = leverType.Two_State;
		private int m_LeverSound = 936;
		private Item m_TargetItem0 = null;
		private string m_TargetProperty0 = null;
		private Item m_TargetItem1 = null;
		private string m_TargetProperty1 = null;
		private Item m_TargetItem2 = null;
		private string m_TargetProperty2 = null;

		private int m_ItemID0 = 0x108c;
		private int m_ItemID1 = 0x108d;
		private int m_ItemID2 = 0x108e;

		private Point3D m_Offset1 = Point3D.Zero;
		private Point3D m_Offset2 = Point3D.Zero;

		private Point3D m_OriginalLocation = Point3D.Zero;

		private Item m_LinkedItem = null;
		private bool already_being_activated = false;
		private bool beingswitched = false;

		private bool m_Disabled = false;

		public Point3D OriginalLocation
		{
			set { m_OriginalLocation = value; }
			get
			{
				if (m_OriginalLocation == Point3D.Zero)
				{
					m_OriginalLocation = Location;
				}
				return m_OriginalLocation;
			}
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public int ItemID0
		{
			get { return m_ItemID0; }
			set
			{
				m_ItemID0 = value;
				// refresh the lever static to reflect the state
				SetLeverStatic();
				InvalidateProperties();
			}
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public int ItemID1
		{
			get { return m_ItemID1; }
			set
			{
				m_ItemID1 = value;
				// refresh the lever static to reflect the state
				SetLeverStatic();
				InvalidateProperties();
			}
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public int ItemID2
		{
			get { return m_ItemID2; }
			set
			{
				m_ItemID2 = value;
				// refresh the lever static to reflect the state
				SetLeverStatic();
				InvalidateProperties();
			}
		}

		// backward compatibility with old Offset property
		public Point3D Offset
		{
			set { m_Offset1 = value; }
			get { return m_Offset1; }
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public Point3D Offset1
		{
			set { m_Offset1 = value; }
			get { return m_Offset1; }
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public Point3D Offset2
		{
			set { m_Offset2 = value; }
			get { return m_Offset2; }
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public bool Disabled
		{
			set { m_Disabled = value; }
			get { return m_Disabled; }
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public Item Link
		{
			set { m_LinkedItem = value; }
			get { return m_LinkedItem; }
		}

		[Constructable]
		public TimedLeverItem()
			: base(0x108C)
		{
			Name = "A timed lever item";
			Movable = false;
		}

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

		public override void OnLocationChange(Point3D oldLoc)
		{
			if (!beingswitched)
				m_OriginalLocation = Location;
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public override int State
		{
			get { return base.State; }
			set
			{
				// prevent infinite recursion
				if (!already_being_activated)
				{
					already_being_activated = true;
					Activate(null, value, null);
					already_being_activated = false;
				}

				InvalidateProperties();
			}
		}

		public void SetSwitchOffset()
		{
			beingswitched = true;
			switch (State)
			{
				case 0:
					Location = OriginalLocation;
					break;
				case 1:
					Location = new Point3D(OriginalLocation.X + m_Offset1.X, OriginalLocation.Y + m_Offset1.Y, OriginalLocation.Z + m_Offset1.Z);
					break;
				case 2:
					Location = new Point3D(OriginalLocation.X + m_Offset2.X, OriginalLocation.Y + m_Offset2.Y, OriginalLocation.Z + m_Offset2.Z);
					break;
			}

			beingswitched = false;
		}

		public void Activate(Mobile from, int state, ArrayList links)
		{
			if (Disabled) return;

			string status_str = null;
			bool reposition = false;

			if (state < 0) state = 0;
			if (state > 1 && m_LeverType == leverType.Two_State) state = 1;
			if (state > 2) state = 2;

			if (base.State != state)
				reposition = true;

			// assign the latch state and start the timer
			base.State = state;

			// update the graphic for the new state
			SetLeverStatic();

			// apply the position offset for the new switch state
			if (reposition)
				SetSwitchOffset();

			// play the switching sound
			try
			{
				Effects.PlaySound(Location, Map, m_LeverSound);
			}
			catch { }

			// if a target object has been specified then apply the property modification
			if (state == 0 && m_TargetItem0 != null && !m_TargetItem0.Deleted && m_TargetProperty0 != null && m_TargetProperty0.Length > 0)
			{
				BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, null, this, out status_str);
				
				if( m_TargetItem0 is BaseDoor && ( (BaseDoor)m_TargetItem0 ).Link != null )
				{
               BaseDoor link = ( (BaseDoor)m_TargetItem0 ).Link;

               if ( link != null )
                  BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, link, null, this, out status_str);
            }
			}
			if (state == 1 && m_TargetItem1 != null && !m_TargetItem1.Deleted && m_TargetProperty1 != null && m_TargetProperty1.Length > 0)
			{
				BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, null, this, out status_str);
			
				if( m_TargetItem1 is BaseDoor && ( (BaseDoor)m_TargetItem1 ).Link != null )
				{
               BaseDoor link = ( (BaseDoor)m_TargetItem1 ).Link;

               if ( link != null )
                  BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, link, null, this, out status_str);
            }
         }
			if (state == 2 && m_TargetItem2 != null && !m_TargetItem2.Deleted && m_TargetProperty2 != null && m_TargetProperty2.Length > 0)
			{
				BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty2, m_TargetItem2, null, this, out status_str);
			
				if( m_TargetItem2 is BaseDoor && ( (BaseDoor)m_TargetItem2 ).Link != null )
				{
               BaseDoor link = ( (BaseDoor)m_TargetItem2 ).Link;

               if ( link != null )
                  BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty2, link, null, this, out status_str);
            }
         }

			// if the switch is linked, then activate the link as well
			if (Link != null && Link is ILinkable)
			{
				if (links == null)
				{
					links = new ArrayList();
				}
				// activate other linked objects if they have not already been activated
				if (!links.Contains(this))
				{
					links.Add(this);

					((ILinkable)Link).Activate(from, state, links);
				}
			}

			// report any problems to staff
			if (status_str != null && from != null && from.AccessLevel > AccessLevel.Player)
			{
				from.SendMessage("{0}", status_str);
			}
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public int LeverSound
		{
			get { return m_LeverSound; }
			set
			{
				m_LeverSound = value;
				InvalidateProperties();
			}
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public leverType LeverType
		{
			get { return m_LeverType; }
			set
			{
				m_LeverType = value; State = 0;
				InvalidateProperties();
			}
		}

		[CommandProperty(AccessLevel.GameMaster)]
		public Item Target0Item
		{
			get { return m_TargetItem0; }
			set { m_TargetItem0 = value; InvalidateProperties(); }
		}
		[CommandProperty(AccessLevel.GameMaster)]
		public string Target0Property
		{
			get { return m_TargetProperty0; }
			set { m_TargetProperty0 = value; InvalidateProperties(); }
		}
		[CommandProperty(AccessLevel.GameMaster)]
		public string Target0ItemName
		{ get { if (m_TargetItem0 != null && !m_TargetItem0.Deleted) return m_TargetItem0.Name; else return null; } }

		[CommandProperty(AccessLevel.GameMaster)]
		public Item Target1Item
		{
			get { return m_TargetItem1; }
			set { m_TargetItem1 = value; InvalidateProperties(); }
		}
		[CommandProperty(AccessLevel.GameMaster)]
		public string Target1Property
		{
			get { return m_TargetProperty1; }
			set { m_TargetProperty1 = value; InvalidateProperties(); }
		}
		[CommandProperty(AccessLevel.GameMaster)]
		public string Target1ItemName
		{ get { if (m_TargetItem1 != null && !m_TargetItem1.Deleted) return m_TargetItem1.Name; else return null; } }

		[CommandProperty(AccessLevel.GameMaster)]
		public Item Target2Item
		{
			get { return m_TargetItem2; }
			set { m_TargetItem2 = value; InvalidateProperties(); }
		}
		[CommandProperty(AccessLevel.GameMaster)]
		public string Target2Property
		{
			get { return m_TargetProperty2; }
			set { m_TargetProperty2 = value; InvalidateProperties(); }
		}
		[CommandProperty(AccessLevel.GameMaster)]
		public string Target2ItemName
		{ get { if (m_TargetItem2 != null && !m_TargetItem2.Deleted) return m_TargetItem2.Name; else return null; } }

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

			writer.Write((int)0); // version
			// version 0
			writer.Write(this.m_ItemID0);
			writer.Write(this.m_ItemID1);
			writer.Write(this.m_ItemID2);
			writer.Write(this.m_Offset1);
			writer.Write(this.m_Offset2);
			writer.Write(this.m_OriginalLocation);
			writer.Write(this.m_Disabled);
			writer.Write(this.m_LinkedItem);
			writer.Write(this.m_LeverSound);
			writer.Write((int)this.m_LeverType);
			writer.Write(this.m_TargetItem0);
			writer.Write(this.m_TargetProperty0);
			writer.Write(this.m_TargetItem1);
			writer.Write(this.m_TargetProperty1);
			writer.Write(this.m_TargetItem2);
			writer.Write(this.m_TargetProperty2);
		}

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

			int version = reader.ReadInt();
			switch (version)
			{
				case 0:
					{
						m_ItemID0 = reader.ReadInt();
						m_ItemID1 = reader.ReadInt();
						m_ItemID2 = reader.ReadInt();
						m_Offset1 = reader.ReadPoint3D();
						m_Offset2 = reader.ReadPoint3D();
						m_OriginalLocation = reader.ReadPoint3D();
						m_Disabled = reader.ReadBool();

						m_LinkedItem = reader.ReadItem();
						this.m_LeverSound = reader.ReadInt();
						int ltype = reader.ReadInt();
						switch (ltype)
						{
								case (int)leverType.Two_State: this.m_LeverType = leverType.Two_State; break;
								case (int)leverType.Three_State: this.m_LeverType = leverType.Three_State; break;

						}
						this.m_TargetItem0 = reader.ReadItem();
						this.m_TargetProperty0 = reader.ReadString();
						this.m_TargetItem1 = reader.ReadItem();
						this.m_TargetProperty1 = reader.ReadString();
						this.m_TargetItem2 = reader.ReadItem();
						this.m_TargetProperty2 = reader.ReadString();
					}
					break;
			}
			// refresh the lever static to reflect the state
			SetLeverStatic();
		}

		public void SetLeverStatic()
		{


			switch (State)
			{
				case 0:
					this.ItemID = m_ItemID0;
					break;
				case 1:
					this.ItemID = m_ItemID1;
					break;
				case 2:
					this.ItemID = m_ItemID2;
					break;
				default:
					break;
			}
		}


		public override void OnDoubleClick(Mobile from)
		{
			if (from == null || Disabled) return;

			if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this))
			{
				from.SendLocalizedMessage(500446); // That is too far away.
				return;
			}
			// animate and change state
			int newstate = State + 1;
			if (newstate > 1 && m_LeverType == leverType.Two_State) newstate = 0;
			if (newstate > 2) newstate = 0;

			// carry out the switch actions
			Activate(from, newstate, null);
		}
	}
}
