using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
using Server.Network;
using Server.Gumps;
using Server.Targeting;
using Server.ContextMenus;
using Server.Engines.PartySystem; //SOUTEZ LOVCU POKLADU

namespace Server.Items
{
	public class TreasureMap : MapItem
	{
		private int m_Level;
		private bool m_Completed;
		private Mobile m_CompletedBy;
		private Mobile m_Decoder;
		private Map m_Map;
		private Point2D m_Location;
		private int m_MessageIndex;

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

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

		[CommandProperty(AccessLevel.GameMaster)]
		public Mobile CompletedBy { get { return m_CompletedBy; } set { m_CompletedBy = value; InvalidateProperties(); } }

		[CommandProperty(AccessLevel.GameMaster)]
		public Mobile Decoder { get { return m_Decoder; } set { m_Decoder = value; InvalidateProperties(); } }

		[CommandProperty(AccessLevel.GameMaster)]
		public Map ChestMap { get { return m_Map; } set { m_Map = value; InvalidateProperties(); } }

		[CommandProperty(AccessLevel.GameMaster)]
		public Point2D ChestLocation { get { return m_Location; } set { m_Location = value; } }

		[CommandProperty(AccessLevel.GameMaster)]
		public Point2D Loc { get { return m_Location; } set { m_Location = value; } }

		private static Point2D[] m_Locations;
		private static Point2D[] m_HavenLocations;

		private static Type[][] m_SpawnTypes = new Type[][]
		{
			new Type[] { typeof(HeadlessOne), typeof(Skeleton) },
			new Type[] { typeof(Mongbat), typeof(Ratman), typeof(HeadlessOne), typeof(Skeleton), typeof(Zombie) },
			new Type[] { typeof(OrcishMage), typeof(Gargoyle), typeof(Gazer), typeof(HellHound), typeof(EarthElemental) },
			new Type[] { typeof(Lich), typeof(OgreLord), typeof(DreadSpider), typeof(AirElemental), typeof(FireElemental) },
			new Type[] { typeof(DreadSpider), typeof(LichLord), typeof(Daemon), typeof(ElderGazer), typeof(OgreLord) },
			new Type[] { typeof(LichLord), typeof(Moloch), typeof(ElderGazer), typeof(PoisonElemental), typeof(BloodElemental) },
			new Type[] { typeof(IceDragon), typeof(AncientWyrm), typeof(Balron), typeof(BloodElemental), typeof(PoisonElemental), typeof(Titan) },

			new Type[] { typeof(EnergyDragon), typeof(AncientWyrm), typeof(WalkingDead), typeof(Balron), typeof(AncientLich), typeof(Moloch), typeof(SpiderKing) },
			new Type[] { typeof(ToxicDragon), typeof(AncientWyrm), typeof(Balron), typeof(WalkingDead), typeof(Beholder), typeof(Moloch) },
			new Type[] { typeof(FireDragon), typeof(AncientWyrm), typeof(Moloch), typeof(BoneWarriorKnight), typeof(BlackLich), typeof(WalkingDead), typeof(MummyLord) }
		};

		public const double LootChance = 0.007; // 0,7% chance to appear as loot

		public static Point2D GetRandomLocation()
		{
			if (m_Locations == null)
				LoadLocations();

			if (m_Locations.Length > 0)
				return m_Locations[Utility.Random(m_Locations.Length)];

			return Point2D.Zero;
		}

		public static Point2D GetRandomHavenLocation()
		{
			if (m_HavenLocations == null)
				LoadLocations();

			if (m_HavenLocations.Length > 0)
				return m_HavenLocations[Utility.Random(m_HavenLocations.Length)];

			return Point2D.Zero;
		}

