context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using Server;
  using Server.Items;
  using Server.Mobiles;
  using Server.Multis;
  using Server.Network;
  using Server.Gumps;
  using Server.ContextMenus;
  
  namespace Server.Items
  {
  	public class Aquarium : BaseAddonContainer
  	{
  		public static readonly TimeSpan EvaluationInterval = TimeSpan.FromDays( 1 );
  
  		// items info
  		private int m_LiveCreatures;
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int LiveCreatures
  		{
  			get{ return m_LiveCreatures; }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int DeadCreatures
  		{
  			get
  			{
  				int dead = 0;
  
  				for ( int i = 0; i < Items.Count; i ++ )
  				{
  					if ( Items[ i ] is BaseFish )
  					{
  						BaseFish fish = (BaseFish) Items[ i ];
  
  						if ( fish.Dead )
  							dead += 1;
  					}
  				}
  
  				return dead;
  			}
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int MaxLiveCreatures
  		{
  			get
  			{
  				int state = ( m_Food.State == (int) FoodState.Overfed ) ? 1 : (int) FoodState.Full - m_Food.State;
  
  				state += (int) WaterState.Strong - m_Water.State;
  
  				state = (int) Math.Pow( state, 1.75 );
  
  				return MaxItems - state;
  			}
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public bool IsFull
  		{
  			get{ return ( Items.Count >= MaxItems ); }
  		}
  
  		// vacation info
  		private int m_VacationLeft;
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int VacationLeft
  		{
  			get{ return m_VacationLeft; }
  			set{ m_VacationLeft = value; InvalidateProperties(); }
  		}
  
  		// aquarium state
  		private AquariumState m_Food;
  		private AquariumState m_Water;
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public AquariumState Food
  		{
  			get{ return m_Food; }
  			set{ m_Food = value; InvalidateProperties(); }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public AquariumState Water
  		{
  			get{ return m_Water; }
  			set{ m_Water = value; InvalidateProperties(); }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public bool OptimalState
  		{
  			get{ return ( m_Food.State == (int) FoodState.Full && m_Water.State == (int) WaterState.Strong ); }
  		}
  
  		// events
  		private List<int> m_Events;
  		private bool m_RewardAvailable;
  		private bool m_EvaluateDay;
  
  		public List<int> Events
  		{
  			get{ return m_Events; }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public bool RewardAvailable
  		{
  			get{ return m_RewardAvailable; }
  			set{ m_RewardAvailable = value; InvalidateProperties(); }
  		}
  
  		// evaluate timer
  		private Timer m_Timer;
  
  		public override BaseAddonContainerDeed Deed
  		{
  			get
  			{
  				if ( ItemID == 0x3062 )
  					return new AquariumEastDeed();
  				else
  					return new AquariumNorthDeed();
  			}
  		}
  
  		public override double DefaultWeight{ get{ return 10.0; } }
  
  		public Aquarium( int itemID ) : base( itemID )
  		{
  			Movable = false;
  
  			if ( itemID == 0x3060 )
  				AddComponent( new AddonContainerComponent( 0x3061 ), -1, 0, 0 );
  
  			if ( itemID == 0x3062 )
  				AddComponent( new AddonContainerComponent( 0x3063 ), 0, -1, 0 );
  
  			MaxItems = 30;
  
  			m_Food = new AquariumState();
  			m_Water = new AquariumState();
  
  			m_Food.State = (int) FoodState.Full;
  			m_Water.State = (int) WaterState.Strong;
  
  			m_Food.Maintain = Utility.RandomMinMax( 1, 2 );
  			m_Food.Improve = m_Food.Maintain + Utility.RandomMinMax( 1, 2 );
  
  			m_Water.Maintain = Utility.RandomMinMax( 1, 3 );
  
  			m_Events = new List<int>();
  
  			m_Timer = Timer.DelayCall( EvaluationInterval, EvaluationInterval, new TimerCallback( Evaluate ) );
  		}
  
  		public Aquarium( Serial serial ) : base( serial )
  		{
  		}
  
  		public override void OnDelete()
  		{
  			if ( m_Timer != null )
  			{
  				m_Timer.Stop();
  				m_Timer = null;
  			}
  		}
  
  		public override void OnDoubleClick( Mobile from )
  		{
  			ExamineAquarium( from );
  		}
  
  		public virtual bool HasAccess( Mobile from )
  		{
  			if ( from == null || from.Deleted )
  				return false;
  			else if ( from.AccessLevel >= AccessLevel.GameMaster )
  				return true;
  
  			BaseHouse house = BaseHouse.FindHouseAt( this );
  
  			return ( house != null && house.IsCoOwner( from ) );
  		}
  
  		public override bool OnDragDrop( Mobile from, Item dropped )
  		{
  			if ( !HasAccess( from ) )
  			{
  				from.SendLocalizedMessage( 1073821 ); // You do not have access to that item for use with the aquarium.
  				return false;
  			}
  
  			if ( m_VacationLeft > 0 )
  			{
  				from.SendLocalizedMessage( 1074427 ); // The aquarium is in vacation mode.
  				return false;
  			}
  
  			bool takeItem = true;
  
  			if ( dropped is FishBowl )
  			{
  				FishBowl bowl = (FishBowl) dropped;
  
  				if ( bowl.Empty || !AddFish( from, bowl.Fish ) )
  					return false;
  
  				bowl.InvalidateProperties();
  
  				takeItem = false;
  			}
  			else if ( dropped is BaseFish )
  			{
  				BaseFish fish = (BaseFish) dropped;
  
  				if ( !AddFish( from, fish ) )
  					return false;
  			}
  			else if ( dropped is VacationWafer )
  			{
  				m_VacationLeft = VacationWafer.VacationDays;
  				dropped.Delete();
  
  				from.SendLocalizedMessage( 1074428, m_VacationLeft.ToString() ); // The aquarium will be in vacation mode for ~1_DAYS~ days
  			}
  			else if ( dropped is AquariumFood )
  			{
  				m_Food.Added += 1;
  				dropped.Delete();
  
  				from.SendLocalizedMessage( 1074259, "1" ); // ~1_NUM~ unit(s) of food have been added to the aquarium.
  			}
  			else if ( dropped is BaseBeverage )
  			{
  				BaseBeverage beverage = (BaseBeverage) dropped;
  
  				if ( beverage.IsEmpty || !beverage.Pourable || beverage.Content != BeverageType.Water )
  				{
  					from.SendLocalizedMessage( 500840 ); // Can't pour that in there.
  					return false;
  				}
  
  				m_Water.Added += 1;
  				beverage.Quantity -= 1;
  
  				from.PlaySound( 0x4E );
  				from.SendLocalizedMessage( 1074260, "1" ); // ~1_NUM~ unit(s) of water have been added to the aquarium.
  
  				takeItem = false;
  			}
  			else if ( !AddDecoration( from, dropped ) )
  			{
  				takeItem = false;
  			}
  
  			from.CloseGump( typeof( AquariumGump ) );
  
  			InvalidateProperties();
  
  			if ( takeItem )
  				from.PlaySound( 0x42 );
  
  			return takeItem;
  		}
  
  		public override void DropItemsToGround()
  		{
  			Point3D loc = GetWorldLocation();
  
  			for ( int i = Items.Count - 1; i >= 0; i-- )
  			{
  				Item item = Items[ i ];
  
  				item.MoveToWorld( loc, Map );
  
  				if ( item is BaseFish )
  				{
  					BaseFish fish = (BaseFish) item;
  
  					if ( !fish.Dead )
  						fish.StartTimer();
  				}
  			}
  		}
  
  		public override bool CheckItemUse( Mobile from, Item item )
  		{
  			if ( item != this )
  				return false;
  
  			return base.CheckItemUse( from, item );
  		}
  
  		public override bool CheckLift( Mobile from, Item item, ref LRReason reject )
  		{
  			if ( item != this )
  			{
  				reject = LRReason.CannotLift;
  				return false;
  			}
  
  			return base.CheckLift( from, item, ref reject );
  		}
  
  		public override void AddNameProperties( ObjectPropertyList list )
  		{
  			base.AddNameProperties( list );
  
  			if ( m_VacationLeft > 0 )
  				list.Add( 1074430, m_VacationLeft.ToString() ); // Vacation days left: ~1_DAYS
  
  			if ( m_Events.Count > 0 )
  				list.Add( 1074426, m_Events.Count.ToString() ); // ~1_NUM~ event(s) to view!
  
  			if ( m_RewardAvailable )
  				list.Add( 1074362 ); // A reward is available!
  
  			list.Add( 1074247, "{0}\t{1}", m_LiveCreatures, MaxLiveCreatures ); // Live Creatures: ~1_NUM~ / ~2_MAX~
  
  			int dead = DeadCreatures;
  
  			if ( dead > 0 )
  				list.Add( 1074248, dead.ToString() ); // Dead Creatures: ~1_NUM~
  
  			int decorations = Items.Count - m_LiveCreatures - dead;
  
  			if ( decorations > 0 )
  				list.Add( 1074249, decorations.ToString() ); // Decorations: ~1_NUM~
  
  			list.Add( 1074250, "#{0}", FoodNumber() ); // Food state: ~1_STATE~
  			list.Add( 1074251, "#{0}", WaterNumber() ); // Water state: ~1_STATE~
  
  			if ( m_Food.State == (int) FoodState.Dead )
  				list.Add( 1074577, "{0}\t{1}", m_Food.Added, m_Food.Improve ); // Food Added: ~1_CUR~ Needed: ~2_NEED~
  			else if ( m_Food.State == (int) FoodState.Overfed )
  				list.Add( 1074577, "{0}\t{1}", m_Food.Added, m_Food.Maintain ); // Food Added: ~1_CUR~ Needed: ~2_NEED~
  			else
  				list.Add( 1074253, "{0}\t{1}\t{2}", m_Food.Added, m_Food.Maintain, m_Food.Improve ); // Food Added: ~1_CUR~ Feed: ~2_NEED~ Improve: ~3_GROW~
  
  			if ( m_Water.State == (int) WaterState.Dead )
  				list.Add( 1074578, "{0}\t{1}", m_Water.Added, m_Water.Improve ); // Water Added: ~1_CUR~ Needed: ~2_NEED~
  			else if ( m_Water.State == (int) WaterState.Strong )
  				list.Add( 1074578, "{0}\t{1}", m_Water.Added, m_Water.Maintain ); // Water Added: ~1_CUR~ Needed: ~2_NEED~
  			else
  				list.Add( 1074254, "{0}\t{1}\t{2}", m_Water.Added, m_Water.Maintain, m_Water.Improve ); // Water Added: ~1_CUR~ Maintain: ~2_NEED~ Improve: ~3_GROW~
  		}
  
  		public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
  		{
  			base.GetContextMenuEntries( from, list );
  
  			if ( from.Alive )
  			{
  				list.Add( new ExamineEntry( this ) );
  
  				if ( HasAccess( from ) )
  				{
  					if ( m_RewardAvailable )
  						list.Add( new CollectRewardEntry( this ) );
  
  					if ( m_Events.Count > 0 )
  						list.Add( new ViewEventEntry( this ) );
  
  					if ( m_VacationLeft > 0 )
  						list.Add( new CancelVacationMode( this ) );
  				}
  			}
  
  			if ( from.AccessLevel >= AccessLevel.GameMaster )
  			{
  				list.Add( new GMAddFood( this ) );
  				list.Add( new GMAddWater( this ) );
  				list.Add( new GMForceEvaluate( this ) );
  				list.Add( new GMOpen( this ) );
  				list.Add( new GMFill( this ) );
  			}
  		}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize( writer );
  
  			writer.Write( 3 ); // Version
  
  			// version 1
  			if ( m_Timer != null )
  				writer.Write( m_Timer.Next );
  			else
  				writer.Write( DateTime.UtcNow + EvaluationInterval );
  
  			// version 0
  			writer.Write( (int) m_LiveCreatures );
  			writer.Write( (int) m_VacationLeft );
  
  			m_Food.Serialize( writer );
  			m_Water.Serialize( writer );
  
  			writer.Write( (int) m_Events.Count );
  
  			for ( int i = 0; i < m_Events.Count; i ++ )
  				writer.Write( (int) m_Events[ i ] );
  
  			writer.Write( (bool) m_RewardAvailable );
  		}
  
  		public override void Deserialize( GenericReader reader )
  		{
  			base.Deserialize( reader );
  
  			int version = reader.ReadInt();
  
  			switch ( version )
  			{
  				case 3:
  				case 2:
  				case 1:
  				{
  					DateTime next = reader.ReadDateTime();
  
  					if ( next < DateTime.UtcNow )
  						next = DateTime.UtcNow;
  
  					m_Timer = Timer.DelayCall( next - DateTime.UtcNow, EvaluationInterval, new TimerCallback( Evaluate ) );
  
  					goto case 0;
  				}
  				case 0:
  				{
  					m_LiveCreatures = reader.ReadInt();
  					m_VacationLeft = reader.ReadInt();
  
  					m_Food = new AquariumState();
  					m_Water = new AquariumState();
  
  					m_Food.Deserialize( reader );
  					m_Water.Deserialize( reader );
  
  					m_Events = new List<int>();
  
  					int count = reader.ReadInt();
  
  					for ( int i = 0; i < count; i ++ )
  
gt: 						m_Events.Add( reader.ReadInt() );