//////////////////////////////////////////////////////////////////////////////
//
//  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"

//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 "stdMgr.h"
#include "symstd.h"
#include "symbol.h"
#include "TaperSym.h"
#include "leader.h"

#include "dbobjptr.h"

#include "mibase.h"
#include "migeom.h"
#include "miStatus.h"

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

//MCAD API
AmiStatus amiPick2 ( TCHAR* prompt, AmiKeyType type, struct resbuf* entmask,
                    AmiPickObj& pickObj, Adesk::Boolean allowGhost );
AmiStatus amiGetKeyFromPick ( AmiPickObj* pPickObj, AmiKeyType& type, 
                             AmiObjectKey*& pObjKey );

//get taper and slope symbol standard
Adesk::Boolean
getTaperStandardId(AcDbObjectId& taperStdId)
{
  //get current standard from standard manager.
  AcDbObjectId curStdId;
  acmStdMgr->getCurrent(curStdId);

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

  if (Acad::eOk != pStd->getCurrentSymbolStd(ACRX_T("AcmTaperStd"), taperStdId))
  {
    acutPrintf(ACRX_T("The taper symbol is not supported by %s standard!"), pStd->name());
    return false;
  }

  return true;
}

Adesk::Boolean
setTaperValues(AcmTaper* pTaper)
{
  //set properties for taper symbol

  //get edge symbol standard from standard manager.
  AcDbObjectId taperStdId;
  if(getTaperStandardId(taperStdId) != Adesk::kTrue)
    return Adesk::kFalse;

  //open taper and slope standard object for read.
  AcDbObjectPointer<AcmTaperStd> pTaperStd(taperStdId, AcDb::kForRead);
  if (Acad::eOk != pTaperStd.openStatus()) {
    acutPrintf(ACRX_T("Taper standard can not be opened!\n"));
    return Adesk::kFalse;
  }

  CString taperTypeStr[] = {"Taper 1","Slope 1","Slope 2","Taper 1","Slope 1","Slope 2","Slope 1",
                              "Slope 2","Taper 2","Slope 1","Slope 2"};
  //get all supported taper types from standard
  AcDbIntArray symbols;
  pTaperStd->getOfferedSymbols(symbols);
  //printout tapers selection
  for(int i = 0; i < symbols.length();i++){
    if(symbols[i] == 1)
      acutPrintf(_T("\n%3d: %s"),i,taperTypeStr[i]);
  }

  int selectedSubType = 0;
  int rc = RTNORM;
  do{
    acutPrintf(_T("\n\nSelect taper type <%2d>: "), pTaper->subType());
    rc = acedGetInt(NULL, &selectedSubType);
    //if cancel return
    if (rc == RTCAN || rc == RTERROR){
      return Adesk::kFalse;
    }
    //set default value 
    if (rc == RTNONE){
      break;
    }
  }while(symbols[selectedSubType] != 1);

  //set sub type
  if(symbols[selectedSubType] == 1)
    pTaper->setSubType(Acm::TaperType(selectedSubType));

  //printout orientation
  CString orientationStr[] = {"kLeftSide","kRightSide"};
  for (int i = 0;i<2;i++){
    acutPrintf(_T("\n%3d: %s"),i,orientationStr[i]);
  }

  //use have selected orientation
  int ret = 0;
  rc = RTNORM;
  do 
  {
    acutPrintf(_T("\n\nSelect orientation type <%2d>: "), pTaper->orientation());
    rc = acedGetInt(NULL, &ret);
    //if cancel return
    if (rc == RTCAN){
      return Adesk::kFalse;
    }

    //set default value 
    if (rc == RTNONE){
      break;
    }
  } while((rc != RTNORM) || (ret < 0) || (ret >= 2));

  //set orientation
  if (rc != RTNONE) // default value
    pTaper->setOrientation(Acm::Orientation(ret));

  //set theoretically exact frame on
  pTaper->setInspect(Adesk::kTrue);

  //user enters display string
  CString value;
  acutPrintf(_T("\n\nEnter Display string <%s>: "),pTaper->value(Acm::TaperDisplayStr));
  rc = acedGetString(1,NULL,value.GetBuffer(133), 133);
  value.ReleaseBuffer();

  //set display string by user entered
  if(ret == RTCAN) return Adesk::kFalse;
  pTaper->setValue(Acm::TaperDisplayStr,LPCTSTR(value));

  //set the symbol is above the curve
  pTaper->setSymAboveCurve(Adesk::kTrue);

  //refresh
  pTaper->regen();
  return Adesk::kTrue;
}