		private static void LoadLocations()
		{
			string filePath = Path.Combine(Core.BaseDirectory, "Data/treasure.cfg");

			ArrayList list = new ArrayList();
			ArrayList havenList = new ArrayList();

			if (File.Exists(filePath))
			{
				using (StreamReader ip = new StreamReader(filePath))
				{
					string line;

					while ((line = ip.ReadLine()) != null)
					{
						try
						{
							string[] split = line.Split(' ');

							int x = Convert.ToInt32(split[0]), y = Convert.ToInt32(split[1]);

							Point2D loc = new Point2D(x, y);
							list.Add(loc);

							if (IsInHavenIsland(loc))
								havenList.Add(loc);
						}
						catch
						{
						}
					}
				}
			}

			m_Locations = (Point2D[])list.ToArray(typeof(Point2D));
			m_HavenLocations = (Point2D[])havenList.ToArray(typeof(Point2D));
		}

		public static bool IsInHavenIsland(IPoint2D loc)
		{
			return (loc.X >= 3314 && loc.X <= 3814 && loc.Y >= 2345 && loc.Y <= 3095);
		}

		public static BaseCreature Spawn(int level, Point3D p, bool guardian)
		{
			if (level >= 0 && level < m_SpawnTypes.Length)
			{
				BaseCreature bc;

				try
				{
					bc = (BaseCreature)Activator.CreateInstance(m_SpawnTypes[level][Utility.Random(m_SpawnTypes[level].Length)]);
				}
				catch
				{
					return null;
				}

				bc.Home = p;
				bc.RangeHome = 5;

				if (guardian && level == 0)
				{
					bc.Name = "a chest guardian";
					bc.Hue = 0x835;
				}

				return bc;
			}

			return null;
		}

		public static BaseCreature Spawn(int level, Point3D p, Map map, Mobile target, bool guardian, TreasureMapChest chest)
		{
			if (map == null)
				return null;

			BaseCreature c = Spawn(level, p, guardian);

			if (c != null)
			{
				bool spawned = false;

				for (int i = 0; !spawned && i < 10; ++i)
				{
					int x = p.X - 3 + Utility.Random(7);
					int y = p.Y - 3 + Utility.Random(7);

					if (map.CanSpawnMobile(x, y, p.Z))
					{
						c.MoveToWorld(new Point3D(x, y, p.Z), map);
						spawned = true;
					}
					else
					{
						int z = map.GetAverageZ(x, y);

						if (map.CanSpawnMobile(x, y, z))
						{
							c.MoveToWorld(new Point3D(x, y, z), map);
							spawned = true;
						}
					}
				}

				if (!spawned)
				{
					c.Delete();
					return null;
				}

				if (target != null)
					c.Combatant = target;

				if (chest != null)
					chest.SecondaryGuardians.Add(c);

					//     			if ( Paragon.CheckConvert( c, c.Location, map ) )
					//     				c.IsParagon = true;

				if (!(c is IceDragon) && !(c is EnergyDragon) && !(c is ToxicDragon) && !(c is FireDragon) && Teragon.CheckConvert(c, c.Location, map))
					c.IsTeragon = true;

				return c;
			}

			return null;
		}

		[Constructable]
		public TreasureMap(int level, Map map)
		{
			m_Level = level;
			m_Map = map;
			m_MessageIndex = Utility.Random(MessageEntry.Entries.Length);

			if (level == 0)
				m_Location = GetRandomHavenLocation();
			else
				m_Location = GetRandomLocation();

			Width = 300;
			Height = 300;

			int width = 600;
			int height = 600;

			int x1 = m_Location.X - Utility.RandomMinMax(width / 4, (width / 4) * 3);
			int y1 = m_Location.Y - Utility.RandomMinMax(height / 4, (height / 4) * 3);

			if (x1 < 0)
				x1 = 0;

			if (y1 < 0)
				y1 = 0;

			int x2 = x1 + width;
			int y2 = y1 + height;

			if (x2 >= 5120)
				x2 = 5119;

			if (y2 >= 4096)
				y2 = 4095;

			x1 = x2 - width;
			y1 = y2 - height;

			Bounds = new Rectangle2D(x1, y1, width, height);
			Protected = true;

			AddWorldPin(m_Location.X, m_Location.Y);
		}

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

