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 float 				selectionWeight;

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

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

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

public class FactionDef : Def
{
	//General config
	public bool					isPlayer = false;
	public RulePackDef			factionNameMaker;
	public RulePackDef			baseNameMaker;
	public RulePackDef			factionNameMakerPlayer;
	public RulePackDef			baseNameMakerPlayer;
	public string				fixedName = null;
	public bool					humanlikeFaction = true;
	public bool					hidden = false;
	public List<PawnGroupMaker>	pawnGroupMakers = null;
	public SimpleCurve			raidCommonalityFromPointsCurve = null;
	public bool					autoFlee = true;
	public bool					canSiege = false;
	public bool					canStageAttacks = false;
	public bool					canUseAvoidGrid = true;
	public float				earliestRaidDays = 0;
	public FloatRange			allowedArrivalTemperatureRange = new FloatRange(-1000, 1000);
	public PawnKindDef			basicMemberKind;
	[NoTranslate] public List<string>	startingResearchTags = null;
	[NoTranslate] public List<string>	recipePrerequisiteTags = null;
	public bool					rescueesCanJoin = false;
	[MustTranslate] public string pawnsPlural = "members";
	public string				leaderTitle = "leader"; //Not MustTranslate because many faction defs never have leaders
	public float				maxPawnOptionCostFactor = 1f;

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

	//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>();
	public List<TraderKindDef>	baseTraderKinds = new List<TraderKindDef>();
	public float				geneticVariance = 1f;

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

	//World drawing
	public string				homeIconPath;
	public string				expandingIconTexture;
	public List<Color>			colorSpectrum;

	//Unsaved
	[Unsaved] private Texture2D	expandingIconTextureInt;

	//Properties
	public bool CanEverBeNonHostile
	{
		get
		{
			if( startingGoodwill.max < 0 && !appreciative )
				return false;
			else
				return true;
		}
	}
	public Texture2D ExpandingIconTexture
	{
		get
		{
			if( expandingIconTextureInt == null )
			{
				if( !expandingIconTexture.NullOrEmpty() )
					expandingIconTextureInt = ContentFinder<Texture2D>.Get(expandingIconTexture);
				else
					expandingIconTextureInt = BaseContent.BadTex;
			}

			return expandingIconTextureInt;
		}
	}

	public float MinPointsToGenerateNormalPawnGroup()
	{
		if( pawnGroupMakers == null )
			return 9999999;

		var groups = pawnGroupMakers.Where(x => x.kindDef == PawnGroupKindDefOf.Normal);

		if( !groups.Any() )
			return 9999999;

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

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

		return apparelStuffFilter.Allows( stuffDef );
	}

	public float RaidCommonalityFromPoints( float points )
	{
		if( points < 0 || raidCommonalityFromPointsCurve == null )
			return 1f;

		return raidCommonalityFromPointsCurve.Evaluate(points);
	}

	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( !isPlayer && 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.";
		}

		if( isPlayer )
		{
			if( baseNameMakerPlayer == null )
				yield return "isPlayer is true but baseNameMakerPlayer is null";

			if( factionNameMakerPlayer == null )
				yield return "isPlayer is true but factionNameMakerPlayer is null";
		}
	}

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

