/////////////////////////////////////////////////////////////////////
// (C) Copyright 1993-2005 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.
//
//
/////////////////////////////////////////////////////////////////////
// includes from ObjectARX Wizard
#ifdef _DEBUG
#define _DEBUG_WAS_DEFINED
#undef _DEBUG
#endif
#include "stdafx.h"           // MFC stuff
#ifdef _DEBUG_WAS_DEFINED
#define _DEBUG
#undef _DEBUG_WAS_DEFINED
#endif

#include "acm.h"
#include "acmdef.h"
#include "cauxent.h"
#include "symbol.h"
#include "leader.h"
#include "symstd.h"
#include "surfsym.h"
#include "fcframe.h"
#include "weldsym.h"
#include "datumtgt.h"
#include "idsym.h"
#include "bomstd.h"
#include "stdISO.h"
#include "stdMgr.h"
#include "cauxentex.h"


#include "WeldStd.h"
#include "WeldServRes.h"

extern "C" HINSTANCE _hdllInstance;
#define APP_ARX_NAME _T("weldServ.arx")



LPCTSTR _version_Weld =  _T("TEST Weld 1999 - %d");

/////////////////////////////////////////////////////////////////////
// standard support for of welding symboogy GB
/////////////////////////////////////////////////////////////////////
ACRX_DXF_DEFINE_MEMBERS(TestWeldingStd,AcmWeldingStdISO,AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,0,TESTWELDSTD,_T("WELDSERV"));

TestWeldingStd::TestWeldingStd() 
{
  setAllowedClosedTail(Adesk::kTrue);
}                     

TestWeldingStd::~TestWeldingStd()  
{
}                     

Acm::ErrorStatus
TestWeldingStd::getRevision(CString& rev, Adesk::UInt16& year) const
{
  assertReadEnabled();
  year = 1999;
  rev.Format(_version_Weld,year);
  return Acm::eOk;
}

Adesk::Boolean
TestWeldingStd::isCompatibleTo(const AcmStandard* pStd) const
{
  assertReadEnabled();
  assert(pStd != NULL);
  return pStd->isKindOf(AcmStandardISO::desc());
}

Acm::ErrorStatus 
TestWeldingStd::cInit()
{
  AcmWeldingStdISO::cInit();
  registerService(new TestJGrooveWeld);
  registerService(new TestAllAroundSquare);
  registerService(new TestFieldWeldEmpty);
  return Acm::eOk;
}

Adesk::Boolean 
TestWeldingStd::setFactoryDefaults()
{
  AcmWeldingStd::setFactoryDefaults();

  setAllowedIdentLine(Adesk::kTrue);
  setIdentLineGap(0.3);
  setSymbolGap(0.3);
  setAllowedClosedTail(Adesk::kTrue);
  createDefaultLTypeIdentLine(_T("TESTWELD"));
  return Adesk::kTrue;
}


