//////////////////////////////////////////////////////////////////////////////
//
//  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 __ACMDEF_H
#define __ACMDEF_H

#ifndef __ACM_H
	#error include 'acm.h' before including this file
#endif

/////////////////////////////////////////////////////////////////////
// acmdef.h
//
// AcmCObjArray    : template class holds pointers to data and
//                   destruct them if it's necessary. You should not
//                   care about deleting items
//
// AcmCObjPtrArray : template class holds pointers to data don't
//                   desctruct containing objects. You must care
//                   delete about deleting items
//
// AcmCDesc          : base class for symbol descriptors
// AcmCArrowDesc     : descriptor class for arroheads
// AcmCSymbolDesc    : descriptor class for symbol types
// AcmCGDTSymbolDesc : descriptor class for GDT symbol types
//
/////////////////////////////////////////////////////////////////////

template<class TClass>
///<summary>Template class holds pointers to data and destroys them if necessary. You should not care about deleting items</summary>
class AcmCObjArray : public AcArray<TClass*>
{
public:
  AcmCObjArray<TClass>(int initPhysicalLength = 0, int initGrowLength = 8);
  // we need virtual destructor, since we sometime need to override
  // this class
  virtual ~AcmCObjArray<TClass>();

  int                   append (TClass* value);

  // need to modify behavior - need to delete first.
  AcmCObjArray<TClass>& setAt(int i, TClass* value);
  AcmCObjArray<TClass>& removeAt(int);
  AcmCObjArray<TClass>& removeFirst();
  AcmCObjArray<TClass>& removeLast();
  AcmCObjArray<TClass>& setLogicalLength(int);

private:
  // these must not be used !!!
  AcmCObjArray<TClass>(const AcmCObjArray<TClass>&);
  AcmCObjArray<TClass>& operator = (const AcmCObjArray<TClass>&);
  AcmCObjArray<TClass>& append (const AcmCObjArray<TClass>& array);
};

template<class TClass>
inline AcmCObjArray<TClass>::AcmCObjArray(int initPhysicalLength/* = 0*/, int initGrowLength/* = 8*/)
:	AcArray<TClass*>(initPhysicalLength,initGrowLength)
{
}

template<class TClass>
inline AcmCObjArray<TClass>::~AcmCObjArray()
{
  setLogicalLength(0);
}

template<class TClass>
inline AcmCObjArray<TClass>::AcmCObjArray(const AcmCObjArray<TClass>& src)
{ 
  assert(0);
}

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::operator = (const AcmCObjArray<TClass>&)
{ 
  assert(0);
  return *this; 
}

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::append (const AcmCObjArray<TClass>& array)
{	assert(0); return *this;}


template<class TClass>
inline int
AcmCObjArray<TClass>::append(TClass* value)
{ 
  return AcArray<TClass*>::append(value);
}

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::setAt(int i, TClass* value)
{
  delete this->at(i);   // delete NULL is ok.
  AcArray<TClass*>::setAt(i, value);
  return *this;
}

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::removeAt(int i)
{
  TClass *c= this->at(i);
  if( NULL != c ) delete c;
  AcArray<TClass*>::removeAt(i);
  return *this;
}

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::removeFirst()
{ return removeAt(0); }

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::removeLast()
{ 
  return removeAt(this->logicalLength()-1);
}

template<class TClass>
inline AcmCObjArray<TClass>&
AcmCObjArray<TClass>::setLogicalLength(int newLen)
{
  TClass *c;
  if( newLen == this->length() ) return *this;

	if( newLen < this->length() ) {
    for(int i = this->length()-1; i>=newLen; i--){
      c = this->at(i);
      if( NULL != c ) delete c;
    }
    AcArray<TClass*>::setLogicalLength(newLen);
  }
	else {
    int oldLen = this->length();
    AcArray<TClass*>::setLogicalLength(newLen);
    if (oldLen == 0) {
      this->setAll(NULL);
    }
    else {
      for(int i = oldLen; i < this->length(); i ++)
        AcArray<TClass*>::setAt(i,NULL);
    }
  }
  return *this;
}

