//////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2025 by Autodesk, Inc.  All rights reserved.
//
// This computer source code and related instructions and comments 
// are the unpublished confidential and proprietary information of 
// Autodesk, Inc. and are protected under applicable copyright and 
// trade secret law.  They may not be disclosed to, copied or used 
// by any third party without the prior written consent of Autodesk, Inc.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef __TAPERSYM_H
#define __TAPERSYM_H

class AcmSymbolStd;
class AcmTaper;
class AcmCTaper;
class AcmCTaperImp;
class AcmTaperStdImp;
class AcmValue;
class AcmCAttach;
class AcDbLine;
class AcmCAttachTaperBaseline;
class AcmCAttachCurve;
class AcmTaperStdRev;

///<summary>This existing class is the class for taper standard object.</summary>
class ACMSYMBB_CRX_DLLSHARE AcmTaperStd : public AcmSymbolStd
{
  friend class AcmSymbbInternals;
  friend class AcmTaperStdRev;

public:
  ACRX_DECLARE_MEMBERS(AcmTaperStd);

  AcmTaperStd();
  virtual ~AcmTaperStd();

  const ACHAR* getBaseSymStdClassName() const override;
  void getOfferedSymbols(AcDbIntArray& array) const;

  ///<summary>This function is used to get preferred dimension type by current taper standard, user have to 
  ///free returned separator.</summary>
  ///<param name="dimType">Output only. Returns the dimension type.</param>
  ///<param name="fract"></param>
  ///<param name="separator">All alpha-numeric characters including spaces are accepted as valid separators. 
  ///The default separator is a colon ':'.</param>
  void getDimensionType(Acm::TaperDimensionType& dimType, Acm::TaperRatioFormat& fract, ACHAR*& separator) const;

  ///<param name="">This function is used to set preferred dimension type by current taper standard.</param>
  ///<param name="dimType">Output only. Returns the dimension type.</param>
  ///<param name="fract"></param>
  ///<param name="separator">All alpha-numeric characters including spaces are accepted as valid separators. 
  ///The default separator is a colon ':'.</param>
  void setDimensionType(const Acm::TaperDimensionType dimType, const Acm::TaperRatioFormat fract, const ACHAR* separator);

  ///<summary>Sets the factory default values.</summary>
  virtual Adesk::Boolean setFactoryDefaults();
  virtual void setDefaultSubSymbol(AcmCTaper* pData) const;
  virtual Acm::ErrorStatus checkVisibility(AcmCTaper* pData) const;
  virtual Acm::ErrorStatus getDescription(CString& desc,
    CBitmap*& pBmpLoaded,
    CBitmap*& pBmpReg,
    Adesk::Boolean& enablePref) const;
  virtual Adesk::Boolean getSymbolList(AcmCObjArray<AcmCTaperSymbolDesc>& list,
    const AcmCTaper* pSubSym =NULL) const;
  virtual void getSubEnts(const AcmCTaper* pSymb,
    AcmCAuxEntArray& subents) const;

  Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer) override;
  Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const override;

  ///<summary>This function is used to set default offered symbols.</summary>
  void setDefaultOfferedSymbols();

  /// <summary>
  /// Function returns keyword and prompt for particular taper descriptor.
  /// </summary>
  /// <param name="desc"> descriptor of taper type</param>
  /// <param name="prompt"> output prompt for CLI or OPM</param>
  /// <param name="keyword"> output keyword for CLI </param>
  /// <param name="bCLVersion"> desides if we return the prompt for CLI or OPM </param>
  ///
  virtual void getPromptKeyword(const AcmCTaperSymbolDesc& desc, Adesk::UInt64& prompt, AcString& keyword, bool bCLVersion = true) const;

enum OfferedSymType
{
  ///<summary>Contains both taper and slope type</summary>
  kAllType,
  ///<summary>Contains only taper type</summary>
  kTaperType,
  ///<summary>Contains only slope type</summary>
  kSlopeType
};
///<summary>This function is used to get default offered symbols according to different TaperSlopeType.</summary>
///<param name="symbols">Return the required symbol types.</param>
///<param name="type">Set the taper slope type that user wants to get. The default value is AcmTaperStd::kAllType. 
///Other two options are AcmTaperStd::kTaperType and AcmTaperStd::kSlopeType.</param>
  virtual void getDefaultOfferedSymbols(AcDbIntArray& symbols,const AcmTaperStd::OfferedSymType type = AcmTaperStd::kAllType) const;

  const ACHAR* getBaseRevClassName() const override;

  Acad::ErrorStatus copyFrom(const AcRxObject* other) override;

  
protected:
  virtual Acad::ErrorStatus subGetClassID(CLSID* pClsid) const;

  void setOfferedSymbols(const AcDbIntArray& array);

  AcmTaperStdImp* getTaperStdImpl() const;
  AcmTaperStdRev* getTaperRevObj() const;
  