void 
TestWeldingStd::getSubEnts(const AcmCSubWelding* pWelding,
                              AcmCAuxEntArray& subents,
                              AcGePoint3d& ptRefEnd) const
{
  assertReadEnabled();

  AcmStandard *pStd = owner();
  ASSERT(pStd);

  //Pointers to all weld symbol in sub-welding
  AcmCWeld *pWOther1 = pWelding->weldOnOtherSide();
  AcmCWeld *pWOther2 = pWelding->weldOnOtherSide(Adesk::kFalse);
  AcmCWeld *pWArrow1 = pWelding->weldOnArrowSide();
  AcmCWeld *pWArrow2 = pWelding->weldOnArrowSide(Adesk::kFalse);
  
  //is there any weld symbol
  AcmCWeld *pWeld = NULL;
  if (pWOther1) pWeld = pWOther1;
  else if (pWOther2) pWeld = pWOther2;
  else if (pWArrow1) pWeld = pWArrow1;
  else pWeld = pWArrow2;

  //if there is no weld symbol
  Adesk::Boolean delWeld = Adesk::kFalse;
  if (!pWeld) {
    pWeld = pWelding->newWeld();
    delWeld = Adesk::kTrue;
  }

  //Draw field weld symbol
  if (pWelding->fieldWeld()) {
    AcmCWeldService *pServField = getService(Acm::kFieldWeld);
    if (pServField) pServField->getSubEnts(pWeld,subents);
  }
  //Alllaround symbol
  if(pWelding->areaDescType() == Acm::kWeldAllAround && 
    pWelding->areaDescType() != Acm::kNoneSymbol) {//or Allaround?
    AcmCWeldService *pServAround = getService(pWelding->areaDescType());
    if (pServAround) pServAround->getSubEnts(pWeld,subents);
  }  

 
  //draw both sides of weld
  AcmCAuxEntArray    arrayOther, arrayArrow;
  AcGeVector3d       moveVecO, moveVecA;
  Acm::AlignmentType alignOther,alignArrow;
  double sizeArrow, sizeOther;

  getSideSubEnts(pWOther1,pWOther2,arrayOther,alignOther,sizeOther);
  getSideSubEnts(pWArrow1,pWArrow2,arrayArrow,alignArrow,sizeArrow);

  //bigger alignment move size
  if ((Acm::kCenter != alignOther) &&
      (sizeOther < sizeArrow))
    sizeOther = sizeArrow;

  if ((Acm::kCenter != alignArrow) &&
      (sizeArrow < sizeOther))
    sizeArrow = sizeOther;

  //append special stagger symbol
  if ((pWelding->associationType() == Acm::kAssociationSpecialStagger) &&
      (pWOther1) && (pWArrow1))
  {
    double staggerO = pWOther1->staggerAuxDist();
    double staggerA = pWArrow1->staggerAuxDist();
    if (fabs(staggerO) < fabs(staggerA))
      pWOther1->setStaggerAuxDist(staggerA);
    else
      pWArrow1->setStaggerAuxDist(staggerO);

    AcmCWeldService *pServS;
    if (pServS = getService(Acm::kSpecialStaggerWeld)) {
      pServS->getSubEnts(pWOther1,arrayOther);
      pServS->getSubEnts(pWArrow1,arrayArrow);
    }
  }

  AcDbExtents extHelp(AcGePoint3d::kOrigin,AcGePoint3d::kOrigin);
  subents.getGeomExtents(extHelp);

  //Do you want Square symbol?//
  if (pWelding->areaDescType() == Acm::kWeldAllAroundSquare &&
    pWelding->areaDescType() != Acm::kNoneSymbol) {
    AcmCWeldService *pServAround = getService(pWelding->areaDescType());
      if (pServAround) {
        AcmCAuxEntArray areaDesc;
        pServAround->getSubEnts(pWeld,areaDesc);
        AcGeVector3d moveVecArea;
         if (pWelding->orientation() == Acm::kLeftSide) {
            moveVecArea.x = extHelp.minPoint().x - currentSymbolGap();
         } else {
            moveVecArea.x = extHelp.maxPoint().x + currentSymbolGap();
          }
           AcGeMatrix3d moveArea(AcGeMatrix3d::kIdentity);
           moveArea.setTranslation(moveVecArea);//
           areaDesc.transformBy(moveArea);
           subents.moveFrom(areaDesc);
           subents.getGeomExtents(extHelp);
           // 
  }
 }
  AcDbExtents extArrow,extOther;
  extOther.set(AcGePoint3d::kOrigin,AcGePoint3d::kOrigin);
  extArrow.set(AcGePoint3d::kOrigin,AcGePoint3d::kOrigin);
  arrayOther.getGeomExtents(extOther);
  arrayArrow.getGeomExtents(extArrow);

  double size,minWidth;
  //minimum length HALF of reference line
  minWidth = pStd->textHeight() * 5;
  if (minWidth < 12.5) minWidth = 12.5;

  //comapre extents on both sides
  if (pWelding->orientation() == Acm::kLeftSide) {
    double xMove1 = extOther.maxPoint().x - sizeOther;
    double xMove2 = extArrow.maxPoint().x - sizeArrow;
    double restM  = extHelp.minPoint().x;
    if (xMove1 < xMove2) xMove1 = xMove2;
    size = restM - xMove1 - currentSymbolGap();
    moveVecO.x = size - sizeOther;
    moveVecA.x = size - sizeArrow;
    minWidth *= -1;
  } else {
    double xMove1 = fabs(extOther.minPoint().x) + sizeOther;
    double xMove2 = fabs(extArrow.minPoint().x) + sizeArrow;
    double restM  = extHelp.maxPoint().x;
    if (xMove1 < xMove2) xMove1 = xMove2;
    size = xMove1 + restM + currentSymbolGap();
    moveVecO.x = size - sizeOther;
    moveVecA.x = size - sizeArrow;
  }

  //controll for half of minimum width
  if ((fabs(size) < fabs(minWidth)) &&
      (fabs(size) < fabs(minWidth)))
  {
    moveVecO.x = minWidth - sizeOther;
    moveVecA.x = minWidth - sizeArrow;
  }

  //identification line
  double moveY = 0.0;
  if (pWelding->identificationLine() == Acm::kIdentLineOtherSide) {
    moveVecO.y += currentIdentLineGap();
    moveY = moveVecO.y;
  } else if (pWelding->identificationLine() == Acm::kIdentLineArrowSide) {
    moveVecA.y -= currentIdentLineGap();
    moveY = moveVecA.y;
  }

  //transform sub-ents of both sides
  AcGeMatrix3d tranSym(AcGeMatrix3d::kIdentity);
  tranSym.setTranslation(moveVecO);
  arrayOther.transformBy(tranSym);
  tranSym.setToTranslation(moveVecA);
  arrayArrow.transformBy(tranSym);
  //move sub-ents to main array
  subents.moveFrom(arrayOther);
  subents.moveFrom(arrayArrow);
  //
  //sets end point of reference line
  extHelp.set(AcGePoint3d::kOrigin,AcGePoint3d::kOrigin);
  subents.getGeomExtents(extHelp);
  if (pWelding->orientation() == Acm::kLeftSide)
    ptRefEnd.x = extHelp.minPoint().x - currentSymbolGap();
  else
    ptRefEnd.x = extHelp.maxPoint().x + currentSymbolGap();

  //controll for min length of reference line
  minWidth *= 2.0;
  if (fabs(ptRefEnd.x) < fabs(minWidth)) ptRefEnd.x = minWidth;
  
  //drawing weld tial
  CString str;
  AcmCWeldService *pTail;
  if ((pWelding->getValue(Acm::WeldNotes,str) != Acm::eIsEmpty) &&
      (pTail = getService(Acm::kWeldingTail)))
  {
    pTail->getSubEnts(pWeld,arrayOther);
    tranSym.setToTranslation(ptRefEnd.asVector());
    arrayOther.transformBy(tranSym);
    subents.moveFrom(arrayOther);
  }
  
  //Draw reference line
  AcmCAuxPline *pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,ptRefEnd);
  pLine->setProperties(AcDbObjectId::kNull,pStd->leaderColor());
  subents.append(pLine);

  //draw identification line
  if (pWelding->identificationLine() != Acm::kNoIdentLine) {
    moveVecO.set( 0.0 , moveY , 0.0 );
    tranSym.setToTranslation(moveVecO);
    pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,ptRefEnd);
    pLine->setProperties(identLtypeId(),pStd->leaderColor());
    pLine->transformBy(tranSym);
    subents.append(pLine);
  }

  //delete temporary weld
  if (delWeld) delete pWeld;
}