template<class TClass>
///<summary>Template class holds pointers to data. Doesn?t destroy containing objects. You must handle deleting objects.</summary>
class AcmCObjPtrArray : public AcArray<TClass*>
{
};
///<summary>This class and its successors (AcmCArrowDesc, AcmCSymbolDesc, AcmCGDTSymbolDesc) are used to transfer symbol dialog descriptors. 
///It is its bitmap and description. Some of them use the internal integer variable for storing their private data.</summary>
class AcmCDesc
{
public:
  AcmCDesc();
  virtual ~AcmCDesc();
  HBITMAP bitmap() const;
  void    setBitmap(HBITMAP bitmap, bool isCached = false);
  LPCTSTR description() const;
  void    setDescription(LPCTSTR description);
  int  info() const;
  void setInfo(int value);

private:
  HBITMAP mBitmap;
  CString mDescription;
  bool    mIsBitmapCached{ false };

protected:
  int mInfo;
};

inline
AcmCDesc::AcmCDesc()
: mBitmap(NULL),mInfo(0)
{}

inline
AcmCDesc::~AcmCDesc()
{
    //if bitmap is cached by the AcmCService ( like AcmCArrowService) we dont want to delete it here,
    //The service will take care of clearing the memory later.
    if (!mBitmap || mIsBitmapCached) 
        return;

    ::DeleteObject(mBitmap);
}

inline HBITMAP
AcmCDesc::bitmap() const
{ return mBitmap; }

inline void
AcmCDesc::setBitmap(HBITMAP bitmap, bool isCached)
{ 
    mBitmap = bitmap; 
    mIsBitmapCached = isCached;
}

inline LPCTSTR
AcmCDesc::description() const
{ return (LPCTSTR)mDescription; }

inline void
AcmCDesc::setDescription(LPCTSTR description)
{ mDescription = description; }

inline int
AcmCDesc::info() const
{ return mInfo; }

inline void
AcmCDesc::setInfo(int value)
{ mInfo = value; }

//////////////////////////////////////////////////////////////////////////
///<summary>descriptor class for arrowheads</summary>
class AcmCArrowDesc : public AcmCDesc
{
public:
  AcmCArrowDesc();
  Acm::ArrowType type() const;
  void setType(Acm::ArrowType type);
  bool isSmallIcon() const;
  void setIsSmallIcon(bool bSmall);
private:
  bool m_bSmallIcon;
};

inline AcmCArrowDesc::AcmCArrowDesc()
: AcmCDesc(), m_bSmallIcon(false){}

inline Acm::ArrowType
AcmCArrowDesc::type() const
{ return (Acm::ArrowType)mInfo; }

inline void
AcmCArrowDesc::setType(Acm::ArrowType type)
{ mInfo = (int)type; }

inline bool
AcmCArrowDesc::isSmallIcon() const
{
  return m_bSmallIcon;
}

inline void
AcmCArrowDesc::setIsSmallIcon(bool bSmall)
{
  m_bSmallIcon = bSmall;
}

//////////////////////////////////////////////////////////////////////////
///<summary>A descriptor class for symbol types.</summary>
class AcmCSymbolDesc : public AcmCDesc
{
public:
  AcmCSymbolDesc();
  Adesk::Boolean offered() const;
  void setOffered(Adesk::Boolean check);
  ///<summary>Get the display order index of the symbol.</summary>
  int displayListIndex() const;
  ///<summary>Set the display order index of the symbol.</summary>
  void setDisplayListIndex(int newIndex);

  Acm::SubSymbolType type() const;
  void               setType(Acm::SubSymbolType type);

private:
  Adesk::Boolean mOffered;
  int mDisplayListIndex;
};

inline
AcmCSymbolDesc::AcmCSymbolDesc()
: mOffered(Adesk::kFalse),
  mDisplayListIndex(-1)
{}

inline Adesk::Boolean
AcmCSymbolDesc::offered() const
{ return mOffered; }

