//////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2025 Autodesk, Inc.  All rights reserved.
//
//  Use of this software is subject to the terms of the Autodesk license 
//  agreement provided at the time of installation or download, or which 
//  otherwise accompanies this software in either electronic or hard copy form.   
//
//////////////////////////////////////////////////////////////////////////////

#ifndef _LEADER_H
#define _LEADER_H

#ifndef __ACMDEF_H
	#error include 'acmdef.h' before including this file
#endif

class AcmCLeaderNodeIterator;
class AcmCAuxEntity;
class AcmCLeaderNode;
class AcmSymbol;
class AcmVariant;

struct AcmSymGripInfo
{
  enum GripType
  {
    kUnknownType    = -1,
    kStartPoint     = 0,      //the 1st leader segment start point grip
    kFirstEndPoint  = 1,      //the 1st leader segment end point grip
    kOther          = 2,      //points at the 2nd, 3rd or 4th leader segment end point etc grip
    kLandEndPoint   = 3,      //land end point, in general at sub symbol
    kTextLocation   = 4,      //for note text location
    kDummyLandPt    = 5,      //for taper with a dummy land when no attach object and no leader
    kSubSymOrig     = 6       //the origin of sub-symbol
  };

  enum LeaderType
  {
    kPrimaryLeader    = 0,
    kSecondaryLeader  = 1,
    kSurfIndLeader    = 2
  };

  AcmSymGripInfo( AcmSymGripInfo::GripType gripType, int index, bool isUseDOF = false, int mNumOfBranches = 1,
    AcmSymGripInfo::LeaderType leaderType = AcmSymGripInfo::kPrimaryLeader,AcDbGripData* pGripData = NULL)
    : mGripType(gripType),
    mIndex(index),
    mIsUseDOF(isUseDOF),
    mLeaderType(leaderType),
    mpGripData(pGripData),
    mNumOfBranches(1)
  {}

  AcDbGripData* mpGripData;
  GripType mGripType;
  int mIndex;
  bool mIsUseDOF;
  LeaderType mLeaderType;
  int mNumOfBranches;
};

///<summary>This class defines the interface for all possible leader implementations. If a particular 
///symbol class does not override the addLeader member function of the AcmSymbol class, then the general 
///symbol leader is used. Otherwise more specialized types of leaders can be used.</summary>
class ACMSYMBB_CRX_DLLSHARE AcmCLeader
{
  public :
  ///<summary>Destructures the leader class.</summary>
  virtual ~AcmCLeader();
  virtual Acm::ArrowType arrowType() const = 0;
  ///<summary>Sets the arrow type of this leader to override the standard setting.</summary>
  virtual Acm::ErrorStatus setArrowType (Acm::ArrowType arrowType) = 0;
  ///<summary>Gets the appearance of the leader line.</summary>
  virtual Acm::ErrorStatus getLineTypeId (AcDbObjectId& linetypeId) const = 0;
  ///<summary>Sets the appearance of the leader line.</summary>
  virtual Acm::ErrorStatus setLineTypeId (const AcDbObjectId& linetypeId) = 0;

  virtual Acm::ErrorStatus getLineWeight (AcDb::LineWeight& lineweight) const = 0;

  ///<summary>Gets the arrowhead scale of the leader.</summary>
  virtual double symbolScale() const = 0;
  ///<summary>Gets the color of the leader.</summary>
  virtual Acm::ErrorStatus getColor (Adesk::Int16& color) const = 0;    
  ///<summary>Sets the color of the leader.</summary>
  virtual Acm::ErrorStatus setColor(Adesk::Int16 v) = 0;
  ///<summary>Gets the data of the coordinate system.</summary>
  virtual void getCoordSystem(AcGePoint3d&, AcGeVector3d&, AcGeVector3d&, AcGeVector3d&) const = 0;

  ///<summary>Gets the tip point of the leader.</summary>
  virtual AcGePoint3d tipPoint () const = 0;
  ///<summary>Sets the tip point of the leader.</summary>
  virtual Acm::ErrorStatus setTipPoint (const AcGePoint3d& newPt) = 0;
  virtual AcGeVector3d normal() const = 0;
  virtual AcGeVector3d landing() const = 0;
  ///<summary>Sets the landing of the leader.</summary>
  virtual Acm::ErrorStatus setLanding (const AcGeVector3d &landing) = 0;
  ///<summary>Appends a new point to the leader so that its tip will become the new point.</summary>
  virtual Acm::ErrorStatus appendPoint (const AcGePoint3d &endPoint) = 0;
  ///<summary>Appends multiple new points to the leader.</summary>
  virtual Acm::ErrorStatus appendPoints (const AcGePoint3dArray &endPoint) =0;
  ///<summary>Checks whether the tip point can be removed, and if yes, removes just the tip point of the current leader.</summary>
  virtual Acm::ErrorStatus removePoint () = 0;
  ///<summary>Gets the distance from the tip point, which is not drawn.</summary>
  virtual Acm::ErrorStatus getNonDrawingDistance (double& v) const = 0;
  ///<summary>Sets the distance from the tip point, which is not drawn.</summary>
  virtual Acm::ErrorStatus setNonDrawingDistance (double v) = 0;