/////////////////////////////////////////////////////////////////////
//EMPTY FIELD WELD SYMBOL 
/////////////////////////////////////////////////////////////////////
TestFieldWeldEmpty::TestFieldWeldEmpty()
{
  setServiceType(Acm::kFieldWeld);
  setAllowedLocation(Acm::kOnlyOnOtherSide);
  setServiceNameRcId(IDS_WELD_FIELDSYM);
  setHidden(Adesk::kTrue);
  setAlignment(Acm::kLeft);
  setBitmapFlipRcId(IDB_WELDFLAGEMPTY);
}

HINSTANCE
TestFieldWeldEmpty::serviceResourceHandle() const
{ 
  return GetModuleHandle(APP_ARX_NAME); 
}

void
TestFieldWeldEmpty::getSubEnts(AcmCWeld* pWeld,
                               AcmCAuxEntArray& entArray)
{
  AcmStandard *pStd = ownerWeldStd()->owner();
  ASSERT(pStd);

  Adesk::UInt16 symColor = pStd->symbolColor();
  double       txtH     = pStd->textHeight();
  double       gap      = ownerWeldStd()->currentSymbolGap();

  getBasicSymbol(pWeld,txtH,gap,symColor,entArray);
}

double
TestFieldWeldEmpty::symbolWidth() const
{
   return ownerWeldStd()->owner()->textHeight() * 2;
}