inline void
AcmCSymbolDesc::setOffered(Adesk::Boolean check)
{ mOffered = check; }

inline int
AcmCSymbolDesc::displayListIndex() const
{
  return mDisplayListIndex;
}

inline void
AcmCSymbolDesc::setDisplayListIndex(int newIndex)
{
  mDisplayListIndex = newIndex;
}

inline	Acm::SubSymbolType
AcmCSymbolDesc::type() const
{ return (Acm::SubSymbolType)mInfo; }

inline void
AcmCSymbolDesc::setType(Acm::SubSymbolType type)
{ mInfo = (int)type; }

//////////////////////////////////////////////////////////////////////////
///<summary>descriptor class for base symbol types used by CLI.</summary>
class AcmSymbolDesc4CL : public AcmCSymbolDesc
{
public:
    void setKeyword(AcString key);
    AcString getKeyword() const;

    void setPrompt(Adesk::UInt64);
    Adesk::UInt64 getPrompt() const;

public:
    AcString mKeyword;
    Adesk::UInt64 mPrompt{ 0 };
};

inline void
AcmSymbolDesc4CL::setKeyword(AcString key)
{
    mKeyword = key;
}

inline AcString
AcmSymbolDesc4CL::getKeyword() const
{
    return mKeyword;
}

inline void
AcmSymbolDesc4CL::setPrompt(Adesk::UInt64 Id)
{
    mPrompt = Id;
}

inline Adesk::UInt64
AcmSymbolDesc4CL::getPrompt() const
{
    return mPrompt;
}

//////////////////////////////////////////////////////////////////////////
///<summary>descriptor class for GDT symbol types.</summary>
class AcmCGDTSymbolDesc : public AcmSymbolDesc4CL
{
public:
  Acm::GdtSymbolType type() const;
  void               setType(Acm::GdtSymbolType type);

private:
    Adesk::UInt64 mOpmPrompt;
};

inline	Acm::GdtSymbolType
AcmCGDTSymbolDesc::type() const
{return (Acm::GdtSymbolType)mInfo; }

inline void
AcmCGDTSymbolDesc::setType(Acm::GdtSymbolType type)
{ mInfo = (int)type; }

//////////////////////////////////////////////////////////////////////////
///<summary>descriptor class for GDT symbol types.</summary>
class AcmCGDTIndicatorDesc : public AcmSymbolDesc4CL
{
public:
    Acm::GdtIndicatorType type() const;
    void               setType(Acm::GdtIndicatorType type);

private:
    Adesk::UInt64 mOpmPrompt;
};

inline	Acm::GdtIndicatorType
AcmCGDTIndicatorDesc::type() const
{
    return (Acm::GdtIndicatorType)mInfo;
}

inline void
AcmCGDTIndicatorDesc::setType(Acm::GdtIndicatorType type)
{
    mInfo = (int)type;
}

//////////////////////////////////////////////////////////////////////////
///<summary>This is class AcmCTaperSymbolDesc.</summary>
class AcmCTaperSymbolDesc : public AcmCSymbolDesc
{
public:
  Acm::TaperType    type() const;
  Acm::Orientation  orientation() const;

  void              setType(Acm::TaperType type);
  void              setOrientation(Acm::Orientation type);

private:
    Acm::Orientation mOrientation; ///orientation of taper symbol - define if symbol is flipped or no.
};

inline	Acm::TaperType
AcmCTaperSymbolDesc::type() const
{return (Acm::TaperType)mInfo; }

inline void
AcmCTaperSymbolDesc::setType(Acm::TaperType type)
{ mInfo = (int)type; }

inline	Acm::Orientation
AcmCTaperSymbolDesc::orientation() const
{
    return mOrientation;
}

inline void
AcmCTaperSymbolDesc::setOrientation(Acm::Orientation type)
{
    mOrientation = type;
}

