//                    \ A
        //                     \
        //                      \
        //   center: O          / P
        //                     /
        //                    / B
        //
        // Tangent(Circle(O), Segment(B, P)),
        // Tangent(Circle(O), Segment(A, P)),
        // Intersection(AP, BP) -> Congruent(Segment(A, P), Segment(P, B))
        //
        private static List<EdgeAggregator> InstantiateTheorem(Tangent tangent1, Tangent tangent2, Intersection inter, GroundedClause original1, GroundedClause original2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Do the tangents apply to the same circle?
            if (!tangent1.intersection.theCircle.StructurallyEquals(tangent2.intersection.theCircle)) return newGrounded;

            // Do the tangents have components the are part of the third intersection
            if (!inter.HasSegment((tangent1.intersection as CircleSegmentIntersection).segment)) return newGrounded;
            if (!inter.HasSegment((tangent2.intersection as CircleSegmentIntersection).segment)) return newGrounded;

            Segment segment1 = Segment.GetFigureSegment(inter.intersect, tangent1.intersection.intersect);
            Segment segment2 = Segment.GetFigureSegment(inter.intersect, tangent2.intersection.intersect);

            GeometricCongruentSegments gcs = new GeometricCongruentSegments(segment1, segment2);

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original1);
            antecedent.Add(original2);
            antecedent.Add(inter);

            newGrounded.Add(new EdgeAggregator(antecedent, gcs, annotation));

            return newGrounded;
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // Two tangents:
        // Intersection(X, AD, BC), Tangent(Circle(O), BC), Tangent(Circle(O), AD) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateTwoTangentsTheorem(Tangent tangent1, Tangent tangent2, Intersection inter, GroundedClause original1, GroundedClause original2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan1 = tangent1.intersection as CircleSegmentIntersection;
            CircleSegmentIntersection tan2 = tangent2.intersection as CircleSegmentIntersection;

            if (tan1.StructurallyEquals(tan2)) return newGrounded;

            // Do the tangents apply to the same circle?
            if (!tan1.theCircle.StructurallyEquals(tan2.theCircle)) return newGrounded;

            Circle circle = tan1.theCircle;

            // Do these tangents work with this intersection?
            if (!inter.HasSegment(tan1.segment) || !inter.HasSegment(tan2.segment)) return newGrounded;

            // Overkill? Do the tangents intersect at the same point as the intersection's intersect point?
            if (!tan1.segment.FindIntersection(tan2.segment).StructurallyEquals(inter.intersect)) return newGrounded;

            //
            // Get the arcs
            //
            Arc minorArc = new MinorArc(circle, tan1.intersect, tan2.intersect);
            Arc majorArc = new MajorArc(circle, tan1.intersect, tan2.intersect);

            Angle theAngle = new Angle(tan1.intersect, inter.intersect, tan2.intersect);

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(majorArc, minorArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original1);
            antecedent.Add(original2);
            antecedent.Add(inter);
            antecedent.Add(majorArc);
            antecedent.Add(minorArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
        //        )  | B
        //         ) |
        // O        )| S
        //         ) |
        //        )  |
        //       )   | A
        // Tangent(Circle(O, R), Segment(A, B)), Intersection(OS, AB) -> Perpendicular(Segment(A,B), Segment(O, S))
        //
        private static List<EdgeAggregator> InstantiateTheorem(Tangent tangent, Intersection inter, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tanInter = tangent.intersection as CircleSegmentIntersection;

            // Does this tangent segment apply to this intersection?
            if (!inter.HasSegment(tanInter.segment)) return newGrounded;

            // Get the radius--if it exists
            Segment radius = null;
            Segment garbage = null;
            tanInter.GetRadii(out radius, out garbage);

            if (radius == null) return newGrounded;

            // Does this radius apply to this intersection?
            if (!inter.HasSubSegment(radius)) return newGrounded;

            Strengthened newPerp = new Strengthened(inter, new Perpendicular(inter));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original);
            antecedent.Add(inter);

            newGrounded.Add(new EdgeAggregator(antecedent, newPerp, annotation));

            return newGrounded;
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // One Secant, One Tangent
        // Intersection(X, AD, BC), Tangent(Circle(O), BC) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateOneSecantOneTangentTheorem(Intersection inter, Tangent tangent, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan = tangent.intersection as CircleSegmentIntersection;

            // Is the tangent segment part of the intersection?
            if (!inter.HasSegment(tan.segment)) return newGrounded;

            // Acquire the chord that the intersection creates.
            Segment secant = inter.OtherSegment(tan.segment);

            Circle circle = tan.theCircle;
            Segment chord = circle.ContainsChord(secant);

            // Check if this segment never intersects the circle or doesn't create a chord.
            if (chord == null) return newGrounded;

            //
            // Get the near / far points out of the chord
            //
            Point closeChordPt = null;
            Point farChordPt = null;
            if (Segment.Between(chord.Point1, chord.Point2, inter.intersect))
            {
                closeChordPt = chord.Point1;
                farChordPt = chord.Point2;
            }
            else
            {
                closeChordPt = chord.Point2;
                farChordPt = chord.Point1;
            }

            //
            // Acquire the arcs
            //
            // Get the close arc first which we know exactly how it is constructed AND that it's a minor arc.
            Arc closeArc = Arc.GetFigureMinorArc(circle, closeChordPt, tan.intersect);

            // The far arc MAY be a major arc; if it is, the first candidate arc will contain the close arc.
            Arc farArc = Arc.GetFigureMinorArc(circle, farChordPt, tan.intersect);

            if (farArc.HasMinorSubArc(closeArc))
            {
                farArc = Arc.GetFigureMajorArc(circle, farChordPt, tan.intersect);
            }

            Angle theAngle = Angle.AcquireFigureAngle(new Angle(closeChordPt, inter.intersect, tan.intersect));

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original);
            antecedent.Add(inter);
            antecedent.Add(closeArc);
            antecedent.Add(farArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
        //
        //          C
        //         /)
        //        /  )
        //       / )
        //      / )
        //   A /)_________ B
        //
        // Tangent(Circle(O), Segment(AB)), Intersection(Segment(AC), Segment(AB)) -> 2 * Angle(CAB) = Arc(C, B)
        //
        public static List<EdgeAggregator> InstantiateTheorem(Intersection inter, Tangent tangent, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan = tangent.intersection as CircleSegmentIntersection;

            //
            // Does this tangent apply to this intersection?
            //
            if (!inter.intersect.StructurallyEquals(tangent.intersection.intersect)) return newGrounded;

            Segment secant = null;
            Segment tanSegment = null;
            if (tan.HasSegment(inter.lhs))
            {
                secant = inter.rhs;
                tanSegment = inter.lhs;
            }
            else if (tan.HasSegment(inter.rhs))
            {
                secant = inter.lhs;
                tanSegment = inter.rhs;
            }
            else return newGrounded;

            //
            // Acquire the angle and intercepted arc.
            //
            Segment chord = tan.theCircle.GetChord(secant);
            if (chord == null) return newGrounded;
            //Segment chord = tan.theCircle.ContainsChord(secant);

            // Arc
            // We want the MINOR ARC only!
            if (tan.theCircle.DefinesDiameter(chord))
            {
                Arc theArc = null;
                Point midpt = PointFactory.GeneratePoint(tan.theCircle.Midpoint(chord.Point1, chord.Point2));
                Point opp = PointFactory.GeneratePoint(tan.theCircle.OppositePoint(midpt));

                Point tanPoint = tanSegment.OtherPoint(inter.intersect);

                if (tanPoint != null)
                {
                    // Angle; the smaller angle is always the chosen angle
                    Angle theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanPoint);

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, midpt, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, opp, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));
                }
                else
                {
                    // Angle; the smaller angle is always the chosen angle
                    Angle theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanSegment.Point1);

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, midpt, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, opp, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    // Angle; the smaller angle is always the chosen angle
                    theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanSegment.Point2);

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, midpt, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, opp, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                }
            }
            else
            {
                Arc theArc = new MinorArc(tan.theCircle, chord.Point1, chord.Point2);

                // Angle; the smaller angle is always the chosen angle
                Point endPnt = (inter.intersect.StructurallyEquals(tanSegment.Point1)) ? tanSegment.Point2 : tanSegment.Point1;
                Angle theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, endPnt);

                if (theAngle.measure > 90)
                {
                    //If the angle endpoint was already set to Point2, or if the intersect equals Point2, then the smaller angle does not exist
                    //In this case, should we create a major arc or return nothing?
                    if (endPnt.StructurallyEquals(tanSegment.Point2) || inter.intersect.StructurallyEquals(tanSegment.Point2)) return newGrounded;
                    theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanSegment.Point2);
                }

                Multiplication product = new Multiplication(new NumericValue(2), theAngle);
                GeometricAngleArcEquation angArcEq = new GeometricAngleArcEquation(product, theArc);

                // For hypergraph
                List<GroundedClause> antecedent = new List<GroundedClause>();
                antecedent.Add(original);
                antecedent.Add(inter);
                antecedent.Add(theArc);
                antecedent.Add(theAngle);

                newGrounded.Add(new EdgeAggregator(antecedent, angArcEq, annotation));
            }

            return newGrounded;
        }