		public static bool HasDiggingTool(Mobile m)
		{
			if (m.Backpack == null)
				return false;

			Item[] items = m.Backpack.FindItemsByType(typeof(BaseHarvestTool));

			foreach (BaseHarvestTool tool in items)
			{
				if (tool.HarvestSystem == Engines.Harvest.Mining.System)
					return true;
			}

			return false;
		}

		public void OnBeginDig(Mobile from)
		{
			if (m_Completed)
			{
				from.SendLocalizedMessage(503028); // The treasure for this map has already been found.
			}
			else if (!IsChildOf(from.Backpack))
			{
				from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it.
			}
			else if (m_Level == 0 && !CheckYoung(from))
			{
				from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map.
			}

			/*
			else if ( from != m_Decoder )
			{
				from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure.
			}
			else if ( m_Decoder != from && !HasRequiredSkill( from ) )
			{
				from.SendLocalizedMessage( 503031 ); // You did not decode this map and have no clue where to look for the treasure.
			}
			*/
			else if (!from.CanBeginAction(typeof(TreasureMap)))
			{
				from.SendLocalizedMessage(503020); // You are already digging treasure.
			}
			else if (from.Map != this.m_Map)
			{
				from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet!
			}
			else
			{
				from.SendLocalizedMessage(503033); // Where do you wish to dig?
				from.Target = new DigTarget(this);
			}
		}

		private class DigTarget : Target
		{
			private TreasureMap m_Map;

			public DigTarget(TreasureMap map) : base(6, true, TargetFlags.None)
			{
				m_Map = map;
			}

			protected override void OnTarget(Mobile from, object targeted)
			{
				if (m_Map.Deleted)
					return;

				Map map = m_Map.m_Map;

				if (m_Map.m_Completed)
				{
					from.SendLocalizedMessage(503028); // The treasure for this map has already been found.
				}
				else if (!(m_Map.IsChildOf(from.Backpack)))
				{
					from.SendLocalizedMessage(1042010); // You must have the object in your backpack to use it.
				}

				/*
				else if ( from != m_Map.m_Decoder )
				{
					from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure.
				}
				else if ( m_Map.m_Decoder != from && !m_Map.HasRequiredSkill( from ) )
				{
					from.SendLocalizedMessage( 503031 ); // You did not decode this map and have no clue where to look for the treasure.
					return;
				}
				*/
				else if (!from.CanBeginAction(typeof(TreasureMap)))
				{
					from.SendLocalizedMessage(503020); // You are already digging treasure.
				}
				else if (!HasDiggingTool(from))
				{
					from.SendMessage("Pokud chces kopat poklad musis u sebe mit naradi na kopani.");
				}
				else if (from.Map != map)
				{
					from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet!
				}
				else
				{
					IPoint3D p = targeted as IPoint3D;

					Point3D targ3D;
					if (p is Item)
						targ3D = ((Item)p).GetWorldLocation();
					else
						targ3D = new Point3D(p);

					int maxRange;
					double skillValue = from.Skills[SkillName.Mining].Value;

					if (skillValue >= 100.0)
						maxRange = 4;
					else if (skillValue >= 81.0)
						maxRange = 3;
					else if (skillValue >= 51.0)
						maxRange = 2;
					else
						maxRange = 1;

					Point2D loc = m_Map.m_Location;
					int x = loc.X, y = loc.Y;

					Point3D chest3D0 = new Point3D(loc, 0);

					if (Utility.InRange(targ3D, chest3D0, maxRange))
					{
						if (from.Location.X == x && from.Location.Y == y)
						{
							from.SendLocalizedMessage(503030); // The chest can't be dug up because you are standing on top of it.
						}
						else if (map != null)
						{
							int z = map.GetAverageZ(x, y);

							if (!map.CanFit(x, y, z, 16, true, true))
							{
								from.SendLocalizedMessage(503021); // You have found the treasure chest but something is keeping it from being dug up.
							}
							else if (from.BeginAction(typeof(TreasureMap)))
							{
								new DigTimer(from, m_Map, new Point3D(x, y, z), map).Start();
							}
							else
							{
								from.SendLocalizedMessage(503020); // You are already digging treasure.
							}
						}
					}

					// 					else if ( m_Map.Level > 0 )
					// 					{
					// 						if ( Utility.InRange( targ3D, chest3D0, 8 ) ) // We're close, but not quite
					// 						{
					// 							from.SendLocalizedMessage( 503032 ); // You dig and dig but no treasure seems to be here.
					// 						}
					// 						else
					// 						{
					// 							from.SendLocalizedMessage( 503035 ); // You dig and dig but fail to find any treasure.
					// 						}
					// 					}
					else
					{
						if (Utility.InRange(targ3D, chest3D0, 8)) // We're close, but not quite
						{
							from.SendAsciiMessage(0x44, "Truhla s pokladem je velmi blizko!");
						}
						else
						{
							Direction dir = Utility.GetDirection(targ3D, chest3D0);

							string sDir;
							switch (dir)
							{
								case Direction.North:	sDir = "severu"; break;
								case Direction.Right:	sDir = "severovychode"; break;
								case Direction.East:	sDir = "vychode"; break;
								case Direction.Down:	sDir = "jihovychode"; break;
								case Direction.South:	sDir = "jihu"; break;
								case Direction.Left:	sDir = "jihozapade"; break;
								case Direction.West:	sDir = "zapade"; break;
								default:				sDir = "severozapade"; break;
							}

							from.SendAsciiMessage(0x44, "Zkus poklad hledat vice na {0}.", sDir);
						}
					}
				}
			}
		}