private:
  AcmTaperStdImp* mpImp;
};
DBREF_DECLARE(AcmTaperStd)

///<summary>This is class AcmCTaper.</summary>
class AcmCTaper : public AcmCSubSymbol
{
public:
  AcmCTaper(AcmTaper* pSym);
  virtual ~AcmCTaper();

  // Copy constructor
  AcmCTaper(const AcmCTaper& other);

  Adesk::Boolean operator==(const AcmCTaper&) const;
  virtual AcmCTaper& operator=(const AcmCTaper&);
  virtual AcmCTaper* clone()const;

  AcmCTaperImp* getImp() const { return mpImp; }

  virtual double subSymAngle() const;
  virtual Acm::ErrorStatus setSubSymAngle(double angle);
  virtual Acm::TaperType subType() const;
  virtual Acm::ErrorStatus setSubType(Acm::TaperType type);
  virtual Acm::Orientation orientation() const;
  virtual Acm::ErrorStatus setOrientation(Acm::Orientation dir);
  virtual Adesk::Boolean isInspect() const;
  virtual Acm::ErrorStatus setInspect(Adesk::Boolean val);
  virtual Adesk::Boolean symAboveCurve() const;
  virtual Acm::ErrorStatus setSymAboveCurve(const Adesk::Boolean lay);
  virtual Adesk::Boolean hasLeader() const;

  virtual const AcmValue* getValue(Acm::Variable var) const;
  virtual AcmValue* getValue(Acm::Variable var);

  virtual Acm::ErrorStatus setPrompt(Acm::Variable var, Adesk::UInt64 id);
  virtual Acm::ErrorStatus setKeyword(Acm::Variable var, const AcString& prompt);

  virtual Acm::ErrorStatus keyword(Acm::Variable var, AcString& keyword) const;
  virtual Acm::ErrorStatus prompt(Acm::Variable var, AcString& keyword) const;
  virtual Acm::ErrorStatus promptID(Acm::Variable var, Adesk::UInt64& id) const;

  AcGePoint3d origin() const override;
  ///<summary>Sets the origin of the symbol in WCS.</summary>
  void setOrigin(const AcGePoint3d& origin) override;
  ///<summary>Gets the value of any symbol variable.</summary>
  LPCTSTR value(Acm::Variable var) const override;
  ///<summary>Gets the value of any symbol variable.</summary>
  Acm::ErrorStatus getValue(Acm::Variable var, CString& value) const override;
  ///<summary>Sets the value of any symbol variable.</summary>
  Acm::ErrorStatus setValue(Acm::Variable var, LPCTSTR value) override;
  ///<summary>Gets the visibility status of the editing controls.</summary>
  Acm::Visibility  variableStatus(Acm::Variable var) const override;
  ///<summary>Sets the visibility status of the editing controls.</summary>
  Acm::ErrorStatus setVariableStatus(Acm::Variable var, Acm::Visibility status) override;
  ///<summary>Gets the variable support data, such as the help index, dialog index, tooltip string, and label string.</summary>
  Acm::ErrorStatus getVarDlgInfo(Acm::Variable var, CVarDlgInfo& v) const override;
  ///<summary>Sets the variable support data, such as the help index, dialog index, tooltip string, and label string.</summary>
  Acm::ErrorStatus setVarDlgInfo(Acm::Variable var, const CVarDlgInfo& v) override;


  Acad::ErrorStatus dwgInFields(AcDbDwgFiler* filer, Adesk::UInt16 ver) override;
  Acad::ErrorStatus dwgOutFields(AcDbDwgFiler* filer) const override;

  Acad::ErrorStatus varInFields(const AcmVariant* pVar, AcRxObject* pFiler = nullptr) override;
  Acad::ErrorStatus varOutFields(AcmVariant* pVar, AcRxObject* pFiler = nullptr) const override;


  Acad::ErrorStatus dxfInFields(AcDbDxfFiler* filer) override;
  Acad::ErrorStatus dxfOutFields(AcDbDxfFiler* filer) const override;

private:
    AcmCTaperImp* mpImp{ nullptr };
};

///<summary>This is class AcmTaper.</summary>
class ACMSYMBB_CRX_DLLSHARE AcmTaper : public AcmSymbol
{
public:
    ACRX_DECLARE_MEMBERS(AcmTaper);
    ///<summary>This is record AcmTaper::dragType.</summary>
    enum dragType {
    kDefault = 0,
    kAlongCurve,
    kTranslateOnly,
    kRotateOnly
    };
    AcmTaper();
    virtual ~AcmTaper();
  
