using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Verse;
using UnityEngine;


namespace RimWorld{
public class PawnGenOption
{
	//Config
	public PawnKindDef			kind;
	public int 					selectionWeight;

	//Properties
	public float Cost{get{return kind.combatPower;}}

	public override string ToString()
	{
		return "(" + kind.ToString() + " w=" + selectionWeight.ToString("F2") + " c=" + Cost.ToString("F2") + ")";
	}

	public void LoadDataFromXmlCustom( XmlNode xmlRoot )
	{
		CrossRefLoader.RegisterObjectWantsCrossRef( this, "kind", xmlRoot.Name );
		selectionWeight = (int)ParseHelper.FromString( xmlRoot.FirstChild.Value, typeof(int) );
	}
}

public class FactionDef : Def
{
	//General config
	public bool					isPlayer = false;
	public RulePackDef			factionNameMaker;
	public string				fixedName = null;
	public bool					humanlikeFaction = true;
	public bool					hidden = false;
	public List<PawnGroupMaker>	pawnGroupMakers = null;
	public string				pawnsPlural = "characters";
	public float				raidCommonality = 0;
	public bool					canFlee = true;
	public bool					canSiege = false;
	public bool					canStageAttacks = false;
	public bool					canUseAvoidGrid = true;
	public float				earliestRaidDays = 0;
	public string				leaderTitle = "Leader";
	public FloatRange			allowedArrivalTemperatureRange = new FloatRange(-1000, 1000);
	public PawnKindDef			basicMemberKind;
	public List<string>			startingResearchTags = null;


	//Faction generation
	public int					requiredCountAtGameStart = 0;
	public int					maxCountAtGameStart = 9999;
	public bool					canMakeRandomly = false;

	//Humanlike faction config
	public RulePackDef			pawnNameMaker;
	public TechLevel			techLevel = TechLevel.Undefined;
	public string				backstoryCategory = null;
	public List<string>			hairTags = new List<string>();
	public ThingFilter			apparelStuffFilter = null;
	public List<TraderKindDef>	caravanTraderKinds = new List<TraderKindDef>();
	public List<TraderKindDef>	visitorTraderKinds = new List<TraderKindDef>();

	//Relations (can apply to non-humanlike factions)
	public FloatRange			startingGoodwill = FloatRange.Zero;
	public bool					mustStartOneEnemy = false;	//Game starts with one of these enemy at least
	public FloatRange			naturalColonyGoodwill = FloatRange.Zero;
	public float				goodwillDailyGain = 2f;
	public float				goodwillDailyFall = 2f;
	public bool					appreciative = true;

	//Map drawing
	public string				homeIconPath;
	public Color				homeIconColor = Color.white;

	//Unsaved
	[Unsaved] public Material	baseRenderMaterial = BaseContent.BadMat;

	//Properties
	public bool CanEverBeNonHostile
	{
		get
		{
			if( startingGoodwill.max < 0 && !appreciative )
				return false;
			else
				return true;
		}
	}


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

		if( !homeIconPath.NullOrEmpty() )
			LongEventHandler.ExecuteWhenFinished(() => baseRenderMaterial = MaterialPool.MatFrom(homeIconPath, ShaderDatabase.Transparent, homeIconColor));
	}

	public float MinPointsToGenerateNormalPawnGroup()
	{
		if( pawnGroupMakers == null )
			return int.MaxValue;

		var groups = pawnGroupMakers.Where(x => x is PawnGroupMaker_Normal);

		if( !groups.Any() )
			return int.MaxValue;

		return groups.Min(pgm => pgm.MinPointsToGenerateAnything);
	}

	public bool CanUseStuffForApparel( ThingDef stuffDef )
	{
		if( apparelStuffFilter == null )
			return true;

		return apparelStuffFilter.Allows( stuffDef );
	}

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

		if( apparelStuffFilter != null )
			apparelStuffFilter.ResolveReferences();
	}

	public override IEnumerable<string> ConfigErrors()
	{
		foreach( var error in base.ConfigErrors() )
			yield return error;

		if( factionNameMaker == null && fixedName == null )
			yield return "FactionTypeDef " + defName + " lacks a factionNameMaker and a fixedName.";

		if( techLevel == TechLevel.Undefined )
			yield return defName + " has no tech level.";

		if( humanlikeFaction )
		{
			if( backstoryCategory == null )
				yield return defName + " is humanlikeFaction but has no backstory category.";

			if( hairTags.Count == 0 )
				yield return defName + " is humanlikeFaction but has no hairTags.";
		}
	}

	public static FactionDef Named( string defName )
	{
		return DefDatabase<FactionDef>.GetNamed(defName);
	}
}}

