//////////////////////////////////////////////////////////////////////////////
//
//  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.   
//
//////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "resource.h"

//AcadM
//////////////////////////////////////////////////////////////////////////
//You must add the following lines before including the "acm.h" file
//1. import defines for AmgDim crx module 
#define ACMSYMBB_CRX_DLLSHARE
#define ACMSYMBB_CRX_DLLSHARE_DATA __declspec(dllimport)
//2. declare new DbRef define
#undef  DBREF_DECLARE
#define DBREF_DECLARE(AcDbType)

#include "acm.h"
//////////////////////////////////////////////////////////////////////////
#include "acmdef.h"
#include "cauxent.h"
#include "SYMBOL.h"
#include "stdmgr.h"
#include "symstd.h"
#include "DetailSym.h"
#include "axobjref.h "

Acad::ErrorStatus postToDb(AcDbEntity* ent, AcDbObjectId& objId);

// Check current space is paper space or model space
Adesk::Boolean isPspace()
{
  if (acdbHostApplicationServices()->workingDatabase()->tilemode()){
    return Adesk::kFalse;
  }

  struct resbuf cvport ;
  acedGetVar(_T(/*MSG0*/"CVPORT"),&cvport);
  return (cvport.resval.rint == 1);
}

// Set properties of detail symbol
void setDetailSymbol(AmdtDetailSym* pDetail)
{
  // Set detail scale
  pDetail->setDetailScale(3);

  // Set label name
  pDetail->setLabelName(_T("TB"));

  // Set label pattern
  pDetail->setLabelPattern(_T("=<DETAIL_LABEL> (<DETAIL_SCALE>) (<DETAIL_ABSSCALE>)"));

  // Set detail space
  if (isPspace())
    pDetail->setDetailSpace(1);
  else
    pDetail->setDetailSpace(0); 
}

// Set properties of detail symbol label
void setDetailSymbolLabel(AmdtDetailSymLabel* pDetailLabel)
{
  // Toggle label above
  if (pDetailLabel->labelAbove() == Adesk::kFalse){
    pDetailLabel->setLabelAbove(Adesk::kTrue);
  }
  else{
    pDetailLabel->setLabelAbove(Adesk::kFalse);
  }
}

// Create a detail symbol entity and its symbol label entity
void createDetailSymbol()
{
  // Select source geometry
  AcDbObjectId id;
  ads_name eName;
  AcGePoint3d pt;

  // Get an entity by calling acedEntSel command, which is used to assigning geometry for detail symbol object 
  int rc = acedEntSel(_T(/*MSG0*/"Select object: "), eName, asDblArray(pt));
  if (rc != RTNORM)
    return;
  
  // Get selected object id
  if (acdbGetObjectId(id, eName) != Acad::eOk)
    return;

  AcDbEntity* pSourceGeom = NULL;
  if (acdbOpenObject(pSourceGeom, id, AcDb::kForWrite) != Acad::eOk)
    return;
  
  // Check the selected entity is a curve
  if (!pSourceGeom->isKindOf(AcDbCurve::desc()))
    return;

  // Create detail symbol object
  AmdtDetailSym* pDetailSym = new AmdtDetailSym();

  // Set all properties to default
  if (pDetailSym->setSymbolDefaults() != Acm::eOk) {
    delete pDetailSym;
    return;
  }

  // Prepare mSourceGeom from an existing geometry
  pDetailSym->makeSourceGeom(AcDbCurve::cast(pSourceGeom));
  pSourceGeom->close();

  // Add detail symbol object to database
  AcDbObjectId objId;
  if (postToDb(pDetailSym, objId) != Acad::eOk) {
    delete pDetailSym;
    return;
  }

  // Get transformation matrix to go from UCS to WCS coordinates
  AcGeMatrix3d currUCS(AcGeMatrix3d::kIdentity);
  acdbUcsMatrix(currUCS);
  AcGePoint3d center;

  // Get a point as the center of detail symbol label
  if (acedGetPoint(NULL, _T("\nCenter point for detail Sym: "), asDblArray(center)) != RTNORM) {
    delete pDetailSym;
    return;
  }

  // Get the scale of detail symbol
  double detailScale;
  if (acedGetDist(asDblArray(center), _T("\nScale: "), &detailScale) != RTNORM) {
    delete pDetailSym;
    return;
  }
  // Set scale of detail symbol
  pDetailSym->setDetailScale(detailScale);

  // Create label entity. Set coordinates and label name

  // Transform matrix to go from UCS to WCS coordinates
  center.transformBy(currUCS);
  
  // Create an AmdtDetailSymLabel object
  if (pDetailSym->makeLabelEnt(center, NULL, NULL) != Acad::eOk) {
    pDetailSym->close();
    return;
  }
  
  // Set label name
  pDetailSym->setLabelName(_T("TA"));

  pDetailSym->close();
}