		private class DigTimer : Timer
		{
			private Mobile m_From;
			private TreasureMap m_TreasureMap;

			private Point3D m_Location;
			private Map m_Map;

			private TreasureChestDirt m_Dirt1;
			private TreasureChestDirt m_Dirt2;
			private TreasureMapChest m_Chest;

			private int m_Count;

			private DateTime m_NextSkillTime;
			private DateTime m_NextSpellTime;
			private DateTime m_NextActionTime;
			private DateTime m_LastMoveTime;

			public DigTimer(Mobile from, TreasureMap treasureMap, Point3D location, Map map) : base(TimeSpan.Zero, TimeSpan.FromSeconds(1.0))
			{
				m_From = from;
				m_TreasureMap = treasureMap;

				m_Location = location;
				m_Map = map;

				m_NextSkillTime = from.NextSkillTime;
				m_NextSpellTime = from.NextSpellTime;
				m_NextActionTime = from.NextActionTime;
				m_LastMoveTime = from.LastMoveTime;

				Priority = TimerPriority.TenMS;
			}

			private void Terminate()
			{
				Stop();
				m_From.EndAction(typeof(TreasureMap));

				if (m_Chest != null)
					m_Chest.Delete();

				if (m_Dirt1 != null)
				{
					m_Dirt1.Delete();
					m_Dirt2.Delete();
				}
			}

