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 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.OfColony )
		{
			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() )
		{
			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( 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);
			}
		}

		ListerBuildingsRepairable.Notify_BuildingDeSpawned(this);
	}
	
	public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
	{
		base.Destroy(mode);
		
        if( def.MakeFog )
            Find.FogGrid.Notify_FogBlockerDestroyed(Position);

		if( def.holdsRoof )
			RoofCollapser.Notify_RoofHolderDestroyed(this);

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

		Find.ListerBuildings.Remove(this);

		if( mode == DestroyMode.Uninstall && def.Minifiable )
		{
			// spawn minified version of me

			MinifiedThing mt = this.MakeMinified();
			GenPlace.TryPlaceThing(mt, Position, ThingPlaceMode.Near);
			SoundDef.Named("ThingUninstalled").PlayOneShot(Position);
		}
		else if( mode == DestroyMode.Deconstruct )
			SoundDef.Named("BuildingDeconstructed").PlayOneShot(Position);
	}


	public override void Draw()
	{
		if( HitPoints < MaxHitPoints && def.useHitPoints && def.drawDamagedOverlay )
			OverlayDrawer.DrawOverlay(this, OverlayTypes.Damaged);

		//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 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;
	}
}
}