void createTaperSym()
{
  //create taper and slope symbol object
  AcmTaper *pTaper = new AcmTaper(); 
  assert(pTaper);
  if (Acm::eOk != pTaper->setSymbolDefaults()) {
    acutPrintf(_T("\nFail to set default for taper symbol."));
    delete pTaper;
    return;
  }

  //get starting and ending point of leader
  int res;
  AcGePoint3dArray ptArr;
  for (int i = 0; i<2; i++ ) {
    AcGePoint3d pt;
    res = ads_getpoint(NULL, _T("\nSelect point: "),asDblArray(pt));
    if (res != RTNORM){
      delete pTaper;
      return;
    }
    ptArr.append(pt);
  }
  pTaper->addLeader(ptArr);

  //set taper and slope symbol properties.
  if (Adesk::kFalse == setTaperValues(pTaper)) {
    delete pTaper;
    return;
  }

  // Post to Database
  AcDbObjectId objId;
  if (postToDb(pTaper, objId) != Acad::eOk) {
    delete pTaper;
    return;
  }

  AmiPickObj pickObj;
  AmiObjectKey* pKey = NULL;
  Ami::KeyType type;
  AmiStatus as = Ami::eOk;
  as = amiPick2( _T("Select geometry: "), Ami::curveKey, NULL, pickObj, Adesk::kFalse);
  if (as.success()) {
    as = amiGetKeyFromPick(&pickObj, type, pKey);
    if (as.failure()) {
      TSTDSTRING strErrText = as.text();
      acutPrintf(_T("\nFail to get selected geometry. %s"), strErrText.c_str());
    }
  }
  //You can attach symbol now. attachGeomRef accept only keys derived from
  //AmiGeomKey.
  if (pKey) {
    Acm::ErrorStatus es = pTaper->attachGeomRef(pKey, AcGePoint3d::kOrigin);
    if (Acm::eOk != es)
      acutPrintf(_T("\nFail to attach to geometry."));

    pKey->release();
  }

  pTaper->close();
}

//set taper and slope standard properties.
void editTaperStandard()
{
  //get taper and slope symbol standard from standard manager.
  AcDbObjectId taperStdId;
  if(getTaperStandardId(taperStdId) != Adesk::kTrue)
    return;

  //open taper and slope standard object for writing.
  AcDbObjectPointer<AcmTaperStd> pTaperStd(taperStdId, AcDb::kForWrite);
  if (Acad::eOk != pTaperStd.openStatus()) {
    acutPrintf(ACRX_T("Taper standard can not be opened!\n"));
    return;
  }

  //edit taper and slope standard properties.
  //printout dimension types
  CString dimensionStr[] = {"kRatio","kPercentage"};
  for (int i = 0;i<2;i++){
    acutPrintf(_T("\n%3d: %s"),i,dimensionStr[i]);
  }

  Acm::TaperDimensionType dimType;
  Acm::TaperRatioFormat fract;
  TCHAR* separator = NULL;
  // Read preferred dimension type
  pTaperStd->getDimensionType(dimType, fract, separator);

  int selectedDimType = 0;
  int rc = RTNORM;
  do{
    acutPrintf(_T("\n\nSelect dimension type <%2d>: "), (int)dimType);
    rc = acedGetInt(NULL, &selectedDimType);
    //if cancel return
    if (rc == RTCAN || rc == RTERROR){
      return;
    }

    //set default value 
    if (rc == RTNONE){
      break;
    }
  }while((rc != RTNORM) || (selectedDimType < 0) || (selectedDimType >= 2));

  //printout format types
  CString formatStr[] = {"kFraction","kNoFraction","kNumber"};
  for (int i = 0;i<3;i++){
    acutPrintf(_T("\n%3d: %s"),i,formatStr[i]);
  }

  int selectedFormatType = 0;
  rc = RTNORM;
  do{
    acutPrintf(_T("\n\nSelect format type <%2d>: "), (int)fract);
    rc = acedGetInt(NULL, &selectedFormatType);
    //if cancel return
    if (rc == RTCAN || rc == RTERROR){
      return;
    }
    //set default value 
    if (rc == RTNONE){
      break;
    }
  }while((rc != RTNORM) || (selectedFormatType < 0) || (selectedFormatType >= 3));

  //user enters separator
  CString value;
  acutPrintf(_T("\n\nEnter separator <%s>: "),separator);
  rc = acedGetString(1,NULL,value.GetBuffer(133), 133);
  value.ReleaseBuffer();

  if(rc == RTCAN) return;

  pTaperStd->setDimensionType((Acm::TaperDimensionType)selectedDimType,(Acm::TaperRatioFormat)selectedFormatType,value);

  //set arrow type
  pTaperStd->setArrowType(Acm::kArrowClosed15);

  //set text height
  double txtHeight = pTaperStd->textHeight();
  acutPrintf(_T("\nEnter new text height <%.2f>: "), txtHeight);
  int result = ads_getreal(NULL, &txtHeight);
  if (result == RTCAN || result == RTERROR)
    return;
  pTaperStd->setTextHeight(txtHeight);

  //edit arrow scale
  double arrowScale = pTaperStd->arwScale();
  acutPrintf(_T("\nEnter new arrow size <%.2f>: "), arrowScale);
  result = ads_getreal(NULL, &arrowScale);
  if (result == RTCAN || result == RTERROR)
    return;
  pTaperStd->setArwScale(arrowScale);

  //get leader color.
  int leaderColor = pTaperStd->leaderTrueColor().colorIndex();
  acutPrintf(_T("\nEnter new leader color <%d>: "), leaderColor);
  result = ads_getint(NULL, &leaderColor);
  if (result == RTCAN || result == RTERROR)
    return;

  //set leader color.
  AcCmColor color;
  color.setColorIndex(leaderColor);
  pTaperStd->setLeaderTrueColor(color);

  //get text color
  int textColor = pTaperStd->textTrueColor().colorIndex();
  acutPrintf(_T("\nEnter new text color <%d>: "), textColor);
  result = ads_getint(NULL, &textColor);
  if (result == RTCAN || result == RTERROR)
    return;

  //set text color
  color.setColorIndex(textColor);
  pTaperStd->setTextTrueColor(color);

  acutPrintf(_T("set taper standard properties successful."));
}