			protected override void OnTick()
			{
				if (m_NextSkillTime != m_From.NextSkillTime || m_NextSpellTime != m_From.NextSpellTime || m_NextActionTime != m_From.NextActionTime)
				{
					Terminate();
					return;
				}

				if (m_LastMoveTime != m_From.LastMoveTime)
				{
					m_From.SendLocalizedMessage(503023); // You cannot move around while digging up treasure. You will need to start digging anew.
					Terminate();
					return;
				}

				int z = (m_Chest != null) ? m_Chest.Z + m_Chest.ItemData.Height : int.MinValue;
				int height = 16;

				if (z > m_Location.Z)
					height -= (z - m_Location.Z);
				else
					z = m_Location.Z;

				if (!m_Map.CanFit(m_Location.X, m_Location.Y, z, height, true, true, false))
				{
					m_From.SendLocalizedMessage(503024); // You stop digging because something is directly on top of the treasure chest.
					Terminate();
					return;
				}

				m_Count++;

				m_From.RevealingAction();
				m_From.Direction = m_From.GetDirectionTo(m_Location);

				if (m_Count > 1 && m_Dirt1 == null)
				{
					m_Dirt1 = new TreasureChestDirt();
					m_Dirt1.MoveToWorld(m_Location, m_Map);

					m_Dirt2 = new TreasureChestDirt();
					m_Dirt2.MoveToWorld(new Point3D(m_Location.X, m_Location.Y - 1, m_Location.Z), m_Map);
				}

				if (m_Count == 5)
				{
					m_Dirt1.Turn1();
				}
				else if (m_Count == 10)
				{
					m_Dirt1.Turn2();
					m_Dirt2.Turn2();
				}
				else if (m_Count > 10)
				{
					if (m_Chest == null)
					{
						m_Chest = new TreasureMapChest(m_From, m_TreasureMap.Level, true);
						m_Chest.MoveToWorld(new Point3D(m_Location.X, m_Location.Y, m_Location.Z - 15), m_Map);
					}
					else
					{
						m_Chest.Z++;
					}

					Effects.PlaySound(m_Chest, m_Map, 0x33B);
				}

				if (m_Chest != null && m_Chest.Location.Z >= m_Location.Z)
				{
					Stop();
					m_From.EndAction(typeof(TreasureMap));

					m_Chest.Temporary = false;
					m_TreasureMap.Completed = true;
					m_TreasureMap.CompletedBy = m_From;

					if (m_TreasureMap.Level > 6)
					{
						World.Broadcast(37, true, "{0} prave vykopal{1} poklad level {2}!", m_From.RawName, (m_From.Female) ? "a":"", m_TreasureMap.Level);
						Server.Commands.LogIt.WriteLine("Poklady", m_From, "{0} vykopal poklad level {1}", m_From.RawName, m_TreasureMap.Level);

						PlayerTitles.TitleProgress(m_From, "treasure", m_TreasureMap.Level - 6); //treasure hunter
					}

					//Guild Expy
					//SOUTEZ LOVCU POKLADU - START
               Party party = Party.Get(m_From);

					//         			int expy = ( m_TreasureMap.Level < 7 ) ? m_TreasureMap.Level : ( m_TreasureMap.Level * 2 );

					if (party != null)
					{
						foreach(PartyMemberInfo info in party.Members)
						{
							PlayerMobile pm = (PlayerMobile) info.Mobile;

							if (pm != null && pm.InRange(m_From.Location, 25))
							{
								//         						pm.Expy += expy;
								//         						pm.SendMessage( 0x35, "Do souteze lovcu pokladu ziskavas {0} bodu!", expy );
								Guilds.Guild.GiveXp(pm, m_TreasureMap.Level * 10);
							}
						}
					}
					else
					{
						if (m_From is PlayerMobile)
						{
							//         				   ((PlayerMobile)m_From).Expy += expy;
							//         					m_From.SendMessage( 0x35, "Do souteze lovcu pokladu ziskavas {0} bodu!", expy );
							Guilds.Guild.GiveXp(m_From, m_TreasureMap.Level * 10);
						}
					}

					//SOUTEZ LOVCU POKLADU - END

					int spawns;
					switch (m_TreasureMap.Level)
					{
						case 0: spawns = 3; break;
						case 1: spawns = 0; break;
						default: spawns = 4; break;
					}

					for (int i = 0; i < spawns; ++i)
					{
						BaseCreature bc = Spawn(m_TreasureMap.Level, m_Chest.Location, m_Chest.Map, null, true, null);

						if (bc != null)
							m_Chest.Guardians.Add(bc);
					}
				}
				else
				{
					if (m_From.Body.IsHuman && !m_From.Mounted)
						m_From.Animate(11, 5, 1, true, false, 0);

					new SoundTimer(m_From, 0x125 + (m_Count % 2)).Start();
				}
			}

			private class SoundTimer : Timer
			{
				private Mobile m_From;
				private int m_SoundID;

				public SoundTimer(Mobile from, int soundID) : base(TimeSpan.FromSeconds(0.9))
				{
					m_From = from;
					m_SoundID = soundID;

					Priority = TimerPriority.TenMS;
				}