    Acm::TaperType subType() const;
    Acm::ErrorStatus setSubType(Acm::TaperType flag);
    Acm::Orientation orientation() const;
    Acm::ErrorStatus setOrientation(Acm::Orientation type);
    Adesk::Boolean isInspect() const;
    Acm::ErrorStatus setInspect(Adesk::Boolean val);
    Adesk::Boolean symAboveCurve() const;
    Acm::ErrorStatus setSymAboveCurve(Adesk::Boolean val);
    Acm::ErrorStatus adjustRefline(double angle);
    Acad::ErrorStatus eraseGeomRefs() override;
  
    Acm::ErrorStatus removeBaselineRef(bool bErase = true);
    bool isDimCalculated() const;
    void setDimCalculated(bool bval);
    void updateDimValue(bool useDefaultDimType = false);
    void updateDimString();

// this public part is not used by COM API, these methods are for internal use only
public:
    AcmCTaper* subSymbol() const;
    LPCTSTR value(Acm::Variable var) const;
    Acm::ErrorStatus setValue(Acm::Variable var, LPCTSTR value);
    Acm::Visibility  variableStatus(Acm::Variable var) const;
    Acm::ErrorStatus setVariableStatus(Acm::Variable var, Acm::Visibility status);
    Acm::ErrorStatus getVarDlgInfo(Acm::Variable var, CVarDlgInfo& v) const;
    Acm::ErrorStatus setVarDlgInfo(Acm::Variable var, const CVarDlgInfo& v);
    AcGeVector3d subSymbolNormal() const;
    double subSymAngle() const;
    Acm::ErrorStatus setSubSymAngle(double angle);

    virtual Acad::ErrorStatus autoAdjust();

    AcmCAttachTaperBaseline* baselineRef();
    Acm::ErrorStatus addBaselineRef(AcRfGeom*, const AcGePoint3d&);

    static bool getLine(AcRfGeom* pGeomRef, const AcGePoint3d& pickPoint, AcGeLineSeg3d*& pBaseline);
    static bool getLine(AcmCAttachCurve* pAttach, AcGeLineSeg3d*& pBaseline);
    static double calDimension(const AcGeLineSeg3d* attachLine, const AcGeLineSeg3d* baseline, AcDbObject* pSymbol, bool isTaper, double blineAngle, bool setOrientation = false);
    static double calRefLine(const AcGeLineSeg3d* attachLine, AcGeLineSeg3d* baseline, AcDbObject* pSymbol);
    static double getAngle(const AcGeLineSeg3d* pLine);
    static bool isCenterline(const AcRfGeom* pBaselineRef);

    ///<summary>Uses this overloaded member function to set up a symbol properly.</summary>
    ///<param name="pDb">Pointer to database. Default is NULL, and host databse will be used.</param>
    ///<returns>If successful then Acm::eOk is returned. If the symbol standard is not valid, then Acm::eNotSupported 
    ///is returned.</returns>
    virtual Acm::ErrorStatus setSymbolDefaults(AcDbDatabase* pDb = NULL);

    virtual void setOrigin(const AcGePoint3d& origin);

    ///<summary>Creates a new leader using supplied points.</summary>
    virtual Acm::ErrorStatus addLeader(const AcGePoint3dArray& ptrArray);

    ///<summary>Provides the method for removing the nth- leader in the list.</summary>
    ///<param name="index">Specifies the index in the leader array. If the leader doesn't exist, the function
    ///returns eInvalidInput.</param>
    virtual Acm::ErrorStatus removeLeader(Adesk::UInt16 index);

    ///<summary>This function is called during the updating of symbols that takes place when the standard is changed.</summary>
    virtual void regen();
    ///<summary>Sends a notification if the tip point of the leader has changed.</summary>
    virtual void leaderTipPointChanged(const AcGeVector3d& offset,
        const AcmCLeader* leader);

    using AcmSymbol::transformBy;
    ///<summary>Transforms all leaders. Default implementation doesn't cover any smart behavior.</summary>
    virtual Acad::ErrorStatus transformBy(const AcGeMatrix3d& xform,
        double symbolScale);

    ///<summary>This method mirrors AcmSymbol entity.</summary>
    ///<param name="xMirrorForm">Transformation matrix with MIRROR element</param>
    ///<param name="XAxis">Returns mirrored X-Axis of the entity coordinate system</param>
    ///<param name="YAxis">Returns mirrored Y-Axis of the entity coordinate system</param>
    ///<param name="normal">Returns mirrored Normal of the entity coordinate system</param>
    ///<returns>This virtual method will be called when a transformation matrix with MIRROR element is applied to
    ///AcmSymbol entities (through AcmSymbol ::subTransformBy). Note that AcmCLeader and AcmCAttach objects associated 
    ///with AcmSymbol entities are not affected by this API.The entity coordinate system passed as references to this 
    ///API will be modified by this method to reflect the mirrored entity coordinate system.</returns>
    virtual void mirrorCoordSys(const AcGeMatrix3d& xMirrorForm,
        AcGeVector3d& XAxis,
        AcGeVector3d& YAxis,
        AcGeVector3d& normal) const;

