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



namespace Verse{
public class Building : ThingWithComps
{
	//Working vars
	private Sustainer		sustainerAmbient = null;

	//Properties
	public CompPower PowerComp		{get{ return GetComp<CompPower>(); }}
	public virtual bool TransmitsPowerNow
	{
		get
		{
			//Designed to be overridden
			//In base game this always just returns the value in the powercomp's def
			CompPower pc = PowerComp;
			return pc != null && pc.Props.transmitsPower;
		}
	}
	public override int HitPoints
	{
		set
		{
			int oldHitPoints = HitPoints;
			base.HitPoints = value;

			BuildingsDamageSectionLayerUtility.Notify_BuildingHitPointsChanged(this, oldHitPoints);
		}
	}
	
	public override void SpawnSetup()
	{
		base.SpawnSetup();
		
		Find.ListerBuildings.Add( this );	
		
		//Remake terrain meshes with new underwall under me
		if( def.coversFloor )
			Find.MapDrawer.MapMeshDirty(Position, MapMeshFlag.Terrain, true, false);

		var occRect = this.OccupiedRect();
		for( int z=occRect.minZ; z<=occRect.maxZ; z++ )
		{
			for( int x=occRect.minX; x<=occRect.maxX; x++ )
			{
				var c = new IntVec3(x,0,z);
				Find.MapDrawer.MapMeshDirty( c, MapMeshFlag.Buildings );
				Find.GlowGrid.MarkGlowGridDirty(c);
				if( !SnowGrid.CanCoexistWithSnow(def) )
					Find.SnowGrid.SetDepth(c, 0);
			}
		}

		if( def.IsEdifice() )
			Find.EdificeGrid.Register(this);

		if( Faction == Faction.OfPlayer )
		{
			if( def.building != null && def.building.spawnedConceptLearnOpportunity != null )
			{
				ConceptDecider.TeachOpportunity( def.building.spawnedConceptLearnOpportunity, OpportunityType.GoodToKnow );
			}
		}

		AutoHomeAreaMaker.Notify_BuildingSpawned( this );

		if( def.building != null && !def.building.soundAmbient.NullOrUndefined() )
		{
			LongEventHandler.ExecuteWhenFinished(() =>
				{
					SoundInfo info = SoundInfo.InWorld(this, MaintenanceType.None);
					sustainerAmbient = SoundStarter.TrySpawnSustainer(def.building.soundAmbient, info);
				});
		}

		ListerBuildingsRepairable.Notify_BuildingSpawned(this);
	}

	public override void DeSpawn()
	{
		if( def.IsEdifice() )
			Find.EdificeGrid.DeRegister(this);

		base.DeSpawn();

		if( def.building.ai_combatDangerous )
			Verse.AI.AvoidGridMaker.Notify_CombatDangerousBuildingDespawned(this);

		if( def.MakeFog )
			Find.FogGrid.Notify_FogBlockerRemoved(Position);

		if( def.holdsRoof )
			RoofCollapseCellsFinder.Notify_RoofHolderDespawned(this);

		if( sustainerAmbient != null )
			sustainerAmbient.End();

		CellRect occRect = GenAdj.OccupiedRect(this);
		for( int z=occRect.minZ; z<=occRect.maxZ; z++ )
		{
			for( int x=occRect.minX; x<=occRect.maxX; x++ )
			{
				IntVec3 c = new IntVec3(x,0,z);

				MapMeshFlag changeType = MapMeshFlag.Buildings;

				if( def.coversFloor )
					changeType |= MapMeshFlag.Terrain;

				if( def.Fillage == FillCategory.Full )
				{
					changeType |= MapMeshFlag.Roofs;
					changeType |= MapMeshFlag.Snow;
				}

				Find.Map.mapDrawer.MapMeshDirty( c, changeType );

				Find.GlowGrid.MarkGlowGridDirty(c);
			}
		}

		Find.ListerBuildings.Remove(this);
		ListerBuildingsRepairable.Notify_BuildingDeSpawned(this);

		if( def.leaveTerrain != null && Current.ProgramState == ProgramState.MapPlaying )
		{
			for( var cri = GenAdj.OccupiedRect(this).GetIterator(); !cri.Done(); cri.MoveNext() )
			{
				Find.TerrainGrid.SetTerrain(cri.Current, def.leaveTerrain);
			}
		}

		//Mining, planning, etc
		Find.DesignationManager.Notify_BuildingDespawned(this);
	}
	
	public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
	{
		base.Destroy(mode);

		// (buildings can be reinstalled)
		InstallBlueprintUtility.CancelBlueprintsFor(this);

		if( mode == DestroyMode.Deconstruct )
			SoundDef.Named("BuildingDeconstructed").PlayOneShot(Position);
	}


	public override void Draw()
	{
		//If we've already added to the map mesh don't bother with drawing our base mesh
		if( def.drawerType == DrawerType.RealtimeOnly )
			base.Draw();
		
		Comps_PostDraw();
	}

	public override void SetFaction( Faction newFaction, Pawn recruiter = null )
	{
		base.SetFaction(newFaction, recruiter);

		ListerBuildingsRepairable.Notify_BuildingFactionChanged(this);
	}

	public override void PostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
	{
		base.PostApplyDamage(dinfo, totalDamageDealt);

		ListerBuildingsRepairable.Notify_BuildingTookDamage(this);
	}

	public override void DrawExtraSelectionOverlays()
	{
		base.DrawExtraSelectionOverlays();

		var ebp = InstallBlueprintUtility.ExistingBlueprintFor(this);

		if( ebp != null )
			GenDraw.DrawLineBetween(this.TrueCenter(), ebp.TrueCenter());
	}

	public override IEnumerable<Gizmo> GetGizmos()
	{
		foreach( var c in base.GetGizmos() )
		{
			yield return c;
		}

		if( def.Minifiable )
			yield return InstallationDesignatorDatabase.DesignatorFor(def);
	}

	public virtual bool ClaimableBy(Faction faction)
	{
		return !def.building.isNaturalRock && def.building.claimable;
	}

	public virtual ushort PathFindCostFor(Pawn p)
	{
		return 0;
	}

	public virtual ushort PathWalkCostFor(Pawn p)
	{
		return 0;
	}
}
}
