using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Verse;
using RimWorld;


namespace Verse.AI{

public class JobDriver_Wait : JobDriver
{
	//Constants
	private const int TargetSearchInterval = 4;

	public override string GetReport()
	{
		if( CurJob.def == JobDefOf.WaitCombat )
		{
			// special case for when the pawn is incapable of violence,
			// so we don't say he's watching for targets
			if( pawn.RaceProps.Humanlike && pawn.story.WorkTagIsDisabled(WorkTags.Violent) )
				return "ReportStanding".Translate();
			else
				return base.GetReport();
		}

		return base.GetReport();
	}

	protected override IEnumerable<Toil> MakeNewToils()
	{
		Toil wait = new Toil();
		wait.initAction = ()=>
		{
			Find.PawnDestinationManager.ReserveDestinationFor(pawn, pawn.Position);
			pawn.pather.StopDead();

			//On init to stop 1-2 frame flickers out of cooldown/warmup stances
			CheckForAutoAttack(); 
		};
		wait.tickAction = ()=>
		{
			//Bug catcher
			if( CurJob.expiryInterval == -1 && CurJob.def == JobDefOf.WaitCombat && !pawn.Drafted )
			{
				Log.Error(pawn + " in eternal WaitCombat without being drafted.");
				ReadyForNextToil();
				return;
			}

			if( (Find.TickManager.TicksGame + pawn.thingIDNumber) % TargetSearchInterval == 0 )
				CheckForAutoAttack();
		};
		wait.defaultCompleteMode = ToilCompleteMode.Never;
		yield return wait;
	}

	public override void Notify_StanceChanged()
	{
		if( pawn.stances.curStance is Stance_Mobile )
			CheckForAutoAttack();
	}

	private void CheckForAutoAttack()
	{
		if( pawn.Downed )
			return;

		//Don't auto-attack while warming up etc
		if( pawn.stances.FullBodyBusy )
			return;

		//While bursting, there seems to be a gap where the pawn becomes mobile
		

		if( pawn.story == null || !pawn.story.WorkTagIsDisabled(WorkTags.Violent) )
		{
			bool shouldFightFires = pawn.RaceProps.ToolUser
								 && pawn.Faction == Faction.OfPlayer
								 && !pawn.story.WorkTagIsDisabled(WorkTags.Firefighting);

			//Melee attack adjacent enemy pawns
			//Barring that, put out fires
			Fire targetFire = null;
			for( int i=0; i<9; i++ )
			{
				IntVec3 neigh = pawn.Position + GenAdj.AdjacentCellsAndInside[i];

				if( !neigh.InBounds() )
					continue;

				var things = neigh.GetThingList();
				for( int j=0; j<things.Count; j++ )
				{
					//We just hit the first pawn we see (north first)
					Pawn otherPawn = things[j] as Pawn;
					if( otherPawn != null
						&& !otherPawn.Downed
						&& pawn.HostileTo(otherPawn)  )
					{
						pawn.meleeVerbs.TryMeleeAttack(otherPawn);
						return;
					}

					//Prioritize the fire we're standing on.
					//If there isn't one, prioritize the smallest fire
					//This algorithm assumes that the inside cell is last
					if( shouldFightFires )
					{
						Fire fire = things[j] as Fire;
						if( fire != null
							&& (targetFire == null || fire.fireSize < targetFire.fireSize || i==8 )
							&& (fire.parent == null || fire.parent != pawn) )
							targetFire = fire;
					}
				}
			}

			if( targetFire != null && (!pawn.InMentalState || pawn.MentalState.def.allowBeatfire) )
			{
				pawn.natives.TryBeatFire( targetFire );
				return;
			}

			//Shoot at the closest enemy in range
            if( pawn.Faction != null && pawn.jobs.curJob.def == JobDefOf.WaitCombat  )
			{
                // if the pawn is not a colonist, allow pawn to select a weapon that normally requires an order
                bool allowManualCastWeapons = !pawn.IsColonist;
                Verb attackVerb = pawn.TryGetAttackVerb(allowManualCastWeapons);

				if( attackVerb != null && !attackVerb.verbProps.MeleeRange )
				{
					//We increase the range because we can hit targets slightly outside range by shooting at their ShootableSquares
					//We could just put the range at int.MaxValue but this is slightly more optimized so whatever
					TargetScanFlags flags = TargetScanFlags.NeedLOSToAll | TargetScanFlags.NeedThreat;
					if( attackVerb.verbProps.ai_IsIncendiary )
						flags |= TargetScanFlags.NeedNonBurning;
					Thing curTarg = AttackTargetFinder.BestShootTargetFromCurrentPosition(pawn, null, attackVerb.verbProps.range, attackVerb.verbProps.minRange, flags);
                     
					if( curTarg != null )
					{
						pawn.equipment.TryStartAttack( curTarg );
						return;
					}
				}
			}
		}
	}
}}