void
TestFieldWeldEmpty::getBasicSymbol(AcmCWeld* pWeld,
                                  double txtH,
                                  double gap, 
                                  Adesk::UInt16 symColor,
                                  AcmCAuxEntArray& entArray
                                  )
{
  //orientation factor
  double xFac = 1;
  if (Acm::kLeftSide == pWeld->subWelding()->orientation()) xFac = -1;

  AcGePoint3d p1( 0.0 , 2 * txtH , 0.0 );//Line
  AcGePoint3d p3( 0.0 ,     txtH , 0.0 );//lower point
  AcGePoint3d p4( 0.0 , 2 * txtH , 0.0 );//upper point
  AcGePoint3d p2( xFac * symbolWidth() , txtH , 0.0 );//the top

  AcGePoint3dArray pts;
  pts.setLogicalLength(3);
  pts.setAt(0,p4);
  pts.setAt(1,p3);
  pts.setAt(2,p2);

  AcmCAuxPline *pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p1);
  pLine->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pLine);

  AcmCAuxPolygon *pPolygon = new AcmCAuxPolygon(pts,kAcGiFillNever);
  pPolygon->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pPolygon);
}

/////////////////////////////////////////////////////////////////////
//SINGLE 
/////////////////////////////////////////////////////////////////////
HINSTANCE
TestJGrooveWeld::serviceResourceHandle() const
{ 
  return GetModuleHandle(APP_ARX_NAME); 
}

TestJGrooveWeld::TestJGrooveWeld()
{
  setGroup(Acm::kBacking);
  setServiceType(Acm::kBevelGrooveShapeWeld);
  setServiceNameRcId(IDS_WELD_BACK);
  setBitmapRcId(IDB_WELD_BEVELSHAPE);
  setAlignment(Acm::kLeft);
}

double
TestJGrooveWeld::symbolHeight(const AcmCWeld *pWeld) const
{
  return ownerWeldStd()->owner()->textHeight() * 2.0;
}

double
TestJGrooveWeld::symbolWidth() const
{
  return ownerWeldStd()->owner()->textHeight() * 2.0;
}

void
TestJGrooveWeld::getSubEnts(AcmCWeld* pWeld,
                                   AcmCAuxEntArray& entArray)
{
  AcmStandard *pStd = ownerWeldStd()->owner();
  ASSERT(pStd);

  Adesk::UInt16 symColor = pStd->symbolColor();
  double        txtH = pStd->textHeight();
  double        gap  = ownerWeldStd()->currentSymbolGap();
  AcDbExtents   ext;

  getBasicSymbol(pWeld,txtH,gap,symColor,entArray);
  return;
}

void
TestJGrooveWeld::getBasicSymbol(AcmCWeld* pWeld,
                                           double txtH,
                                           double gap, 
                                           Adesk::UInt16 symColor,
                                           AcmCAuxEntArray& entArray)
{
    AcGePoint3d p0 = AcGePoint3d::kOrigin;
    AcGePoint3d p1, p2, p3;
if(pWeld->subWelding()->identificationLine() == Acm::kNoIdentLine) { 
   if(pWeld->location() == Acm::kArrowSide){
     //p0 ;//.set( 0.0 ,0.0, 0.0 );
     p1.set( symbolWidth() , p0.y , 0.0 );
     p2.set( p1.x, p1.y + (0.5*(symbolHeight(pWeld))) , 0.0 );
     p3.set( 0.0 , p2.y , 0.0 );
     } else if(pWeld->location() == Acm::kOtherSide){
     //p0 = AcGePoint3d::kOrigin;//.set( 0.0 ,0.0, 0.0 );
     p1.set( symbolWidth() , p0.y , 0.0 );
     p2.set( p1.x, p1.y + (0.5*(symbolHeight(pWeld))) , 0.0 );
     p3.set( 0.0 , p2.y , 0.0 );
     }
   } else  {
   if(pWeld->location() == Acm::kArrowSide && pWeld->subWelding()->identificationLine() != Acm::kIdentLineOtherSide){
     p0.set( p0.y , -(0.3 * symbolHeight(pWeld)), p0.y );
     p1.set( symbolWidth() , 0.0 , 0.0 );
     p2.set( p1.x, p1.y + (0.5*(symbolHeight(pWeld))) , 0.0 );
     p3.set( 0.0 , p2.y , 0.0 ); 
  } else if(pWeld->location() == Acm::kArrowSide && pWeld->subWelding()->identificationLine() == Acm::kIdentLineOtherSide){ 
     p1.set( symbolWidth() , p0.y , 0.0 );
     p2.set( p1.x, p1.y + (0.5*(symbolHeight(pWeld))) , 0.0 );
     p3.set( 0.0 , p2.y , 0.0 );
  } else if(pWeld->location() == Acm::kOtherSide && pWeld->subWelding()->identificationLine() == Acm::kIdentLineArrowSide){
     p1.set( symbolWidth() , p0.y , 0.0 );
     p2.set( p1.x, p1.y + (0.5*(symbolHeight(pWeld))) , 0.0 );
     p3.set( 0.0 , p2.y , 0.0 );
  } else if(pWeld->location() == Acm::kOtherSide && pWeld->subWelding()->identificationLine() != Acm::kIdentLineArrowSide){
     p0.set( 0.0 , -(0.3 * symbolHeight(pWeld)), 0.0 );
     p1.set( symbolWidth() , 0.0 , 0.0 );
     p2.set( p1.x, + (0.5*(symbolHeight(pWeld))) , 0.0 );
     p3.set( 0.0 , p2.y , 0.0 );
    }
  }
  /*AcmCAuxPline *pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p1);
  pLine->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pLine);
  pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p2);
  pLine->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pLine);*/
  AcmCAuxPline *pLine;
//  ASSERT(pLine);
if(pWeld->subWelding()->identificationLine() == Acm::kNoIdentLine){ 
  //AcmCAuxPline *pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p0);
 // pLine->setProperties(AcDbObjectId::kNull,symColor);
 // entArray.append(pLine);
    pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p0);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
    entArray.append(pLine);
    pLine = new AcmCAuxPline(p0,p1);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
    entArray.append(pLine);
    pLine = new AcmCAuxPline(p1,p2);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
    entArray.append(pLine);
    pLine = new AcmCAuxPline(p2,p3);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
  } else {
    pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p0);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
    entArray.append(pLine);
    pLine = new AcmCAuxPline(AcGePoint3d::kOrigin,p1);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
    entArray.append(pLine);
    pLine = new AcmCAuxPline(p1,p2);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
    entArray.append(pLine);
    pLine = new AcmCAuxPline(p2,p3);
    pLine->setProperties(AcDbObjectId::kNull,symColor);
  }
 //
  entArray.append(pLine);

  AcmCWeldBaseService::getBasicSymbol(pWeld,txtH,gap,symColor,entArray);
}

