using System;
using System.Collections;
using Server;
using Server.Items;
using Server.Engines.CannedEvil;
using System.Collections.Generic;

namespace Server.Mobiles
{
	public enum ChampDrop
	{
		Gold,
		DragonDust,
		HiryuDust,
		SpiderDust,
		DemonDust
	}
	
	public abstract class BaseChampion : BaseCreature
	{
		private bool m_IsChampion;
		private int m_Range, m_DropMin, m_DropMax, m_BonusLootAmount;
 		private string m_BonusLoot;
		private ChampDrop m_DropType;

		[CommandProperty(AccessLevel.GameMaster)]
		public ChampDrop DropType { get { return m_DropType; } set { m_DropType = value; } }
		
		[CommandProperty(AccessLevel.GameMaster)]
		public bool IsChampion
		{
			get { return m_IsChampion; }
			set
			{
				m_IsChampion = value;
				if ( !m_IsChampion && Blessed )
				{
					Blessed = false;
					
               if ( m_Timer != null )
      			{
      				m_Timer.Stop();
      				m_Timer = null;
      			}
            }
			}
		}
		
		[CommandProperty(AccessLevel.GameMaster)]
		public int Range
		{
			get { return m_Range; }
			set
			{
				m_Range = value;
				m_Range = ( m_Range < 1 ) ? 1 : ( ( m_Range > 20 ) ? 20 : m_Range );
			}
		}
		
		[CommandProperty(AccessLevel.GameMaster)]
		public int DropMin
		{
			get { return m_DropMin; }
			set
			{
				m_DropMin = value;
				m_DropMin = ( m_DropMin < 1 ) ? 1 : ( ( m_DropMin > 60000 ) ? 60000 : m_DropMin );
				if ( m_DropMin > m_DropMax ) m_DropMin = DropMax;
			}
		}
		
		[CommandProperty(AccessLevel.GameMaster)]
		public int DropMax
		{
			get { return m_DropMax; }
			set
			{
				m_DropMax = value;
				m_DropMax = ( m_DropMax < 1 ) ? 1 : ( ( m_DropMax > 60000 ) ? 60000 : m_DropMax );
				if ( m_DropMax < m_DropMin ) DropMax = m_DropMin;
			}
		}
		
		[CommandProperty( AccessLevel.GameMaster )]
		public String BonusLoot
		{
			get { return m_BonusLoot; }
			set
			{
				string str = value;

				if ( str != null )
				{
					str = str.ToLower();
					str = str.Trim();

					Type type = SpawnerType.GetType( str );

					if ( type != null )
						m_BonusLoot = str;
					else
						m_BonusLoot = null;//"-invalid-";
				}
				else
					m_BonusLoot = null;
			}
		}
		
		[CommandProperty(AccessLevel.GameMaster)]
		public int BonusLootAmount
		{
			get { return m_BonusLootAmount; }
			set
			{
				m_BonusLootAmount = value;
				m_BonusLootAmount = ( m_BonusLootAmount < 1 ) ? 1 : ( ( m_BonusLootAmount > 60000 ) ? 60000 : m_BonusLootAmount );
			}
		}
		
		public BaseChampion( AIType aiType ) : this( aiType, FightMode.Closest, true, 12 )
		{
		}

		public BaseChampion( AIType aiType, FightMode mode, bool ischampion, int range ) : base( aiType, mode, 18, 1, 0.1, 0.2 )
		{
			m_IsChampion = ischampion;
			m_Range = range;
			m_DropType = ChampDrop.Gold;
			m_DropMin = 75;
			m_DropMax = 300;
			
			m_BonusLoot = null;
			m_BonusLootAmount = 1;
			
			if ( m_Timer != null )
			{
				m_Timer.Stop();
				m_Timer = null;
			}

			if ( m_IsChampion )
			{
				this.Blessed = true;
				m_Timer = new BaseChampionTimer( this );
				m_Timer.Start();
			}
		}

		private Timer m_Timer;

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

		public abstract ChampionSkullType SkullType{ get; }

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

			writer.Write( (int) 2 ); // version
			
			writer.Write( m_BonusLoot );
			writer.Write( m_BonusLootAmount );
			
