//////////////////////////////////////////////////////////////////////////////
//
//  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 "acm.h"
#include "acmdef.h"

#include "stdmgr.h"
#include "cauxent.h"
#include "symstd.h"

// Scale Area API
#include "AmgScaleAreaMgr.h"
#include "AmgScaleArea.h"

AcDbObjectIdArray rescaledObjIds;

Adesk::Boolean getAttachedObjectId(AcDbObjectId& borderId)
{
  //select a scale area, get its Id
  ads_name entres;
  ads_point ptres;
  int res = acedEntSel(_T("\nSelect Scale Area: "), entres,ptres);
  if( res == RTNORM ) {
    AcDbObjectId closedCurveId;
    if( acdbGetObjectId(closedCurveId,entres) != Acad::eOk ) return Adesk::kFalse;    
    borderId = closedCurveId;    
  }

  //check objId is valid
  if (!borderId.isValid())
    return Adesk::kFalse;

  AcDbEntity *pEnt = NULL;
  if(Acad::eOk != acdbOpenObject(pEnt, borderId, AcDb::kForRead))
    return Adesk::kFalse;

  // if entity that user selects is not a closed curve, return
  if (true != pEnt->isKindOf(AcDbCurve::desc())){
    pEnt->close();
    return Adesk::kFalse;
  }

  //close opened entity
  pEnt->close();

  return Adesk::kTrue;
}

void createScaleArea()
{
  // pick a closed curve for the border
  AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
  AcDbBlockTable *pBtbl;
  pDb->getSymbolTable(pBtbl, AcDb::kForRead);
  AcDbBlockTableRecord *pBtblRcd;
  pBtbl->getAt(ACDB_MODEL_SPACE, pBtblRcd, AcDb::kForWrite);
  pBtbl->close();

  // create closed curve as border
  AcDbPolyline *pPoly = new AcDbPolyline(4);

  AcGePoint3dArray points;
  points.append(AcGePoint3d(100, 200, 0));
  points.append(AcGePoint3d(200, 200, 0));
  points.append(AcGePoint3d(200, 100, 0));
  points.append(AcGePoint3d(100, 100, 0));

  AcGeVector3d normal(0,0,1);

  pPoly->setNormal(normal);
  AcGeMatrix3d   wcs2ecs(AcGeMatrix3d::kIdentity);
  pPoly->getEcs(wcs2ecs);
  wcs2ecs.invert();

  for (int i=0;i<points.length();i++)
  {
    AcGePoint3d pt(points[i]);
    pt.transformBy(wcs2ecs);
    pPoly->addVertexAt(i, AcGePoint2d(pt[0], pt[1]));
  }
  pPoly->setClosed(true);

  // create entities that are rescaled.
  AcDbCircle *pCir2 = new AcDbCircle(AcGePoint3d(140, 130, 0), AcGeVector3d(0,0,1), 50);
  AcDbCircle *pCir3 = new AcDbCircle(AcGePoint3d(150, 150 ,0), AcGeVector3d(0,0,1), 50);
  AcDbLine *pLine1 = new AcDbLine(AcGePoint3d(110, 110, 0), AcGePoint3d(120, 120, 0));
  AcDbText *pText = new AcDbText(AcGePoint3d(150, 150, 0), _T("Test"));

  // get closed curve ID
  pBtblRcd->appendAcDbEntity(pPoly);
  AcDbObjectId polyId = pPoly->objectId();
  const AcDbObjectId borderId = polyId;
  pPoly->close();
  
  // get objects to rescale
  pBtblRcd->appendAcDbEntity(pCir2);
  AcDbObjectId cir2objId = pCir2->objectId();
  rescaledObjIds.append(cir2objId);
  pCir2->close();

  pBtblRcd->appendAcDbEntity(pCir3);
  AcDbObjectId cir3objId = pCir2->objectId();
  rescaledObjIds.append(cir3objId);
  pCir3->close();

  pBtblRcd->appendAcDbEntity(pLine1);
  AcDbObjectId line1objId = pLine1->objectId();
  rescaledObjIds.append(line1objId);
  pLine1->close();

  pBtblRcd->appendAcDbEntity(pText);
  AcDbObjectId textobjId = pText->objectId();
  rescaledObjIds.append(textobjId);
  pText->close();

  pBtblRcd->close();

  // create scale area

  // get Scale Area Manager object
  AcMgScaleAreaMgr *pSAMgr = AcMgScaleAreaMgr::getAcMgScaleAreaMgr();
  if(pSAMgr == NULL)
    return;

  //create scale area on the closed curve
  AcMgScaleArea *pSA = pSAMgr->createScaleArea(borderId);
  if (pSA == NULL)
    return;

  pSA->setScaleType(AcMgScaleArea::kScalePf);

  // we only set text scaling factor if scale type is kScalePf 
  pSA->setTextScalingFactor(2);

  // if ScaleType is kScaleDf, return false
  pSA->setBasicScale();

  // rescale selected objects
  pSA->rescaleObjects(rescaledObjIds);

  // create viewport on specified layout and position
  pSA->createViewPort(_T("layout1"), AcGePoint3d(100, 100, 0));

  delete pSA;
}

void modifyScaleArea()
{
  // get document reference
  AcMgScaleAreaMgr *pSAMgr = AcMgScaleAreaMgr::getAcMgScaleAreaMgr();
  if (!pSAMgr)
    return;

  AcDbObjectId objId;
  if (getAttachedObjectId(objId) == Adesk::kFalse)
    return;

  // find scale area from current layout only.
  AcMgScaleArea *pSA = pSAMgr->findScaleArea(objId, false);
  if (!pSA)
    return;

  // change scale area type
  AcMgScaleArea::ScaleType type = pSA->scaleType();
  if (type == AcMgScaleArea::kScaleDf)
    pSA->setScaleType(AcMgScaleArea::kScalePf);

  // set new text scaling factor for selected scale area
  double textFactor = pSA->textScalingFactor();
  acutPrintf(_T("\nEnter new plot scale <%.2f>: "), textFactor);
  int result = ads_getreal(NULL, &textFactor);
  if (result == RTNORM) {
    pSA->setTextScalingFactor(textFactor);
  }

  pSA->setBasicScale();

  // delete attached viewport
  pSA->deleteViewPort();
	
  // rescale the same selected objects
  pSA->rescaleObjects(rescaledObjIds);

  delete pSA;
}