    //Rev 187

using System;
using System.Collections;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Gumps;
using Server.Items;
using Server.Multis;
using Server.Network;

namespace Server.Engines.Plants
{
	public enum PlantStatus
	{
		BowlOfDirt		= 0,
		Seed			= 1,
		Sapling			= 2,
		Plant			= 4,
		FullGrownPlant	= 7,
		DecorativePlant = 10,
		DeadTwigs		= 11,

		Stage1			= 1,
		Stage2			= 2,
		Stage3			= 3,
		Stage4			= 4,
		Stage5			= 5,
		Stage6			= 6,
		Stage7			= 7,
		Stage8			= 8,
		Stage9			= 9
	}

	public class PlantItem : Item, ISecurable
	{
		private PlantSystem m_PlantSystem;

		private PlantStatus m_PlantStatus;
		private PlantType m_PlantType;
		private PlantHue m_PlantHue;
		private bool m_ShowType;

		private SecureLevel m_Level;

		[CommandProperty( AccessLevel.GameMaster )]
		public SecureLevel Level
		{
			get{ return m_Level; }
			set{ m_Level = value; }
		}

		public PlantSystem PlantSystem { get { return m_PlantSystem; } }

		public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } }

		public override int LabelNumber
		{
			get
			{
				if ( m_PlantStatus >= PlantStatus.DeadTwigs )
					return base.LabelNumber;
				else if ( m_PlantStatus >= PlantStatus.DecorativePlant )
					return 1061924; // a decorative plant
				else if ( m_PlantStatus >= PlantStatus.FullGrownPlant )
					return PlantTypeInfo.GetInfo( m_PlantType ).Name;
				else
					return 1029913; // plant bowl
			}
		}


		[CommandProperty( AccessLevel.GameMaster )]
		public PlantStatus PlantStatus
		{
			get { return m_PlantStatus; }
			set
			{
				if ( m_PlantStatus == value || value < PlantStatus.BowlOfDirt || value > PlantStatus.DeadTwigs )
					return;

				double ratio;
				if ( m_PlantSystem != null )
					ratio = (double) m_PlantSystem.Hits / m_PlantSystem.MaxHits;
				else
					ratio = 1.0;

				m_PlantStatus = value;

				if ( m_PlantStatus >= PlantStatus.DecorativePlant )
				{
					m_PlantSystem = null;
				}
				else
				{
					if ( m_PlantSystem == null )
						m_PlantSystem = new PlantSystem( this, false );

					int hits = (int)( m_PlantSystem.MaxHits * ratio );

					if ( hits == 0 && m_PlantStatus > PlantStatus.BowlOfDirt )
						m_PlantSystem.Hits = hits + 1;
					else
						m_PlantSystem.Hits = hits;
				}

				Update();
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public PlantType PlantType
		{
			get { return m_PlantType; }
			set
			{
				m_PlantType = value;
				Update();
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public PlantHue PlantHue
		{
			get { return m_PlantHue; }
			set
			{
				m_PlantHue = value;
				Update();
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public bool ShowType
		{
			get { return m_ShowType; }
			set
			{
				m_ShowType = value;
				InvalidateProperties();
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public bool ValidGrowthLocation
		{
			get
			{
				if ( IsLockedDown && RootParent == null )
					return true;


				Mobile owner = RootParent as Mobile;
				if ( owner == null )
					return false;

				if ( owner.Backpack != null && IsChildOf( owner.Backpack ) )
					return true;

				BankBox bank = owner.FindBankNoCreate();
				if ( bank != null && IsChildOf( bank ) )
					return true;

				return false;
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public bool IsGrowable
		{
			get { return m_PlantStatus >= PlantStatus.BowlOfDirt && m_PlantStatus <= PlantStatus.Stage9; }
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public bool IsCrossable
		{
			get { return PlantHueInfo.IsCrossable( PlantHue ) && PlantTypeInfo.IsCrossable( PlantType ); }
		}

		private static readonly ArrayList m_Instances = new ArrayList();

		public static ArrayList Plants{ get{ return m_Instances; } }

		[Constructable]
		public PlantItem() : this( false )
		{
		}

		[Constructable]
		public PlantItem( bool fertileDirt ) : base( 0x1602 )
		{
			Weight = 1.0;

			m_PlantStatus = PlantStatus.BowlOfDirt;
			m_PlantSystem = new PlantSystem( this, fertileDirt );
			m_Level = SecureLevel.CoOwners;

			m_Instances.Add( this );
		}

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

		public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
		{
			base.GetContextMenuEntries( from, list );
			SetSecureLevelEntry.AddTo( from, this, list );
		}

		public string GetLocalizedPlantStatus()
		{
			if ( m_PlantStatus >= PlantStatus.Plant )
				return "plant"; // plant
			else if ( m_PlantStatus >= PlantStatus.Sapling )
				return "sapling"; // sapling
            else if (m_PlantStatus >= PlantStatus.Seed)
                return "seed"; // seed
			else
				return "dirt"; // seed
		}

		private void Update()
		{
			if ( m_PlantStatus >= PlantStatus.DeadTwigs )
			{
				ItemID = 0x1B9D;
				Hue = PlantHueInfo.GetInfo( m_PlantHue ).Hue;
			}
			else if ( m_PlantStatus >= PlantStatus.FullGrownPlant )
			{
				ItemID = PlantTypeInfo.GetInfo( m_PlantType ).ItemID;
				Hue = PlantHueInfo.GetInfo( m_PlantHue ).Hue;
			}
			else if ( m_PlantStatus >= PlantStatus.Plant )
			{
				ItemID = 0x1600;
				Hue = 0;
			}
			else
			{
				ItemID = 0x1602;
				Hue = 0;
			}

			InvalidateProperties();
		}

        public override void OnSingleClick(Mobile from)
        {
            if (m_PlantStatus >= PlantStatus.DeadTwigs)
                base.OnSingleClick(from);
            else if (m_PlantStatus >= PlantStatus.FullGrownPlant)
            {
                PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo(m_PlantType);

                if (m_PlantStatus < PlantStatus.DecorativePlant)
                {
                    if (typeInfo.ContainsPlant)
                        LabelTo(from, string.Format("{0} {1} {2}", m_PlantSystem.GetLocalizedHealth(), PlantHue.ToString().ToLower(), PlantType.ToString().ToLower()));
                    else
                        LabelTo(from, string.Format("{0} bright {1} {2} plant", m_PlantSystem.GetLocalizedHealth(), PlantHue.ToString().ToLower(), PlantType.ToString().ToLower()));
                }
                else
                    LabelTo(from, string.Format("Decorative {0} {1}", PlantHue.ToString().ToLower(), PlantType.ToString().ToLower()));
            }
            else if (m_PlantStatus >= PlantStatus.Seed)
            {
                if (m_ShowType)
                {
                    PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo(m_PlantType);

                    if (typeInfo.ContainsPlant && m_PlantStatus == PlantStatus.Plant)
                        LabelTo(from, string.Format("Bowl of {0} dirt with a {1} {2} {3}", m_PlantSystem.GetLocalizedDirtStatus().ToLower(), m_PlantSystem.GetLocalizedHealth().ToLower(), PlantHue.ToString().ToLower(), PlantType.ToString().ToLower()));
                    else
                        LabelTo(from, string.Format("Bowl of {0} dirt with a {1} {2} {3} {4}", m_PlantSystem.GetLocalizedDirtStatus().ToLower(), m_PlantSystem.GetLocalizedHealth().ToLower(), PlantHue.ToString().ToLower(), GetLocalizedPlantStatus().ToLower(), PlantType.ToString().ToLower()));
                }
                else
                    LabelTo(from, string.Format("Bowl of {0} dirt with a {1} {2} {3}", m_PlantSystem.GetLocalizedDirtStatus().ToLower(), m_PlantSystem.GetLocalizedHealth().ToLower(), PlantHue.ToString().ToLower(), GetLocalizedPlantStatus().ToLower()));
            }
            else
                LabelTo(from, string.Format("Bowl of {0} dirt ",  m_PlantSystem.GetLocalizedDirtStatus().ToLower()));
        }

        public override void AddNameProperty(ObjectPropertyList list)
        {
            if (m_PlantStatus >= PlantStatus.DeadTwigs)
            {
                base.AddNameProperty(list);
            }
            else if (m_PlantStatus >= PlantStatus.FullGrownPlant)
            {
                PlantHueInfo hueInfo = PlantHueInfo.GetInfo(m_PlantHue);
                PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo(m_PlantType);

                int title = PlantTypeInfo.GetBonsaiTitle(m_PlantType);
                if (title == 0) // Not a bonsai
                    title = hueInfo.Name;

                if (m_PlantStatus < PlantStatus.DecorativePlant)
                {
                    if (m_PlantType == PlantType.SugarCanes)
                    {
                        string args = string.Format("#{0}", m_PlantSystem.GetLocalizedHealth());
                        list.Add(1094702, args); // ~1_HEALTH~ Sugar Canes
                    }
                    else
                    {

                        string args = string.Format("#{0}\t#{1}\t#{2}", m_PlantSystem.GetLocalizedHealth(), title, typeInfo.Name);

                        if (typeInfo.ContainsPlant)
                        {
                            // a ~1_HEALTH~ [bright] ~2_COLOR~ ~3_NAME~
                            list.Add(hueInfo.IsBright() ? 1061891 : 1061889, args);
                        }
                        else
                        {
                            // a ~1_HEALTH~ [bright] ~2_COLOR~ ~3_NAME~ plant
                            list.Add(hueInfo.IsBright() ? 1061892 : 1061890, args);
                        }
                    }
                }
                else
                {
                    if (m_PlantType == PlantType.SugarCanes)
                        list.Add(1094703); // Decorative Sugar Canes
                    else if (title == 1080528)
                        // a decorative ~2_TYPE~
                        list.Add(1080539, string.Format("#{0}\t#{1}", title, typeInfo.Name));
                    else
                        // a decorative [bright] ~1_COLOR~ ~2_TYPE~
                        list.Add(hueInfo.IsBright() ? 1074267 : 1070973, string.Format("#{0}\t#{1}", title, typeInfo.Name));
                }
            }
            else if (m_PlantStatus >= PlantStatus.Seed)
            {
                PlantHueInfo hueInfo = PlantHueInfo.GetInfo(m_PlantHue);

                int title = PlantTypeInfo.GetBonsaiTitle(m_PlantType);
                if (title == 0) // Not a bonsai
                    title = hueInfo.Name;

                string args = string.Format("#{0}\t#{1}\t#{2}", m_PlantSystem.GetLocalizedDirtStatus(), m_PlantSystem.GetLocalizedHealth(), title);

                // 7.0.12.0 cliloc change
                args = String.Concat("#1150435\t", args); // TODO: Change to plant container type when implemented

                if (m_ShowType)
                {
                    PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo(m_PlantType);
                    args += "\t#" + typeInfo.Name.ToString();

                    if (typeInfo.ContainsPlant && m_PlantStatus == PlantStatus.Plant)
                    {
                        // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~
                        list.Add(hueInfo.IsBright() ? 1060832 : 1060831, args);
                    }
                    else
                    {
                        // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~ ~6_val~
                        list.Add(hueInfo.IsBright() ? 1061887 : 1061888, args + "\t#" + GetLocalizedPlantStatus().ToString());
                    }
                }
                else
                {
                    // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~
                    list.Add(hueInfo.IsBright() ? 1060832 : 1060831, args + "\t#" + GetLocalizedPlantStatus().ToString());
                }
            }
            else
            {
                string args = "#" + m_PlantSystem.GetLocalizedDirtStatus();

                // 7.0.12.0 cliloc change
                args = String.Concat("#1150435\t", args); // TODO: Change to plant container type when implemented

                list.Add(1060830, args); // a ~1_val~ of ~2_val~ dirt
            }
        }

		public bool IsUsableBy( Mobile from )
		{
			Item root = RootParent as Item;
			return IsChildOf( from.Backpack ) || IsChildOf( from.FindBankNoCreate() ) || IsLockedDown && IsAccessibleTo( from ) || root != null && root.IsSecure && root.IsAccessibleTo( from );
		}

		public override void OnDoubleClick( Mobile from )
		{
			if ( m_PlantStatus >= PlantStatus.DecorativePlant )
				return;

            Point3D loc = this.GetWorldLocation();

            if (!from.InLOS(loc) || !from.InRange(loc, 2))
            {
                from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1019045); // I can't reach that.
                return;
            }

			if ( !IsUsableBy( from ) )
			{
				LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it.
				return;
			}

			from.SendGump( new MainPlantGump( this ) );
		}

		public void PlantSeed( Mobile from, Seed seed )
		{
			if ( m_PlantStatus >= PlantStatus.FullGrownPlant )
			{
                LabelTo(from, 1061919); // You must use a seed on some prepared soil!
            }
			else if ( !IsUsableBy( from ) )
			{
				LabelTo( from, 1061921 ); // The bowl of dirt must be in your pack, or you must lock it down.
			}
			else if ( m_PlantStatus != PlantStatus.BowlOfDirt )
			{
				if ( m_PlantStatus >= PlantStatus.Plant )
					LabelTo( from, "This bowl of dirt already has a plant in it!" );
				else if ( m_PlantStatus >= PlantStatus.Sapling )
					LabelTo( from, "This bowl of dirt already has a sapling in it!" );
				else
					LabelTo( from, "This bowl of dirt already has a seed in it!" );
			}
			else if ( m_PlantSystem.Water < 2 )
			{
                LabelTo(from, 1061920); // The dirt needs to be softened first.
            }
			else
			{
				m_PlantType = seed.PlantType;
				m_PlantHue = seed.PlantHue;
				m_ShowType = seed.ShowType;

                seed.Consume();

				PlantStatus = PlantStatus.Seed;

				m_PlantSystem.Reset( false );

				LabelTo( from, 1061922 ); // You plant the seed in the bowl of dirt.
			}
		}

		public void Die()
		{
			if ( m_PlantStatus >= PlantStatus.FullGrownPlant )
			{
				PlantStatus = PlantStatus.DeadTwigs;
			}
			else
			{
				PlantStatus = PlantStatus.BowlOfDirt;
				m_PlantSystem.Reset( true );
			}
		}

		public void Pour( Mobile from, Item item )
		{
			if ( m_PlantStatus >= PlantStatus.DeadTwigs )
				return;

			if ( m_PlantStatus == PlantStatus.DecorativePlant )
			{
				LabelTo( from, 1053049 ); // This is a decorative plant, it does not need watering!
				return;
			}

			if ( !IsUsableBy( from ) )
			{
				LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it.
				return;
			}

			if ( item is BaseBeverage )
			{
				BaseBeverage beverage = (BaseBeverage)item;

				if ( beverage.IsEmpty || !beverage.Pourable || beverage.Content != BeverageType.Water )
				{
					LabelTo( from, 1053069 ); // You can't use that on a plant!
					return;
				}

				if ( !beverage.ValidateUse( from, true ) )
					return;

				beverage.Quantity--;
				m_PlantSystem.Water++;

				from.PlaySound( 0x4E );
				LabelTo( from, 1061858 ); // You soften the dirt with water.
			}
			else if ( item is BasePotion )
			{
				BasePotion potion = (BasePotion)item;

				int message;
				if ( ApplyPotion( potion.PotionEffect, false, out message ) )
				{
                    potion.Consume();
					from.PlaySound( 0x240 );
					from.AddToBackpack( new Bottle() );
				}
				LabelTo( from, message );
			}
			else if ( item is PotionKeg )
			{
				PotionKeg keg = (PotionKeg)item;

				if ( keg.Held <= 0 )
				{
					LabelTo( from, 1053069 ); // You can't use that on a plant!
					return;
				}

				int message;
				if ( ApplyPotion( keg.Type, false, out message ) )
				{
					keg.Held--;
                    keg.ColorKeg();
					from.PlaySound( 0x240 );
				}
				LabelTo( from, message );
			}
			else
			{
				LabelTo( from, 1053069 ); // You can't use that on a plant!
			}
		}

		public bool ApplyPotion( PotionEffect effect, bool testOnly, out int message )
		{
			if ( m_PlantStatus >= PlantStatus.DecorativePlant )
			{
				message = 1053049; // This is a decorative plant, it does not need watering!
				return false;
			}

			if ( m_PlantStatus == PlantStatus.BowlOfDirt )
			{
				message = 1053066; // You should only pour potions on a plant or seed!
				return false;
			}

			bool full = false;

			if ( effect == PotionEffect.PoisonGreater || effect == PotionEffect.PoisonDeadly )
			{
				if ( m_PlantSystem.IsFullPoisonPotion )
					full = true;
				else if ( !testOnly )
					m_PlantSystem.PoisonPotion++;
			}
			else if ( effect == PotionEffect.CureGreater )
			{
				if ( m_PlantSystem.IsFullCurePotion )
					full = true;
				else if ( !testOnly )
					m_PlantSystem.CurePotion++;
			}
			else if ( effect == PotionEffect.HealGreater )
			{
				if ( m_PlantSystem.IsFullHealPotion )
					full = true;
				else if ( !testOnly )
					m_PlantSystem.HealPotion++;
			}
			else if ( effect == PotionEffect.StrengthGreater )
			{
				if ( m_PlantSystem.IsFullStrengthPotion )
					full = true;
				else if ( !testOnly )
					m_PlantSystem.StrengthPotion++;
			}
			else if ( effect == PotionEffect.PoisonLesser || effect == PotionEffect.Poison || effect == PotionEffect.CureLesser || effect == PotionEffect.Cure ||
				effect == PotionEffect.HealLesser || effect == PotionEffect.Heal ||	effect == PotionEffect.Strength )
			{
				message = 1053068; // This potion is not powerful enough to use on a plant!
				return false;
			}
			else
			{
				message = 1053069; // You can't use that on a plant!
				return false;
			}

			if ( full )
			{
				message = 1053065; // The plant is already soaked with this type of potion!
				return false;
			}
			else
			{
				message = 1053067; // You pour the potion over the plant.
				return true;
			}
		}

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

			writer.Write( 1 ); // version

			writer.Write( (int) m_Level );

			writer.Write( (int) m_PlantStatus );
			writer.Write( (int) m_PlantType );
			writer.Write( (int) m_PlantHue );
			writer.Write( m_ShowType );

			if ( m_PlantStatus < PlantStatus.DecorativePlant )
				m_PlantSystem.Save( writer );
		}

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

			int version = reader.ReadInt();

			switch ( version )
			{
				case 1:
				{
					m_Level = (SecureLevel)reader.ReadInt();
					goto case 0;
				}
				case 0:
				{
					if ( version < 1 )
						m_Level = SecureLevel.CoOwners;

					m_PlantStatus = (PlantStatus)reader.ReadInt();
					m_PlantType = (PlantType)reader.ReadInt();
					m_PlantHue = (PlantHue)reader.ReadInt();
					m_ShowType = reader.ReadBool();

					if ( m_PlantStatus < PlantStatus.DecorativePlant )
						m_PlantSystem = new PlantSystem( this, reader );

					break;
				}
			}

			m_Instances.Add( this );
		}

		public override void OnAfterDelete()
		{
			base.OnAfterDelete();

			m_Instances.Remove( this );
		}
	}
}