				protected override void OnTick()
				{
					m_From.PlaySound(m_SoundID);
				}
			}
		}

		public override void OnDoubleClick(Mobile from)
		{
			MessageEntry entry;

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

			if (m_MessageIndex >= 0 && m_MessageIndex < MessageEntry.Entries.Length)
				entry = MessageEntry.Entries[m_MessageIndex];
			else
				entry = MessageEntry.Entries[m_MessageIndex = Utility.Random(MessageEntry.Entries.Length)];

			if (!m_Completed && m_Decoder == null)
				Decode(from);
			else
			{
				DisplayTo(from);
				// 				from.CloseGump( typeof( CartGump ) );
				// 				from.SendGump( new CartGump( this, entry, m_Map, m_Location ) );
			}

			if (from == null)
				return;
		}

		private bool CheckYoung(Mobile from)
		{
			if (from.AccessLevel >= AccessLevel.GameMaster)
				return true;

			if (from is PlayerMobile && ((PlayerMobile)from).Young)
				return true;

			if (from == this.Decoder)
			{
				this.Level = 1;
				from.SendLocalizedMessage(1046446); // This is now a level one treasure map.
				return true;
			}

			return false;
		}

		private double GetMinSkillLevel()
		{
			switch (m_Level)
			{
				case 1: return -3.0;
				case 2: return 41.0;
				case 3: return 51.0;
				case 4: return 61.0;
				case 5: return 70.0;
				case 6: return 70.0;
				case 7: return 80.0;
				case 8: return 90.0;
				case 9: return 100.0;

				default: return 0.0;
			}
		}

		private bool HasRequiredSkill(Mobile from)
		{
			return (from.Skills[SkillName.Cartography].Value >= GetMinSkillLevel());
		}

		public void Decode(Mobile from)
		{
			// 			MessageEntry entry;

			if (m_Completed || m_Decoder != null)
				return;

			if (m_Level == 0)
			{
				if (!CheckYoung(from))
				{
					from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map.
					return;
				}
			}
			else
			{
				double minSkill = GetMinSkillLevel();

				if (from.Skills[SkillName.Cartography].Value < minSkill)
					from.SendLocalizedMessage(503013); // The map is too difficult to attempt to decode.

				double maxSkill = minSkill + 60.0;

				if (!from.CheckSkill(SkillName.Cartography, minSkill, maxSkill))
				{
					from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503018); // You fail to make anything of the map.
					return;
				}
			}

			from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503019); // You successfully decode a treasure map!
			Decoder = from;

			// 			if ( m_MessageIndex >= 0 && m_MessageIndex < MessageEntry.Entries.Length )
			// 				entry = MessageEntry.Entries[m_MessageIndex];
			// 			else
			// 				entry = MessageEntry.Entries[m_MessageIndex = Utility.Random( MessageEntry.Entries.Length )];

