/// <summary>
        /// Gets the name of a triangle with the given stats.
        /// </summary>
        /// <param name="stats">The stats object of the triangle.</param>
        /// <returns>The name of the triangle with the given stats.</returns>
        public static string GetTriangleName(TriangleStats stats)
        {
            var result = "";

            switch (stats.Angle)
            {
            case TriangleAngle.Acute:
                result = "acute";
                break;

            case TriangleAngle.Right:
                result = "right";
                break;

            case TriangleAngle.Obtuse:
                result = "obtuse";
                break;
            }
            switch (stats.Type)
            {
            case TriangleType.Equilateral:
                // all equilateral triangles are also acute triangles, so no need to keep it in the name
                result = "equilateral";
                break;

            case TriangleType.Isosceles:
                result += " isosceles";
                break;

            case TriangleType.Scalene:
                result += " scalene";
                break;
            }
            return(result);
        }
        /// <summary>
        /// Calculates the stats of a triangle with the given side lengths.
        /// Throws an exception if the sides do not create a valid triangle (triangles with zero area are allowed).
        /// </summary>
        /// <param name="sideA">The length of side A of the triangle.</param>
        /// <param name="sideB">The length of side B of the triangle.</param>
        /// <param name="sideC">The length of side C of the triangle.</param>
        /// <returns>An object containing the triangle's stats.</returns>
        public static TriangleStats GetTriangleStats(double sideA, double sideB, double sideC)
        {
            if (sideA < 0)
            {
                throw new ArgumentException(ERR_NEGATIVE_LENGTH, "sideA");
            }
            if (sideB < 0)
            {
                throw new ArgumentException(ERR_NEGATIVE_LENGTH, "sideB");
            }
            if (sideC < 0)
            {
                throw new ArgumentException(ERR_NEGATIVE_LENGTH, "sideC");
            }
            if (sideC > sideA + sideB || sideA > sideB + sideC || sideB > sideC + sideA)
            {
                throw new InvalidTriangleException("No side's length can be greater than the sum of the other two.");
            }

            var info = new TriangleStats();

            // check side lengths
            var AeqB = sideA == sideB;
            var BeqC = sideB == sideC;
            var CeqA = sideC == sideA;

            if (AeqB && BeqC)
            {
                info.Type = TriangleType.Equilateral;
            }
            else if (AeqB || BeqC || CeqA)
            {
                info.Type = TriangleType.Isosceles;
            }
            else
            {
                info.Type = TriangleType.Scalene;
            }

            // check angles
            // uses cosine rule to calculate angles A and B, and subtract both from 180 degrees to find C
            var angA = Math.Acos((Math.Pow(sideB, 2) + Math.Pow(sideC, 2) - Math.Pow(sideA, 2)) / (2 * sideB * sideC));
            var angB = Math.Acos((Math.Pow(sideA, 2) + Math.Pow(sideC, 2) - Math.Pow(sideB, 2)) / (2 * sideA * sideC));
            var angC = Math.PI - angA - angB;

            // allow a small margin of error to account for floating-point innacuracy
            if (Math.Abs(angA - RIGHT_ANGLE) < FP_MARGIN || Math.Abs(angB - RIGHT_ANGLE) < FP_MARGIN || Math.Abs(angC - RIGHT_ANGLE) < FP_MARGIN)
            {
                info.Angle = TriangleAngle.Right;
            }
            else if (angA > RIGHT_ANGLE || angB > RIGHT_ANGLE || angC > RIGHT_ANGLE)
            {
                info.Angle = TriangleAngle.Obtuse;
            }
            else
            {
                info.Angle = TriangleAngle.Acute;
            }

            return(info);
        }
 protected string GetTriangleMessage(TriangleStats info)
 {
     return(string.Format(VALID_RESULT_TEXT, TriangleChecker.GetTriangleName(info)));
 }