﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;

namespace rjw
{
	/// <summary>
	/// Checks for relations, workaround for relation checks that rely on other relation checks, since the vanilla inRelation checks have been prefixed.
	/// 
	/// Return true if first pawn is specified relation of the second pawn
	/// 
	///  If "me" isRelationOf "other" return true
	/// </summary>
	/// 
	public static class RelationChecker
	{
		// like getMother() but without gender, and capable of pulling second parent of same gender
		private static Pawn getParent(Pawn pawn, bool skipFirst)
		{
			if (pawn == null)
			{
				return null;
			}
			if (!pawn.RaceProps.IsFlesh)
			{
				return null;
			}
			if (pawn.relations == null)
			{
				return null;
			}
			foreach (DirectPawnRelation directPawnRelation in pawn.relations.DirectRelations)
			{
				if (directPawnRelation.def == PawnRelationDefOf.Parent)
				{
					if (!skipFirst)
					{
						return directPawnRelation.otherPawn;
					}
					skipFirst = false;
				}
			}
			return null;
		}

		// unnecessary but make reading relations easier
		public static Pawn getParent(Pawn pawn)
		{
			return getParent(pawn, false);
		}

		public static Pawn getSecondParent(Pawn pawn)
		{
			return getParent(pawn, true);
		}

		// checks against all Parent direct relations, ignoring gender
		public static bool isChildOf(Pawn me, Pawn other)
		{
			if (me == null || other ==null || me == other)
			{
				return false;
			}
			if (!other.RaceProps.IsFlesh)
			{
				return false;
			}
			if (me.relations == null)
			{
				return false;
			}
			foreach (DirectPawnRelation directPawnRelation in me.relations.DirectRelations)
			{
				if (directPawnRelation.def == PawnRelationDefOf.Parent && directPawnRelation.otherPawn == other)
				{
					return true;
				}
			}
			return false;
		}

		public static bool isSiblingOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (getParent(me) != null && getSecondParent(me) != null && (
				getParent(me) == getParent(other) && getSecondParent(me) == getSecondParent(other) || // if both have same parents
				getParent(me) == getSecondParent(other) && getSecondParent(me) == getParent(other))) // if parents swapped roles, idk how such relation would be named, but without this they are kin, which is wrong
			{
				return true;
			}
			return false;
		}

		public static bool isHalfSiblingOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (isSiblingOf(me, other))
			{
				return false;
			}
			return getParent(me) != null && (getParent(me) == getParent(other) || getParent(me) == getSecondParent(other)) ||
					getSecondParent(me) != null && (getSecondParent(me) == getParent(other) || getSecondParent(me) == getSecondParent(other));
		}

		public static bool isAnySiblingOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (getParent(me) != null && (getParent(me) == getParent(other) || getParent(me) == getSecondParent(other)) ||
				getSecondParent(me) != null && (getSecondParent(me) == getParent(other) || getSecondParent(me) == getSecondParent(other)))
			{
				return true;
			}
			return false;
		}

		public static bool isGrandchildOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((getParent(me) != null && isChildOf(getParent(me), other)) || (getSecondParent(me) != null && isChildOf(getSecondParent(me), other)))
			{
				return true;
			}
			return false;
		}

		public static bool isGrandparentOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (isGrandchildOf(other, me))
			{
				return true;
			}
			return false;
		}

		public static bool isNephewOrNieceOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((getParent(me) != null && (isAnySiblingOf(other, getParent(me)))) || (getSecondParent(me) != null && (isAnySiblingOf(other, getSecondParent(me)))))
			{
				return true;
			}
			return false;
		}

		public static bool isUncleOrAuntOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if (isNephewOrNieceOf(other, me))
			{
				return true;
			}
			return false;
		}

		public static bool isCousinOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			if ((getParent(other) != null && isNephewOrNieceOf(me, getParent(other))) || (getSecondParent(other) != null && isNephewOrNieceOf(me, getSecondParent(other))))
			{
				return true;
			}
			return false;
		}

		public static bool isGreatGrandparentOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			return isGreatGrandChildOf(other, me);
		}

		public static bool isGreatGrandChildOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			if ((getParent(me) != null && isGrandchildOf(getParent(me), other)) || (getSecondParent(me) != null && isGrandchildOf(getSecondParent(me), other)))
			{
				return true;
			}
			return false;
		}

		public static bool isGreatUncleOrAuntOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			return isGrandnephewOrGrandnieceOf(other, me);
		}

		public static bool isGrandnephewOrGrandnieceOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}

			if ((getParent(me) != null && isUncleOrAuntOf(other, getParent(me))) || (getSecondParent(me) != null && isUncleOrAuntOf(other, getSecondParent(me))))
			{
				return true;
			}
			return false;
		}

		public static bool isCousinOnceRemovedOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			if ((getParent(other) != null && isCousinOf(me, getParent(other))) || (getSecondParent(other) != null && isCousinOf(me, getSecondParent(other))))
			{
				return true;
			}
			if ((getParent(other) != null && isGrandnephewOrGrandnieceOf(me, getParent(other))) || (getSecondParent(other) != null && isGrandnephewOrGrandnieceOf(me, getSecondParent(other))))
			{
				return true;
			}
			return false;
		}

		public static bool isSecondCousinOf(Pawn me, Pawn other)
		{
			if (me == null || me == other)
			{
				return false;
			}
			Pawn parent = getParent(other);
			if (parent != null && ((getParent(parent) != null && isGrandnephewOrGrandnieceOf(me, getParent(parent))) || (getSecondParent(parent) != null && isGrandnephewOrGrandnieceOf(me, getSecondParent(parent)))))
			{
				return true;
			}

			Pawn secondParent = getSecondParent(other);
			if (secondParent != null && (getParent(secondParent) != null && isGrandnephewOrGrandnieceOf(me, getParent(secondParent)) || (getSecondParent(secondParent) != null && isGrandnephewOrGrandnieceOf(me, getSecondParent(secondParent)))))
			{
				return true;
			}
			return false;
		}
	}
}