void modifyDetailSymbol()
{
  AcDbObjectId id;
  ads_name eName;
  AcGePoint3d pt;

  // Get an entity by calling acedEntSel command
  int rc = acedEntSel(_T(/*MSG0*/"Select object :"),eName,asDblArray(pt));
  if ((rc == RTERROR) || (!eName))
    return;

  if (rc != RTNORM)
    return;

  // Get object id by its SS name
  if (acdbGetObjectId(id,eName) != Acad::eOk)
    return;
  
  AcDbObjectPointer<AcDbEntity> pEntity(id, AcDb::kForWrite);
  if (Acad::eOk != pEntity.openStatus()) {
    return;
  }
  
  AmdtDetailSym* pDetailSym;
  AmdtDetailSymLabel* pDetailLabel;
  if(pEntity->isKindOf(AmdtDetailSym::desc())){
    // The selected entity is a AmdtDetailSym
    pDetailSym = AmdtDetailSym::cast(pEntity);
    if (pDetailSym) {
      // Set properties of detail symbol
      setDetailSymbol(pDetailSym);
    }
  }
  else if (pEntity->isKindOf(AmdtDetailSymLabel::desc())){
    // The selected entity is a AmdtDetailSymLabel
    pDetailLabel = AmdtDetailSymLabel::cast(pEntity);
    if (pDetailLabel) {
      // Set properties of detail label
      setDetailSymbolLabel(pDetailLabel);
    }
  }
  else{
    // The entity selected is not a AmdtDetailSym or a AmdtDetailSymLabel
    acutPrintf(_T("\nThe entity selected is not a Detail symbol or Label."));
  }
}

void editDetailSymStd()
{
  // Get current standard from standard manager.
  AcDbObjectId curStdId;
  acmStdMgr->getCurrent(curStdId);

  // Get the detail symbol standard from current standard
  const AcDbObjectPointer<AcmStandard> pStd(curStdId, AcDb::kForRead);
  if (Acad::eOk != pStd.openStatus()) 
    return;

  AcDbObjectId detailSymStdId;  
  if (Acad::eOk != pStd->getCurrentSymbolStd(_T("AmdtDetailSymStd"), detailSymStdId)) {
    return;
  }

  // Open detail symbol standard object for write.
  AcDbObjectPointer<AmdtDetailSymStd> pDetailSymStd(detailSymStdId, AcDb::kForWrite);
  if (Acad::eOk != pDetailSymStd.openStatus()) {
    return;
  }

  // Set label pattern name
  pDetailSymStd->setLabelPattern(_T("=<DETAIL_LABEL> [<DETAIL_SCALE>] (<DETAIL_ABSSCALE>)"));

  // Set label position
  pDetailSymStd->setLabelAbove(Adesk::kFalse);

  // Set show border
  pDetailSymStd->setShowBorder(Adesk::kTrue);

  // Set show leader
  pDetailSymStd->setShowAnnotLeader(Adesk::kTrue);

}

Acad::ErrorStatus postToDb(AcDbEntity* ent, AcDbObjectId& objId)
{
  Acad::ErrorStatus      es;
  AcDbBlockTable*        pBlockTable;
  AcDbBlockTableRecord*  pSpaceRecord;

  if ((es = acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead)) != Acad::eOk) return es;

  //  Determine appropriate space from AutoCAD core function isPspace()
  if ((es = pBlockTable->getAt(ACDB_MODEL_SPACE,pSpaceRecord, AcDb::kForWrite)) != Acad::eOk) return es;
  if ((es = pBlockTable->close()) != Acad::eOk) return es;
  if ((es = pSpaceRecord->appendAcDbEntity(objId, ent)) != Acad::eOk) return es;
  // be carefull, entity remains opened.
  return pSpaceRecord->close();
}