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

namespace Server.Spells.Spellweaving
{
	public class ArcaneCircleSpell : ArcanistSpell
	{
		private static SpellInfo m_Info = new SpellInfo(
				"Arcane Circle", "Myrshalee",
				SpellCircle.First, //0.5s
				-1
			);

        public override double RequiredSkill { get { return 0.0; } }
        public override int RequiredMana { get { return 24; } }

        public ArcaneCircleSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
		{
		}

        public override bool CheckCast()
        {
            if( !IsValidLocation( Caster.Location, Caster.Map ) )
            {
                Caster.SendLocalizedMessage( 1072705 ); // You must be standing on an arcane circle, pentagram or abbatoir to use this spell.
                return false;
            }

            return base.CheckCast();
        }

        public override void OnCast()
        {
            if( CheckSequence() )
            {				
                Caster.FixedParticles( 0x3779, 10, 20, 0x0, EffectLayer.Waist );
                Caster.PlaySound( 0x5C0 );

                /* Tested in Osi.
                 * 
                 * Test values:
                 * 
                 *  20.0 =  3600 secs.
                 *  30.0 =  3600 secs.
                 *  40.0 =  3600 secs.
                 *  47.9 =  3600 secs.
                 *  48.0 =  7200 secs.
                 *  50.0 =  7200 secs.
                 *  60.0 =  7200 secs.
                 *  70.0 =  7200 secs.
                 *  71.9 =  7200 secs.
                 *  72.0 = 10800 secs.
                 *  80.0 = 10800 secs.
                 *  90.0 = 10800 secs.
                 *  95.9 = 10800 secs.
                 *  96.0 = 14400 secs.
                 * 100.0 = 14400 secs.
                 * 110.0 = 14400 secs.
                 * 119.9 = 14400 secs.
                 * 120.0 = 18000 secs.
                 * 
                 * Finally:
                 * 
                 *   0.0 -  47.9 :  3600s -----
                 *  48.0 -  72.9 :  7200s (+48)
                 *  72.0 -  95.9 : 10800s (+24)
                 *  96.0 - 119.9 : 14400s (+24)
                 * 120.0 - 120.0 : 18000s (+24)
                 */
                List<Mobile> Arcanists = GetArcanists();

				int duration = Math.Max( 1, (int)( Math.Floor( Caster.Skills[SkillName.Spellweaving].Value / 24 ) ) ) * 3600; // Floor( Skill / 24 ) * 3600, Min 1
                int maxLevel = IsSanctuary( Caster.Location, Caster.Map ) ? 6 : 5;
                
                int level = Math.Min( Arcanists.Count, maxLevel );

                for( int i = 0; i < Arcanists.Count; i++ )
                    GiveArcaneFocus( Arcanists[i], duration, level );
            }

            FinishSequence();
        }

        private static bool IsSanctuary( Point3D p, Map m )
        {
			return ( m == Map.Trammel || m == Map.Felucca ) && p.X == 6267 && p.Y == 131 && p.Z == 5;
        }

        private static bool IsValidLocation( Point3D location, Map map )
        {
            Tile lt = map.Tiles.GetLandTile( location.X, location.Y );         // Land Tiles            
            
            if( IsValidTile( lt.ID ) && lt.Z == location.Z )
                return true;

            Tile[] tiles = map.Tiles.GetStaticTiles( location.X, location.Y ); // Static Tiles

            for( int i = 0; i < tiles.Length; ++i )
            {
                Tile t = tiles[i];
                ItemData id = TileData.ItemTable[t.ID & 0x3FFF];

                int tand = t.ID & 0x3FFF;

                if( t.Z != location.Z )
                    continue;
                else if( IsValidTile( tand ) )
                    return true;
            }

            IPooledEnumerable eable = map.GetItemsInRange( location, 0 );      // Added Tiles

            foreach( Item item in eable )
            {
                if( item == null || item.Z != location.Z )
                    continue;
                else if( IsValidTile( item.ItemID ) )
                {
                    eable.Free();
                    return true;
                }
            }

            eable.Free();
            return false;
        }

        public static bool IsValidTile( int itemID )
        {
            /*
             * 0xFEA  // pentagram midpoint
             * 0x1216 // abbatoir midpoint
             * 0x307F // arcane circle midpoint
             */
            return itemID == 0xFEA || itemID == 0x1216 || itemID == 0x307F;
        }

        private List<Mobile> GetArcanists()
        {
            List<Mobile> weavers = new List<Mobile>();

            weavers.Add( Caster );

			double mySkill = Caster.Skills[SkillName.Spellweaving].Value;

            foreach( Mobile m in Caster.GetMobilesInRange( 1 ) )
            {
				if( m.Player && m.Alive && !SpellHelper.ValidIndirectTarget( Caster, m ) )
                {					
					double hisSkill = m.Skills[SkillName.Spellweaving].Value;

					if( hisSkill >= mySkill - 20 &&
						hisSkill <= mySkill + 20  )
                    {
                        weavers.Add( m );
                    }
                }

                /* Everyone gets the Arcane Focus, but it's power is capped at 5 elsewhere.

                if( weavers.Count >= 5 )
                    break;                 
                 */
            }

            return weavers;
        }

        private void GiveArcaneFocus( Mobile to, int duration, int level )
        {
            if( to == null || to.Deleted || to.Backpack == null || to.Backpack.Deleted )
                return;

            to.SendLocalizedMessage( 1072516, String.Format( "{0}\t{1}", "#1032629", duration.ToString() ) ); // ~1_name~ will expire in ~2_val~ seconds!
            
  				DupresShield shield = null;
  				
  				if ( to.FindItemOnLayer( Layer.TwoHanded ) is DupresShield )
  				  shield = ( DupresShield ) to.FindItemOnLayer( Layer.TwoHanded );
  				  
             if ( shield != null && shield.Bonus > 4 )
               level += 2;

			ArcaneFocus focus = GetFocus( to );

			if( focus == null )
			{
				to.SendLocalizedMessage( 1072740 ); // An arcane focus appears in your backpack.
				to.AddToBackpack( new ArcaneFocus( duration, level, to ) );
			}
			else
			{
				to.SendLocalizedMessage( 1072828 ); // Your arcane focus is renewed.
							
				focus.LifeSpan = duration;
				focus.Level = level;
				focus.InvalidateProperties();
			}
        }
	}
}