  ///<summary>Returns objects for working with the internal leader structure.</summary>
  virtual AcmCLeaderNodeIterator* newNodeIterator() const = 0;

  ///<summary>Gets the snap points of the leader.</summary>
  virtual Acad::ErrorStatus   getOsnapPoints(
				 AcDb::OsnapMode     osnapMode,
				 INT_PTR             gsSelectionMark,
				 const AcGePoint3d&  pickPoint,
				 const AcGePoint3d&  lastPoint,
				 const AcGeMatrix3d& viewXform,
				 AcGePoint3dArray&   snapPoints,
				 AcDbIntArray&       geomIds) const = 0;

  ///<summary>Returns the total number of points directly or indirectly connected to this node.</summary>
  virtual int numOfGripPoints() const = 0;
  ///<summary>Gets the grip points of the leader.</summary>
  virtual Acad::ErrorStatus getGripPoints(AcGePoint3dArray& gripPoints,
			AcDbIntArray& osnapModes,
			AcDbIntArray& geomIds) const = 0;
  virtual Acad::ErrorStatus moveGripPointsAt(const AcDbIntArray& indices,
			const AcGeVector3d& offset) = 0; 
  ///<summary>Moves the stretched points of the leader.</summary>
  virtual Acad::ErrorStatus moveStretchPointsAt(const AcDbIntArray& indices,
                                                const AcGeVector3d& offset) = 0;

  virtual Acad::ErrorStatus moveGripPoint(const AcmSymGripInfo* grip, const AcGeVector3d& offset) = 0;
  virtual Acad::ErrorStatus transformBy(const AcGeMatrix3d& trans) = 0;

  ///<summary>Returns the total number of lines directly or indirectly connected to this node. 
  ///This number can be used to calculate GS marker range. This function can be used to check if the 
  ///incoming GS marker corresponds to any line in the leader. If the symbol has more than one leader, 
  ///the next one will start with the last GS marker increased by one. Then for the first one this member 
  ///function will return Adesk::kFalse. Then the number of markers in the first leader will decrease the 
  ///marker value and the member function will be called for next leader. This calculation is the responsibility
  ///of the container class - a symbol implementation.</summary>
  virtual INT_PTR numOfGsMarkers() const = 0;

  ///<summary>Gets the segment from the GS marker.</summary>
  virtual Acm::ErrorStatus getSegFromGSMarker(INT_PTR marker, AcmCAuxEntity*&) const = 0;

  ///<summary>Creates a geometry reference for the leader arrowhead and changes its position to the 
  ///newArrowHeadLocation point. The geometry reference is associated with the drawing view. All necessary
  ///notifications are going from that view.</summary>
  ///<param name="pGeometry"></param>
  ///<param name="view">Optional. If not specified, this function is used to attach the leader in the model space.</param>
  ///<param name="prevLocation"></param>
  ///<param name="hasReactor"></param>
  virtual Acm::ErrorStatus attachGeomRef(const void* pGeometry,
                                         const AcDbObjectId& view,
                                         const AcGePoint3d& prevLocation , // this parameter is used as arrowhead location
                                         Adesk::Boolean hasReactor = Adesk::kFalse) = 0;

  ///<summary>Creates a geometry reference for the leader arrowhead and changes its position to the 
  ///newArrowHeadLocation point. The geometry reference is associated with the drawing view. All necessary 
  ///notifications are going from that view.</summary>
  ///<param name="pGeometry"></param>
  ///<param name="prevLocation"></param>
  ///<param name="hasReactor"></param>
  virtual Acm::ErrorStatus attachGeomRef(const void* pGeometry,
                                         const AcGePoint3d& prevLocation , // this parameter is used as arrowhead location
                                         Adesk::Boolean hasReactor = Adesk::kFalse) = 0;
  ///<summary>Detaches all geometry references.</summary>
  virtual Acm::ErrorStatus detachGeomRef() = 0;
  ///<summary>Releases all geometry references.</summary>
  virtual void releaseGeomRef() = 0;

  virtual Acad::ErrorStatus dwgInFields (AcDbDwgFiler* filer, Adesk::UInt16) = 0;
  virtual Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const = 0;
  virtual Acad::ErrorStatus dxfInFields (AcDbDxfFiler* filer) = 0;
  virtual Acad::ErrorStatus dxfOutFields(AcDbDxfFiler* filer) const = 0;
  virtual Acad::ErrorStatus varInFields(const AcmVariant* pVar, AcRxObject* pFiler = nullptr) = 0;
  virtual Acad::ErrorStatus varOutFields(AcmVariant* pVar, AcRxObject* pFiler = nullptr) const = 0;


  virtual Acm::ErrorStatus getTrueColor (AcCmColor & color) const = 0; 
  virtual Acm::ErrorStatus setTrueColor(const AcCmColor & v) = 0;
  virtual void setArrowheadDir(const AcGeVector3d& vec) = 0;
  virtual AcGeVector3d arrowheadDir() const = 0;
  virtual double arrowScale() const = 0;
  virtual void setArrowScale(double scale) = 0;
  virtual AcmSymbol* getOwner() const = 0;
};

