namespace Math
{
	const array<int> Primes =
	{
		3,7,11,17,23,29,37,47,59,71,89,107,131,163,197,239,293,353,431,521,631,761,919,1103,1327,1597,1931,2333,2801,
		3371,4049,4861,5839,7013,8419,10103,12143,14591,17519,21023,25229,30293,36353,43627,52361,62851,75431,
		90523,108631,130363,156437,187751,225307,270371,324449,389357,467237,560689,672827,807403,968897,
		1162687,1395263,1674319,2009191,2411033,2893249,3471899,4166287,4999559,5999471,7199369
	};
	
	const float Epsilon = 1.401298E-45;
	const float piHalf = 1.570796f;
	//------------------------------------------------------------------------------------------------------------------------
	// Compares two floating point values if they are similar.
	//------------------------------------------------------------------------------------------------------------------------
	bool Approximately(const float a, const float b)
	{
		return Fabs(b - a) < Max(1E-06f * Max(Fabs(a), Fabs(b)), Epsilon * 8.0f);
	}
	//------------------------------------------------------------------------------------------------------------------------
	// Compares a kVec3 point to a float value if they are similar.
	//------------------------------------------------------------------------------------------------------------------------
	bool Vec3Approximately(kVec3 a, const float b)
	{
		return Approximately(a.x, b) && Approximately(a.y, b) && Approximately(a.z, b);
	}
	//------------------------------------------------------------------------------------------------------------------------
	// Returns the number of digits in the integer (ignores negative values)
	//------------------------------------------------------------------------------------------------------------------------
	int IntLength(const int n)
	{
		int num = Abs(n);
		int count = 0;
		while (num > 0)
		{
			num /= 10;
			count++;
		}
		return count;
	}
	//------------------------------------------------------------------------------------------------------------------------
	float LerpClamped(const float start, const float end, float time)
	{
		return Lerp(start, end, Clampf(time, 0.0f, 1.0f));
	}
	//------------------------------------------------------------------------------------------------------------------------
	int LerpClampedInt(const int start, const int end, const float time)
	{
		return int(Lerp(start, end, Clampf(time, 0.0f, 1.0f)));
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Clampf(const float value, const float min, const float max)
	{
		return (value < min) ? min : ((value > max) ? max : value);
	}
	//------------------------------------------------------------------------------------------------------------------------
	int Clamp(const int value, const int min, const int max)
	{
		return (value < min) ? min : ((value > max) ? max : value);
	}
	//------------------------------------------------------------------------------------------------------------------------
	float Round(const float value)
	{
		int a = int(value * 10);
		int b = int(value) * 10;
		if (value < 0)
		{
			return (a + b >= 5) ? Floor(value) : Ceil(value);
		}
		return (a - b >= 5) ? Ceil(value) : Floor(value);
	}
	//------------------------------------------------------------------------------------------------------------------------
	int RoundToInt(const float value)
	{
		return int(Round(value));
	}
	//------------------------------------------------------------------------------------------------------------------------
	int CeilToInt(const float value)
	{
		return int(Math::Ceil(value));
	}
	//------------------------------------------------------------------------------------------------------------------------
    // Returns a clamped angle to intervals of angleClamp degrees
	//------------------------------------------------------------------------------------------------------------------------
    float ClampAngle(const float value, const float angleClamp)
    {
        return Round(value / angleClamp) * angleClamp;
    }
	//------------------------------------------------------------------------------------------------------------------------
	// Converts an Angle(in rads) to a kVec3 using x,y as direction with magnitude of 1
	//------------------------------------------------------------------------------------------------------------------------
	kVec3 AngleToDirectionXY(const float r)
	{
		return kVec3(Sin(r), Cos(r), 0.0f);
	}
	//------------------------------------------------------------------------------------------------------------------------
	int ToggleBit(int flags, const int bit)
	{
		if ((flags & bit) != 0)
		{
			flags &= ~bit;
		}
		else
		{
			flags |= bit;
		}
		
		return flags;
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool IsPrime(int candidate)
	{
		if ((candidate & 1) != 0)
		{
			int num = int(Math::Sqrt(float(candidate)));
			for (int i = 3; i <= num; i += 2)
			{
				if (candidate % i == 0)
				{
					return false;
				}
			}
			return true;
		}
		return candidate == 2;
	}
	//------------------------------------------------------------------------------------------------------------------------
	int GetPrime(int min)
	{
		for (uint i = 0; i < Primes.length(); i++)
		{
			int prime = Primes[i];
			if (prime >= min)
				return prime;
		}
		
		for (int i = min | 1; i < 2147483647; i += 2)
		{
			if (IsPrime(i) && (i - 1) % 101 != 0)
				return i;
		}
		
		return min;
	}
	//------------------------------------------------------------------------------------------------------------------------
	int ExpandPrime(int oldSize)
	{
		int num = 2 * oldSize;
		if (num > 2146435069 && 2146435069 > oldSize)
		{
			return 2146435069;
		}
		return GetPrime(num);
	}
	//------------------------------------------------------------------------------------------------------------------------
}