			// 			from.CloseGump( typeof( CartGump ) );
			// 			from.SendGump( new CartGump( this, entry, m_Map, m_Location ) );
			DisplayTo(from);
		}

		public override void DisplayTo(Mobile from)
		{
			if (m_Completed)
			{
				SendLocalizedMessageTo(from, 503014); // This treasure hunt has already been completed.
			}
			else if (m_Level == 0 && !CheckYoung(from))
			{
				from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map.
				return;
			}

			/*
			else if ( m_Decoder != from && !HasRequiredSkill( from ) )
			{
				from.SendLocalizedMessage( 503031 ); // You did not decode this map and have no clue where to look for the treasure.
				return;
			}
			*/
			else
			{
				SendLocalizedMessageTo(from, 503017); // The treasure is marked by the red pin. Grab a shovel and go dig it up!
			}

			from.PlaySound(0x249);
			base.DisplayTo(from);
		}

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

			if (!m_Completed)
			{
				if (m_Decoder == null)
				{
					list.Add(new DecodeMapEntry(this));
				}
				else
				{
					bool digTool = HasDiggingTool(from);

					list.Add(new OpenMapEntry(this));
					list.Add(new DigEntry(this, digTool));
				}
			}
		}

		private class DecodeMapEntry : ContextMenuEntry
		{
			private TreasureMap m_Map;

			public DecodeMapEntry(TreasureMap map) : base(6147, 2)
			{
				m_Map = map;
			}

			public override void OnClick()
			{
				if (!m_Map.Deleted)
					m_Map.Decode(Owner.From);
			}
		}

		private class OpenMapEntry : ContextMenuEntry
		{
			private TreasureMap m_Map;

			public OpenMapEntry(TreasureMap map) : base(6150, 2)
			{
				m_Map = map;
			}

			public override void OnClick()
			{
				if (!m_Map.Deleted)
					m_Map.DisplayTo(Owner.From);
			}
		}

		private class DigEntry : ContextMenuEntry
		{
			private TreasureMap m_Map;

			public DigEntry(TreasureMap map, bool enabled) : base(6148, 2)
			{
				m_Map = map;

				if (!enabled)
					this.Flags |= CMEFlags.Disabled;
			}

			public override void OnClick()
			{
				if (m_Map.Deleted)
					return;

				Mobile from = Owner.From;

				if (HasDiggingTool(from))
					m_Map.OnBeginDig(from);
				else
					from.SendMessage("Pokud chces kopat poklad musis u sebe mit naradi na kopani.");
			}
		}

		public override int LabelNumber
		{
			get
			{
				if (m_Decoder != null)
				{
					if (m_Level == 6)
						return 1063453;
					else
						return 1041516 + m_Level;
				}
				else if (m_Level == 6)
					return 1063452;
				else
					return 1041510 + m_Level;
			}
		}

		public override void GetProperties(ObjectPropertyList list)
		{
			base.GetProperties(list);

			list.Add(m_Map == Map.Felucca ? 1041502 : 1041503); // for somewhere in Felucca : for somewhere in Trammel

			if (m_Completed)
			{
				list.Add(1041507, m_CompletedBy == null ? "someone" : m_CompletedBy.Name); // completed by ~1_val~
			}
		}

		public override void OnSingleClick(Mobile from)
		{
			if (m_Completed)
			{
				from.Send(new MessageLocalizedAffix(Serial, ItemID, MessageType.Label, 0x3B2, 3, 1048030, "", AffixType.Append, String.Format(" completed by {0}", m_CompletedBy == null ? "someone" : m_CompletedBy.Name), ""));
			}
			else if (m_Decoder != null)
			{
				if (m_Level == 6)
					LabelTo(from, 1063453);
				else
					LabelTo(from, 1041516 + m_Level);
			}
			else
			{
				if (m_Level == 6)
					LabelTo(from, 1041522, String.Format("#{0}\t \t#{1}", 1063452, m_Map == Map.Felucca ? 1041502 : 1041503));
				else
					LabelTo(from, 1041522, String.Format("#{0}\t \t#{1}", 1041510 + m_Level, m_Map == Map.Felucca ? 1041502 : 1041503));
			}
		}

		// 		private class CartGump : Gump
		// 		{
		// 			public TreasureMap Tmap = null;
		// 			public int xc{ get{ if( Tmap != null ) return Tmap.Loc.X; else return 0; } }
		// 			public int yc{ get{ if( Tmap != null ) return Tmap.Loc.Y; else return 0; } }
		// 
		// 			public CartGump( TreasureMap tmap, MessageEntry entry, Map map, Point2D loc ) : base( (640 - entry.Width) / 2, (480 - entry.Height) / 2 )
		// 			{
		// 				string fmtx;
		// 				string fmty;
		// 				Tmap = tmap;
		// 
		// 				fmtx = String.Format( xc.ToString() );
		// 				fmty = String.Format( yc.ToString() );
		// 
		// 				AddPage( 0 );
		// 				AddBackground( 0, 0, entry.Width, entry.Height, 2520 );
		// 				AddHtml( 38, 38, entry.Width - 83, entry.Height - 86, String.Format( "From what you can tell, the location of the treasure is at these coordinates." ), false, false );
		// 				AddHtml( 30, 120, 120, 30, fmtx, false, false );
		// 				AddHtml( 90, 120, 120, 90, fmty, false, false );
		// 			}
		// 		}

		private class CartGump : Gump
		{
			public TreasureMap Tmap = null;
			public int xc { get { if(Tmap != null) return Tmap.Loc.X;					else return 0; } }
			public int yc { get { if(Tmap != null) return Tmap.Loc.Y;					else return 0; } }

			public CartGump(TreasureMap tmap, MessageEntry entry, Map map, Point2D loc) : base(250, 150)
			{
				string fmtx;
				string fmty;
				Tmap = tmap;

				fmtx = String.Format("X: {0}", xc.ToString());
				fmty = String.Format("Y: {0}", yc.ToString());

				this.Closable = true;
				this.Disposable = true;
				this.Dragable = true;
				this.Resizable = false;
				this.AddPage(0);
				this.AddImage(4, 4, 39);
				this.AddLabel(77, 36, 1844, @"Mapa pokladu");
				this.AddHtml(77, 60, 124, 30, "Level " + Tmap.Level, (bool)false, (bool)false);
				this.AddHtml(33, 95, 195, 80, @"Na teto mape vidis presne napsane souradnice umisteni pokladu.", (bool)false, (bool)false);
				this.AddHtml(33, 190, 74, 30, fmtx, (bool)false, (bool)false);
				this.AddHtml(33, 210, 74, 30, fmty, (bool)false, (bool)false);
				this.AddHtml(33, 233, 74, 30, String.Format("{0}", Tmap.ChestMap), (bool)false, (bool)false);
				this.AddItem(20, 33, 5355);
				this.AddItem(110, 207, 6988);
				this.AddItem(132, 193, 6989);
				this.AddItem(134, 220, 6990);
				this.AddItem(157, 242, 6991);
				this.AddItem(156, 198, 6993);
				this.AddItem(179, 226, 6992);
				this.AddItem(180, 219, 3648);
			}
		}

		private class MessageEntry
		{
			private int m_Width, m_Height;
			private string m_Message;

			public int Width { get { return m_Width; } }
			public int Height { get { return m_Height; } }
			public string Message { get { return m_Message; } }

			public MessageEntry(int width, int height, string message)
			{
				m_Width = width;
				m_Height = height;
				m_Message = message;
			}

			private static MessageEntry[] m_Entries = new MessageEntry[]
			{
				new MessageEntry(280, 180, "The treasure map is hard to make out, but with some luck and a lot of work, the red 'X' is finally discovered.")
			};

			public static MessageEntry[] Entries
			{
				get { return m_Entries; }
			}
		}

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

			writer.Write((int) 1);

			writer.Write((Mobile) m_CompletedBy);

			writer.Write(m_Level);
			writer.Write(m_Completed);
			writer.Write(m_Decoder);
			writer.Write(m_Map);
			writer.Write(m_Location);
		}

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

			int version = reader.ReadInt();

			switch (version)
			{
				case 1:
				{
					m_CompletedBy = reader.ReadMobile();

					goto case 0;
				}

				case 0:
				{
					m_Level = (int)reader.ReadInt();
					m_Completed = reader.ReadBool();
					m_Decoder = reader.ReadMobile();
					m_Map = reader.ReadMap();
					m_Location = reader.ReadPoint2D();

					if (version == 0 && m_Completed)
						m_CompletedBy = m_Decoder;

					break;
				}
			}
		}
	}

	public class TreasureChestDirt : Item
	{
		public TreasureChestDirt() : base(0x912)
		{
			Movable = false;

			Timer.DelayCall(TimeSpan.FromMinutes(2.0), new TimerCallback(Delete));
		}

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

		public void Turn1()
		{
			this.ItemID = 0x913;
		}

		public void Turn2()
		{
			this.ItemID = 0x914;
		}

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

			writer.WriteEncodedInt(0); // version
		}

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

			int version = reader.ReadEncodedInt();

			Delete();
		}
	}
}