public class Program
{
	// For clarity, we declare them at class scope. You could do this inline in Main.
	public static IAutomationHook Hook;
	public static IADRoot Root;

	public static void Main()
	{
		try
		{
			// 1. Attach to a running Alibre instance.
			//    Alternatively, you can do:
			//      Hook = new AutomationHook();
			//      Hook.InitializeService(); // if you want to start a new “service” instance
			Hook = (IAutomationHook)Marshal.GetActiveObject("AlibreX.AutomationHook");
			Root = (IADRoot)Hook.Root;

			if (Root == null)
			{
				Console.WriteLine("Failed to get IADRoot.");
				return;
			}

			// 2. Create a new Part Session
			IADPartSession partSession = Root.CreateEmptyPart("All3DSketchFeatures", false);
			Console.WriteLine("Created part: " + partSession.Name);

			// 3. Access the 3D sketches collection
			IAD3DSketches sketches3D = partSession.Sketches3D;
			if (sketches3D == null)
			{
				Console.WriteLine("No 3D sketches interface found.");
				return;
			}

			// 4. Add a new 3D Sketch
			IAD3DSketch sketch = sketches3D.Add3DSketch("ShowAll3DFeatures");
			Console.WriteLine($"Created 3D sketch: {sketch.Name}");

			// (Optional) set or get: sketch.Name, IsConsumed, IsSuppressed, IsActive, etc.

			// 5. Begin changes
			sketch.BeginChange();
			IAD3DSketchFigures figures = sketch.Figures;

			// ---------------------------------------------------
			// (A) Add a 3D Point
			// ---------------------------------------------------
			//   We can do AddPoint(...) or AddPoint_2(...). The latter
			//   accepts X, Y, Z coords directly.
			IAD3DSketchPoint pointA = figures.AddPoint(1.0, 2.0, 3.0);
			Console.WriteLine("Added 3D point at (1,2,3).");

			// ---------------------------------------------------
			// (B) Add a 3D Line
			// ---------------------------------------------------
			//   i) Overload #1: coordinates
			
			IAD3DSketchLine line1 = figures.AddLine(0.0, 0.0, 0.0,
													10.0, 5.0, 2.0);
			Console.WriteLine("Added 3D line from (0,0,0) to (10,5,2).");

			//   ii) Overload #2: passing IADPoint objects
			//       We'll create them using the geometry factory
			//       just to illustrate the concept.
			IADGeometryFactory geomFactory = partSession.GeometryFactory;

			// Create two 3D points for start/end
			IADPoint pStart = geomFactory.CreatePoint(5.0, 5.0, 10.0);
			IADPoint pEnd = geomFactory.CreatePoint(15.0, 5.0, 10.0);

			// The method is called AddLine_2 in the IDL
			IAD3DSketchLine line2 = figures.AddLine(pStart, pEnd);
			Console.WriteLine("Added 3D line using IADPoints from (5,5,10) to (15,5,10).");

			// ---------------------------------------------------
			// (C) Add a 3D Circular Arc
			// ---------------------------------------------------
			//   i) By center, start, end coordinates
			IAD3DSketchCircularArc arc = figures.AddCircularArcByCenterStartEnd(
				0.0, 0.0, 10.0,    // center
				5.0, 0.0, 10.0,    // start
				0.0, 5.0, 10.0     // end
			);
			Console.WriteLine("Added 3D circular arc by center/start/end coords.");

			//   ii) There's also AddCircularArcByCenterStartEnd_2 using IADPoint objects
			IADPoint arcCenter = geomFactory.CreatePoint(10.0, 10.0, 5.0);
			IADPoint arcStart = geomFactory.CreatePoint(20.0, 10.0, 5.0);
			IADPoint arcEnd = geomFactory.CreatePoint(10.0, 20.0, 5.0);

			IAD3DSketchCircularArc arc2 = figures.AddCircularArcByCenterStartEnd(
				arcCenter, arcStart, arcEnd
			);
			Console.WriteLine("Added 3D circular arc by IADPoints center/start/end.");

			// ---------------------------------------------------
			// (D) Add a 3D Polyline
			// ---------------------------------------------------
			//   Requires passing coordinates in an array => ref System.Array
			double[] polyPoints = new double[]
			{
				1.0,  1.0,  15.0,
				5.0,  3.0,  15.0,
				8.0,  8.0,  15.0,
				2.0,  10.0, 15.0
			};
			System.Array arrPoly = polyPoints;
			IObjectCollector polyResult = figures.AddPolyline(ref arrPoly);
			Console.WriteLine("Added 3D polyline with 4 points.");

			// ---------------------------------------------------
			// (E) Add a 3D Bspline By Interpolation
			// ---------------------------------------------------
			//   This is simpler if we want the curve to pass
			//   directly through the input points.
			double[] splineInterp = new double[]
			{
				0.0,   0.0,   25.0,
				10.0,  0.0,   25.0,
				20.0,  5.0,   25.0,
				30.0,  10.0,  25.0
			};
			System.Array arrInterp = splineInterp;
			IAD3DSketchBspline bSplineInterp = figures.AddBsplineByInterpolation(ref arrInterp);
			Console.WriteLine("Added 3D Bspline via interpolation.");

			// ---------------------------------------------------
			// (F) Add a 3D Bspline (order/ctlPoints/knotVector/weights)
			// ---------------------------------------------------
			//   This is more advanced – you must define order, # of control points,
			//   knot vector, weights, etc.  We'll do a small example with order=3,
			//   4 control points, etc.
			int order = 3;
			int numPoints = 4;

			// Control points (in 3D)
			double[] ctrlPoints = new double[]
			{
				0.0,  5.0,  30.0,
				10.0, 0.0,  30.0,
				20.0, 10.0, 30.0,
				30.0, 5.0,  30.0
			};

			// Knot vector (for a clamped cubic B-spline with 4 control points):
			// Typically length = numPoints + order = 4 + 3 = 7
			// e.g. [0,0,0,1,2,3,3,3] for a certain style, but let's do something simpler
			// However, the official dimension is #Knots = numCtlPoints + order
			// For 4 ctl points, order=3 => 7 knots
			double[] knotVec = new double[]
			{
				0.0,  0.0,  0.0,
				1.0,  2.0,
				3.0,  3.0,  3.0
			};
			// Actually, this is 8 entries, let's reduce or adapt. We'll do 7 total:
			// (We can define a uniform style or non-uniform style)
			// We'll do a 1D array: [0,0,0,1,2,3,3,3] is length=8, that's 8 knots for order=3, #points=4 => 4+3=7
			// Actually we need 4+order=7 or 4+order+1=8? B-spline indexing can differ.
			// We'll just illustrate the principle. We'll keep 8 for the 4 control points & order=3. 
			// We'll pass them all, hopefully the geometry is valid. 
			double[] newKnotVec = new double[] { 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0 };

			// Weights (for non-rational, you can set them all=1.0)
			double[] weights = new double[] { 1.0, 1.0, 1.0, 1.0 };

			// Convert everything to System.Array
			System.Array arrCtrl = ctrlPoints;
			System.Array arrKnots = newKnotVec;
			System.Array arrWeights = weights;

			// AddBspline(int order, int numCtlPoints, SAFEARRAY ctlPoints, SAFEARRAY knots, SAFEARRAY weights)
			IAD3DSketchBspline advancedSpline = figures.AddBspline(
				order,
				numPoints,
				ref arrCtrl,
				ref arrKnots,
				ref arrWeights
			);
			Console.WriteLine("Added 3D Bspline (manual knots, weights, etc.).");

			// ---------------------------------------------------
			// (G) Fetch a figure by ID & change its reference status
			// ---------------------------------------------------
			// Let's retrieve the newly added polyline's “ID” by enumerating the IObjectCollector.
			// Typically, the polyline is multiple figures (each segment?). We'll just show the principle:
			// We'll do a quick scan of all figures
			for (int i = 1; i <= figures.Count; i++)
			{
				IAD3DSketchFigure fig = figures.Item(i);
				Console.WriteLine($"Figure #{i}: ID={fig.ID}, Type={fig.FigureType}");

				// Optionally set reference
				if (fig.FigureType == ADGeometryType.AD_LINE)
				{				
					Console.WriteLine($"Figure #{i}: IsReference={fig.IsReference}");
				}
			}

			// End changes
			sketch.EndChange();
			Console.WriteLine("Done populating 3D sketch with all possible geometry calls.");

			// Optionally regenerate or save
			// partSession.RegenerateAll();
			// partSession.Save();

			Console.WriteLine("Press any key to exit.");

			// Cleanup
			Hook = null;
			Root = null;
		}
		catch (Exception ex)
		{
			Console.WriteLine("Exception: " + ex.Message);
		}
	}
}