///<summary>This class is used to control the appearance of the dialog for various symbols including surface texture and welding.</summary>
class CVarDlgInfo
{
public:
  ///<summary>the construct function </summary>
  CVarDlgInfo();
  ///<summary>the destruct function</summary>
  virtual ~CVarDlgInfo();
  ///<summary>Gets a help id to be used to get context-sensitive help for the current variable. </summary>
  Adesk::UInt32 helpIndex() const;
  ///<summary>Sets a help id to be used to get context-sensitive help for the current variable. </summary>
  void setHelpIndex(Adesk::UInt32 hlpIdx);

  Adesk::Int16 dlgIndex() const;
  ///<summary>Sets an index being used to edit the specified data in the dialog. </summary>
  void setDlgIndex(Adesk::Int16 dlgIdx);
  ///<summary>Gets a string specifying a tool tip string. </summary>
  LPCTSTR tooltip() const;
  ///<summary>Sets a string specifying a tool tip string. </summary>
  void setTooltip(LPCTSTR str);
  ///<summary>Gets a string specifying the label to be used for the current variable. </summary>
  LPCTSTR label() const;
  ///<summary>Sets a string specifying the label to be used for the current variable. </summary>
  void setLabel(LPCTSTR str);

  CStringList& suggested() const;
  void setSuggested(const CStringList& list);
  ///<summary>Gets whether the specified variable has suggested values. </summary>
  Adesk::Boolean isSuggested() const;

private:
  Adesk::UInt32 mHelpIndex;
  Adesk::Int16  mDlgIndex;
  CString       mTooltip;
  CString       mLabel;
  CStringList   mSuggested;     // keep list of suggested values
};

inline
CVarDlgInfo::CVarDlgInfo()
: mHelpIndex(0), mDlgIndex(-1), mSuggested()
{}

inline
CVarDlgInfo::~CVarDlgInfo()
{}

inline Adesk::UInt32
CVarDlgInfo::helpIndex() const
{ return mHelpIndex; }

inline void
CVarDlgInfo::setHelpIndex(Adesk::UInt32 hlpIdx)
{ mHelpIndex = hlpIdx; }

inline Adesk::Int16
CVarDlgInfo::dlgIndex() const
{ return mDlgIndex; }

inline void
CVarDlgInfo::setDlgIndex(Adesk::Int16 dlgIdx)
{ mDlgIndex = dlgIdx; }

inline LPCTSTR
CVarDlgInfo::tooltip() const
{ return (LPCTSTR)mTooltip; }

inline void
CVarDlgInfo::setTooltip(LPCTSTR str)
{ mTooltip = str; }

inline LPCTSTR
CVarDlgInfo::label() const
{ return (LPCTSTR)mLabel; }

inline void
CVarDlgInfo::setLabel(LPCTSTR str)
{ mLabel = str; }

inline CStringList&
CVarDlgInfo::suggested() const
{ return (CStringList&) mSuggested; }

inline void
CVarDlgInfo::setSuggested(const CStringList& list)
{
  INT_PTR i, count = list.GetCount();
  for (i=0; i<count; i++)
    mSuggested.AddTail(list.GetAt(list.FindIndex(i)));
}

inline Adesk::Boolean
CVarDlgInfo::isSuggested() const
{
  return (!mSuggested.IsEmpty());
}
///<summary>This is class CSymStdTreeItemDesc.</summary>
class CSymStdTreeItemDesc
{
public:
  ///<summary>the destruct function </summary>
  virtual ~CSymStdTreeItemDesc();
  virtual CBitmap* GetIcon() const = 0;
  virtual void GetItemText(CString& str) const = 0;
  virtual Acm::ErrorStatus getRevision(CString& rev,
                                       Adesk::UInt16& year) const = 0;

  virtual BOOL OnProperties(CWnd* parentWindow) const = 0;
  ///<summary>Supports finer granularity for applying factory defaults.
  ///It was added mainly for use with AcmCPartListStd and AcmCBalloonStd, 
  ///but it can be used in any symbol standard that implements more than one symbol. </summary>
  virtual BOOL OnFactoryDefaults() = 0;
};

inline
CSymStdTreeItemDesc::~CSymStdTreeItemDesc()
{}

#endif //__ACMDEF_H