/////////////////////////////////////////////////////////////////////
//ALL AROUND THREE SIDE SYMBOL specific fo GB 
/////////////////////////////////////////////////////////////////////
HINSTANCE
TestAllAroundSquare::serviceResourceHandle() const
{ 
  return GetModuleHandle(APP_ARX_NAME); 
}

TestAllAroundSquare::TestAllAroundSquare()
{
  setGroup(Acm::kAreaDesc);
  setServiceType(Acm::kWeldAllAroundSquare);
  setHidden(Adesk::kTrue);
  setAllowedLocation(Acm::kOnlyOnOtherSide);
  setServiceNameRcId(IDS_WELD_ALLAROUND);
  setBitmapRcId(IDB_WELD_ALLAROUNDSQUARE);
}

HBITMAP
TestAllAroundSquare::loadBitmap(Adesk::Boolean mask) const
{
  if (!bitmapRcId()) return NULL; 
  return (HBITMAP)LoadImage(serviceResourceHandle(), MAKEINTRESOURCE(bitmapRcId()), IMAGE_BITMAP, 60, 36, LR_LOADMAP3DCOLORS);
}

void
TestAllAroundSquare::getSubEnts(AcmCWeld* pWeld,
                                AcmCAuxEntArray& entArray)
{
  AcmStandard *pStd = ownerWeldStd()->owner();
  ASSERT(pStd);

  Adesk::UInt16 symColor = pStd->symbolColor();
  double       txtH     = pStd->textHeight();
  double       gap      = ownerWeldStd()->currentSymbolGap();

  getBasicSymbol(pWeld,txtH,gap,symColor,entArray);
}

void
TestAllAroundSquare::getBasicSymbol(AcmCWeld* pWeld,
                                     double txtH,
                                     double gap, 
                                     Adesk::UInt16 symColor,
                                     AcmCAuxEntArray& entArray)
{
  AcGePoint3d p0, p1, p2, p3;
 //if there is identifikation line we need to move symbol
  if (pWeld->subWelding()->identificationLine() == Acm::kIdentLineOtherSide)
    gap += gap;
   
  p0.set(0.5 * txtH, gap, 0.0); 
  p1.set(p0.x + 1.2 * txtH, gap, 0.0);
  p2.set(p0.x, p0.y + txtH, 0.0);
  p3.set(p1.x, p2.y, 0.0);
   
  AcmCAuxPline *pLine = new AcmCAuxPline(p0, p1);
  pLine->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pLine);
  pLine = new AcmCAuxPline(p0, p2);
  pLine->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pLine);
  pLine = new AcmCAuxPline(p2, p3);
  pLine->setProperties(AcDbObjectId::kNull,symColor);
  entArray.append(pLine);
}
