/////////////////////////////////////////////////////////////////////
// (C) Copyright 2007 by Autodesk, Inc. 
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted, 
// provided that the above copyright notice appears in all copies and 
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting 
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC. 
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to 
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
//
/////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "resource.h"

#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->setShowLeader(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();
}