inline
AcmCLeader::~AcmCLeader()
{
}

///<summary>This abstract class is very important for specialized leader operations. It allows you to walk
///through any possible leader implementations and simplify the interface.</summary>
class ACMSYMBB_CRX_DLLSHARE AcmCLeaderNodeIterator
{
  public :
///<summary>Destructures the leader node iterator class.</summary>
  virtual ~AcmCLeaderNodeIterator();
  ///<summary>Starts the walk-through of the leader node iterator.</summary>
  ///<param name="onlyleafNodes">Specifies whether you're interested just in leaf nodes. If yes, you cannot
  ///add a new node, but you can remove a node.</param>
  virtual void start(Adesk::Boolean onlyLeafNodes = Adesk::kFalse) = 0;
  ///<summary>Step backward or forward the walk-through of the leader node iterator.</summary>
  ///<param name="backwards">Specifies whether to step backward or forward.</param>
  virtual void step( Adesk::Boolean backwards = Adesk::kFalse) = 0;
  ///<summary>Checks whether to go up through the parent object.</summary>
  virtual Adesk::Boolean parent() = 0;
  ///<summary>Checks whether all nodes have been walked through.</summary>
  virtual Adesk::Boolean done() const = 0;

  ///<summary>Finds the node with vertex that is the same as the one specified.</summary>
  virtual Acm::ErrorStatus find(const AcGePoint3d& pt, bool fromTipPoint = true)=0;
  ///<summary>Finds the node that is closest to the specified point in the leader's plane.</summary>
  virtual Acm::ErrorStatus findClosest(const AcGePoint3d& pt)=0;
  ///<summary>Finds the node using its grip index.</summary>
  virtual Acm::ErrorStatus findByGrip(int indice)=0;

  ///<summary>Checks whether it is a leaf node.</summary>
  virtual Adesk::Boolean isLeafNode() const = 0;
  ///<summary>Creates the leader iterator, which will iterate through the leader segment connected to this node.</summary>
  virtual AcmCLeaderNodeIterator* newNodeIterator(int branch) const = 0;
  ///<summary>Returns the number of branches.</summary>
  virtual int numOfBranches() const = 0;
  ///<summary>Trims all connected nodes and makes the current node a leaf node.</summary>
  virtual Acm::ErrorStatus trim() = 0;
  ///<summary>Creates a new leader segment connected to the current node using the supplied points.</summary>
  virtual Acm::ErrorStatus addLeader(const AcGePoint3dArray &ptrArray) = 0;
  ///<summary>Removes the leader connected to the node.</summary>
  virtual Acm::ErrorStatus removeLeader() = 0;
  ///<summary>Inserts the node before the current node.</summary>
  virtual Acm::ErrorStatus insertBefore(const AcGePoint3d &pt) = 0;
  ///<summary>Removes the current node from the node structure.</summary>
  virtual Acm::ErrorStatus remove() = 0;
  ///<summary>Gets the vertex point of the node.</summary>
  virtual AcGePoint3d vertex() const = 0;
  ///<summary>Gets the vertex point of the node.</summary>
  virtual Acm::ErrorStatus setVertex(const AcGePoint3d& newPoint) =0;
  virtual Acad::ErrorStatus transformBy(const AcGeMatrix3d& trans) = 0;

  ///<summary>Gets the status information about current attachments. If it is called for a non-leaf node, 
  ///it will return an error code.</summary>
  ///<param name="viewId">Optional.</param>
  virtual Adesk::Boolean isAttachedToView(AcDbObjectId& viewId) const = 0;
  virtual Adesk::Boolean isAttachedNoView() const = 0;
  ///<summary>Gets the id of the view the node is associated to.</summary>
  virtual AcDbObjectId viewId() const = 0;

  ///<summary>Creates a geometry reference.</summary>
  ///<param name="view">Optional. If not specified, this function is used to attach the leader node in the model space.</param>
  ///<param name="prevLocation"></param>
  ///<param name="hasReactor"></param>
  virtual Acm::ErrorStatus attachGeomRef(const void* pGeometry,
                                         const AcDbObjectId& view,
                                         const AcGePoint3d& prevLocation, //this parameter is used as arrowhead location,
                                         Adesk::Boolean hasReactor = Adesk::kFalse) = 0;

  ///<summary>Creates a geometry reference.</summary>
  virtual Acm::ErrorStatus attachGeomRef(const void* pGeometry,
                                         const AcGePoint3d& prevLocation, //this parameter is used as arrowhead location,
                                         Adesk::Boolean hasReactor = Adesk::kFalse) = 0;
  ///<summary>Detaches all geometry references.</summary>
  virtual Acm::ErrorStatus detachGeomRef() = 0;
  ///<summary>Releases all geometry references.</summary>
  virtual void releaseGeomRef() = 0;
};

inline
AcmCLeaderNodeIterator::~AcmCLeaderNodeIterator()
{
}

#endif // _LEADER_H