    Acad::ErrorStatus dwgInFields(AcDbDwgFiler*) override;
    Acad::ErrorStatus dwgOutFields(AcDbDwgFiler*) const override;

///////////////////////////////////////////////////////////////////////////////////////
//     Temporary disabled for Xenon
//     //////////////////////////////////////////////////////////////////////////
//     // Attention!!!
//     // All ACM symbols that start to use the new serialization system mustn't override 
//     // the original serialization functions defined by AcDbObject. They can  override 
//     // the serialization function from the AcmSymbol object (original name + postfix _Ext)
// 
//     Acad::ErrorStatus dwgInFields_Ext(AcDbDwgFiler*) override;
//     Acad::ErrorStatus dwgOutFields_Ext(AcDbDwgFiler*) const override;
// 
//     //new serialization system for AcmVariant
//     Acad::ErrorStatus varInFields(const AcmVariant* pVar, AcRxObject* pFiler = nullptr) override;
//     Acad::ErrorStatus varOutFields(AcmVariant* pVar, AcRxObject* pFiler = nullptr) const override;
//     Adesk::Int32 acadmSchemaNumberPerSymbolType(AcDbDwgFiler* pFiler, AcDbDatabase* pDb) const override;
///////////////////////////////////////////////////////////////////////////////////////

    Acad::ErrorStatus dxfInFields(AcDbDxfFiler*) override;
    Acad::ErrorStatus dxfOutFields(AcDbDxfFiler*) const override;

    virtual Adesk::Boolean copyTaperSymProp(const AcmTaper* pSrcSym);
    ///<summary>This function is used to get current selected symbol type(Acm::kTaper1, Acm::kTaper2, Acm::kSlope1
    ///and Acm::kSlope2).</summary>
    Acm::TaperSlopeSymType subSymType() const;
    ///<summary>This function is used to set symbol type by current taper standard.</summary>
    ///<param name="flag">For GB standard it contains all the symbol types. Other standards only contain three 
    ///symbol types except Acm::kTaper2. So for other standards set Acm::kTaper2 will fail.</param>
    Acm::ErrorStatus setSubSymType(Acm::TaperSlopeSymType flag);

    void buildKeywordsAndPrompt(std::vector<std::pair<AcString, AcString>>& output) const;
    Acm::ErrorStatus getVarForKeyword(const AcString& keyword, Adesk::UInt32& var) const;

    ///<summary>The function calls the AcmSymbol::regen function at first and then
    ///update the display string for calculated taper ratio.</summary>
    void regenProperties() override;

protected:
  virtual Adesk::Boolean    subWorldDraw(AcGiWorldDraw*);
  ///<summary>Queries all leaders for their grip points.</summary>
  virtual Acad::ErrorStatus subGetGripPoints(AcGePoint3dArray&,
    AcDbIntArray&,
    AcDbIntArray&) const;
  ///<summary>Queries all leaders for their grip points.</summary>
  virtual Acad::ErrorStatus   subGetGripPoints(AcDbGripDataPtrArray& grips,
    const double curViewUnitSize, 
    const int gripSize, 
    const AcGeVector3d& curViewDir,
    const int bitflags) const;

  ///<summary>Determines the leaders to which indices belong and apply moveGripPointsAt to them. If the tip point
  ///is being edited, then the leaderTipPointChanged() member function of the symbol will be called. If the 
  ///leader contains a landing and it is changed, then the leaderLanding() member function of the symbol is called.</summary>
  virtual Acad::ErrorStatus subMoveGripPointsAt(const AcDbIntArray& indices,
    const AcGeVector3d& offset);

  virtual Acad::ErrorStatus subMoveGripPointsAt(const AcDbVoidPtrArray& gripAppData, 
    const AcGeVector3d& offset, 
    const int bitflags);

  ///<summary>Queries the standard for sub-entities for all leaders and then the server for all sub-entities for
  ///all sub-symbols. All sub-entities are then exploded.</summary>
  virtual Acad::ErrorStatus subExplode(AcDbVoidPtrArray& entitySet) const;
  ///<summary>Sums geometry extents for a leader.</summary>
  virtual Acad::ErrorStatus subGetGeomExtents(AcDbExtents&) const;
  virtual Acad::ErrorStatus subTransformBy(const AcGeMatrix3d& xform); 
  virtual Acad::ErrorStatus subGetClassID(CLSID* pClsid) const;

private:

  double getRefLineLength(bool ignoreFixedLen = false) const;

  AcmCTaper *mpSubSymbol;
};
DBREF_DECLARE(AcmTaper)

#endif // __TAPERSYM_H