			writer.Write( m_IsChampion );
			writer.Write( m_Range );
			writer.Write( m_DropMin );
			writer.Write( m_DropMax );
			writer.Write( (int) m_DropType );
		}

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

			int version = reader.ReadInt();
			
			switch( version )
			{
				case 2:
					{
						m_BonusLoot = reader.ReadString();
						m_BonusLootAmount = reader.ReadInt();
						goto case 1;
					}
            case 1:
					{
						m_IsChampion = reader.ReadBool();
						m_Range = reader.ReadInt();
						m_DropMin = reader.ReadInt();
						m_DropMax = reader.ReadInt();
						m_DropType = (ChampDrop)reader.ReadInt();
						goto case 0;
					}
				case 0:
					{
						if ( version < 1 )
						{
							m_IsChampion = false;
							m_Range = 12;
							m_DropMin = 75;
							m_DropMax = 300;
							m_DropType = ChampDrop.Gold;
						}
						
						if ( version < 2 )
						{
							m_BonusLoot = null;
							m_BonusLootAmount = 1;
						}
						break;
					}
			}
		}
		
		public override bool IsNotScaredOfDeath{ get{ return true; } } //neutika pri malem poctu hp
		public override bool BardImmune{ get{ return true; } }
		
		public override void OnAfterDelete()
		{
			if ( m_Timer != null )
				m_Timer.Stop();
			
			m_Timer = null;
			
			base.OnAfterDelete();
		}
		
		private PowerScroll CreateRandomPowerScroll()
		{
			int level;
			double random = Utility.RandomDouble();

			if ( 0.1 >= random )
				level = 20;
			else if ( 0.4 >= random )
				level = 15;
			else
				level = 10;

			return PowerScroll.CreateRandomNoCraft( level, level );
		}
		
		private LevelUpScroll CreateRandomLevelUpScroll()
		{
			int level;
			double random = Utility.RandomDouble();

			if (0.1 >= random)
				level = 20;
			else if (0.4 >= random)
				level = 15;
			else if (0.7 >= random)
				level = 10;
			else
				level = 5;

			return new LevelUpScroll(level);
		}

		public void GivePowerScrolls()
		{
			// 			if ( Map != Map.Felucca )
			// 				return;

			ArrayList toGive = new ArrayList();
			List<DamageStore> rights = BaseCreature.GetLootingRights( this.DamageEntries, this.HitsMax );

			for ( int i = 0; i < rights.Count; ++i )
			{
				DamageStore ds = rights[i];

				if ( ds.m_HasRight )
					toGive.Add( ds.m_Mobile );
			}

			if ( toGive.Count == 0 )
				return;

    		if ( m_IsChampion )
    		{
            for( int i = 0; i < toGive.Count; i++ )
    			{
    				Mobile m = (Mobile)toGive[i];
    
    				if( !(m is PlayerMobile) )
    					continue;
    
    				bool gainedPath = false;
    
    				int pointsToGain = 800;
    
    				if( VirtueHelper.Award( m, VirtueName.Valor, pointsToGain, ref gainedPath ) )
    				{
    					if( gainedPath )
    						m.SendLocalizedMessage( 1054032 ); // You have gained a path in Valor!
    					else
    						m.SendLocalizedMessage( 1054030 ); // You have gained in Valor!
    
    					//No delay on Valor gains
    				}
    			}
    		}

			// Randomize
			for ( int i = 0; i < toGive.Count; ++i )
			{
				int rand = Utility.Random( toGive.Count );
				object hold = toGive[i];
				toGive[i] = toGive[rand];
				toGive[rand] = hold;
			}
			
			int psNumber = ( toGive.Count < 6 ) ? toGive.Count : ( m_IsChampion ) ? 6 : toGive.Count;
			
			for ( int i = 0; i < psNumber; ++i )
			{
				Mobile m = (Mobile)toGive[i % toGive.Count];
				
				if ( this is AncientSmithy && m_IsChampion )
				{
					m.SendLocalizedMessage( 1049524 ); // You have received a scroll of power!
					
               LevelUpScroll psu = CreateRandomLevelUpScroll();
					
					if ( m.Alive )
						m.AddToBackpack( psu );
					else
					{
						if ( m.Corpse != null && !m.Corpse.Deleted )
							((Container)m.Corpse).DropItem( psu );
						else
							m.AddToBackpack( psu );
					}
				}
				else if ( m_BonusLoot != null )
				{
               Type type = SpawnerType.GetType( m_BonusLoot );
               
               if ( type == null )
                  return;
               
               try
               {
                  Item bonusloot = (Item)Activator.CreateInstance( type );
                   
                  if ( bonusloot == null )
                     return;
                   
                  if ( m_BonusLootAmount > 1 && bonusloot.Stackable )
                      bonusloot.Amount = m_BonusLootAmount;
                   
    					if ( m.Alive )
    						m.AddToBackpack( bonusloot );
    					else
    					{
    						if ( m.Corpse != null && !m.Corpse.Deleted )
    							((Container)m.Corpse).DropItem( bonusloot );
    						else
    							m.AddToBackpack( bonusloot );
    					}
                   
                  m.SendMessage( 696, "Ziskavas {0} za zabiti {1}", ( bonusloot.Name == null ) ? "odmenu" : bonusloot.Name, this.Name );
               }
               catch
               {
                  m_BonusLoot = null;
                  Console.WriteLine( "BonusLoot: {0} - spatne nastaven", Server.Commands.CommandLogging.Format( this ) );
               }
            }
				else if ( m_IsChampion )
				{
					m.SendLocalizedMessage( 1049524 ); // You have received a scroll of power!
               
               PowerScroll ps = CreateRandomPowerScroll();
					
					if ( m.Alive )
						m.AddToBackpack( ps );
					else
					{
						if ( m.Corpse != null && !m.Corpse.Deleted )
							((Container)m.Corpse).DropItem( ps );
						else
							m.AddToBackpack( ps );
					}
				}

				
				if ( m is PlayerMobile && m_IsChampion )
				{
					PlayerMobile pm = (PlayerMobile)m;

					for ( int j = 0; j < pm.JusticeProtectors.Count; ++j )
					{
						Mobile prot = (Mobile)pm.JusticeProtectors[j];

						if ( prot.Map != m.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion( m, prot ) || toGive.Contains( prot ) )
							continue;

						int chance = 0;

						switch ( VirtueHelper.GetLevel( prot, VirtueName.Justice ) )
						{
								case VirtueLevel.Seeker: chance = 60; break;
								case VirtueLevel.Follower: chance = 75; break;
								case VirtueLevel.Knight: chance = 100; break;
						}

						if ( chance >= Utility.Random( 100 ) )
						{
							prot.SendLocalizedMessage( 1049368 ); // You have been rewarded for your dedication to Justice!
							
							if ( this is AncientSmithy )
							{
								LevelUpScroll psu2 = CreateRandomLevelUpScroll();
								
								if ( prot.Alive )
									prot.AddToBackpack( psu2 );
								else
								{
									if ( prot.Corpse != null && !prot.Corpse.Deleted )
										((Container)prot.Corpse).DropItem( psu2 );
									else
										prot.AddToBackpack( psu2 );
								}
							}
							else
							{
								PowerScroll ps2 = CreateRandomPowerScroll();
								
								if ( prot.Alive )
									prot.AddToBackpack( ps2 );
								else
								{
									if ( prot.Corpse != null && !prot.Corpse.Deleted )
										((Container)prot.Corpse).DropItem( ps2 );
									else
										prot.AddToBackpack( ps2 );
								}
							}
						}
					}
				}
			}
		}

		public override bool OnBeforeDeath()
		{
			if ( !NoKillAwards )
			{
				if ( m_IsChampion || m_BonusLoot != null )
            GivePowerScrolls();

				Map map = this.Map;
				int minusrang = (0- m_Range);

				if ( map != null )
				{
					for ( int x = minusrang; x <= m_Range; ++x )
					{
						for ( int y = minusrang; y <= m_Range; ++y )
						{
							double dist = Math.Sqrt(x*x+y*y);

							if ( dist <= m_Range )
								new GoodiesTimer( map, X + x, Y + y, m_DropType, m_DropMin, m_DropMax ).Start();
						}
					}
				}
			}

			return base.OnBeforeDeath();
		}

		public override void OnDeath( Container c )
		{
			List<DamageStore> rights = BaseCreature.GetLootingRights( this.DamageEntries, this.HitsMax );
			List<Mobile> toGive = new List<Mobile>();
         
			for ( int i = rights.Count - 1; i >= 0; --i )
			{
				DamageStore ds = rights[i];

				if ( ds.m_HasRight )
					toGive.Add( ds.m_Mobile );
			}
         
         if ( m_IsChampion && !( this is AncientSmithy ) )
			{
				if ( toGive.Count > 0 )
					toGive[Utility.Random( toGive.Count )].AddToBackpack( new ChampionSkull( SkullType ) );
				else
					c.DropItem( new ChampionSkull( SkullType ) );
			}
			
         for( int i = 0; i < toGive.Count; i++ )
  			{
  				Mobile m = (Mobile)toGive[i];
  
  				if( !(m is PlayerMobile) )
  					continue;
  
  				Guilds.Guild.GiveXp( m, ( m_BonusLoot != null ) ? Math.Min( 1000, Math.Max( 100, this.HitsMax / 100 ) ) : 50 );
  			}

			base.OnDeath( c );
		}

		private class GoodiesTimer : Timer
		{
			private Map m_Map;
			private int m_X, m_Y;
			private ChampDrop m_Drop;
			private int m_Min, m_Max;

			public GoodiesTimer( Map map, int x, int y, ChampDrop droptype, int min, int max ) : base( TimeSpan.FromSeconds( Utility.RandomDouble() * 10.0 ) )
			{
				m_Map = map;
				m_X = x;
				m_Y = y;
				m_Drop = droptype;
				m_Min = min;
				m_Max = max;
			}

			protected override void OnTick()
			{
				int z = m_Map.GetAverageZ( m_X, m_Y );
				bool canFit = m_Map.CanFit( m_X, m_Y, z, 6, false, false );

				for ( int i = -3; !canFit && i <= 3; ++i )
				{
					canFit = m_Map.CanFit( m_X, m_Y, z + i, 6, false, false );

					if ( canFit )
						z += i;
				}

				if ( !canFit )
					return;
				
				Item g = null;
				
				switch( m_Drop )
				{
					case ChampDrop.Gold:
						{
							Gold gl = new Gold( m_Min, m_Max );
							gl.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map );
							g = (Item) gl;
							break;
						}
					case ChampDrop.DragonDust:
						{
							Xanthos.Evo.RaelisDragonDust d = new Xanthos.Evo.RaelisDragonDust( Utility.RandomMinMax( m_Min, m_Max ) );
							d.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map );
							g = (Item) d;
							break;
						}
					case ChampDrop.HiryuDust:
						{
							Xanthos.Evo.HiryuEvoDust h = new Xanthos.Evo.HiryuEvoDust( Utility.RandomMinMax( m_Min, m_Max ) );
							h.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map );
							g = (Item) h;
							break;
						}
					case ChampDrop.SpiderDust:
						{
							Xanthos.Evo.EvoSpiderDust s = new Xanthos.Evo.EvoSpiderDust( Utility.RandomMinMax( m_Min, m_Max ) );
							s.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map );
							g = (Item) s;
							break;
						}
					case ChampDrop.DemonDust:
						{
							Xanthos.Evo.RaelisDemonioDust dm = new Xanthos.Evo.RaelisDemonioDust( Utility.RandomMinMax( m_Min, m_Max ) );
							dm.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map );
							g = (Item) dm;
							break;
						}
				}

				if ( g == null )
					return;
				
				if ( 0.5 >= Utility.RandomDouble() )
				{
					switch ( Utility.Random( 3 ) )
					{
						case 0: // Fire column
							{
								Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x3709, 10, 30, 5052 );
								Effects.PlaySound( g, g.Map, 0x208 );

								break;
							}
						case 1: // Explosion
							{
								Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x36BD, 20, 10, 5044 );
								Effects.PlaySound( g, g.Map, 0x307 );

								break;
							}
						case 2: // Ball of fire
							{
								Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x36FE, 10, 10, 5052 );

								break;
							}
					}
				}
			}
		}
	}
	
	public class BaseChampionTimer : Timer
	{
		private Mobile m_Champion;

		public BaseChampionTimer( Mobile champ ) : base( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.0 ) )
		{
			m_Champion = champ;
			Priority = TimerPriority.FiveSeconds;
		}

		protected override void OnTick()
		{
			m_Champion.Blessed = false;
			this.Stop();
		}
	}
}
