//
//  (C) Copyright 2009 by Autodesk, Inc.  All rights reserved.
//
// 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 "component.h"
#include <math.h>

//  component_main()
//
void component_main()
{
  AmiCompKey *pComp1_1 = NULL;
  AmiCompDefKey *pComp1Def =  NULL;
  AmiCompViewDefKey *pComp1TopDef = NULL;
  AmiCompViewKey *pComp1_1Top = NULL;
  createComponents(
    pComp1_1,
    pComp1Def,
    pComp1TopDef,
    pComp1_1Top);

  if (!pComp1_1 || !pComp1Def || !pComp1TopDef || !pComp1_1Top)
      return;

  AmiCompViewDefKey *pComp1FrontDef = NULL;
  AmiCompViewKey *pComp1_1Front = NULL;
  addComponentView(
    pComp1_1,
    pComp1FrontDef,
    pComp1_1Front);

  AmiCompViewKey *pComp1_2Top = NULL;
  AmiCompViewKey *pComp1_2Front = NULL;
  AmiCompKey *pComp1_2 = NULL;
  createAssemblyComp(
    pComp1Def,
    pComp1TopDef,
    pComp1FrontDef,
    pComp1_2Top,
    pComp1_2Front,
    pComp1_2);

  AmiCompKey *pAssy1_1 = NULL;
  AmiCompViewKey *pAssy1_1Top = NULL;
  AmiCompViewKey *pAssy1_1Front = NULL;
  AmiCompDefKey *pAssy1Def = NULL;
  assembleComponents(
    pComp1_1Top,
    pComp1_1Front,
    pComp1_2Top,
    pComp1_2Front,
    pAssy1_1,
    pAssy1_1Top,
    pAssy1_1Front,
    pAssy1Def);
return;
  AmiCompViewKey *pAssy1_1Side = new AmiCompViewKey();
  AmiCompViewKey *pComp1_1Side = new AmiCompViewKey();
  modifyAssemblyComponent(
    pAssy1_1,
    pComp1_1,
    pComp1_2,
    pAssy1_1Top,
    pAssy1_1Front,
    pAssy1_1Side,
    pComp1_1Side);

  AmiCompViewKey *pComp2_2Front = new AmiCompViewKey();
  AmiCompViewKey *pComp2_1Top = new AmiCompViewKey();
  AmiCompViewKey *pComp2_1Front = new AmiCompViewKey();
  addAssemblyComponent(
    pAssy1_1Top,
    pAssy1_1Front,
    pAssy1_1Side,
    pComp2_2Front,
    pComp2_1Top,
    pComp2_1Front);

  createSubAssembly(
    pComp1_1Top,
    pComp2_1Top,
    pComp1_1Front,
    pComp2_2Front,
    pComp2_1Front,
    pComp1_1Side,
    pAssy1_1Top,
    pAssy1_1Front,
    pAssy1_1Side,
    pAssy1Def);
}


// --------------- create component ---------------
Adesk::Boolean createComponents(
  AmiCompKey *&pComp1_1,
  AmiCompDefKey *&pComp1Def,
  AmiCompViewDefKey *&pComp1TopDef,
  AmiCompViewKey *&pComp1_1Top) {

  AcDbObjectId rectangleObjId;
  AcDbObjectIdArray entities;

  // set rectangle points
  AcGePoint3dArray ptArr;
  ptArr.setLogicalLength(4);
  ptArr[0].set(10, 50, 0.0);
  ptArr[1].set(50, 50, 0.0);
  ptArr[2].set(50, 70, 0.0);
  ptArr[3].set(10, 70, 0.0);
  AcDb2dPolyline *pRectangle1 = new AcDb2dPolyline(AcDb::k2dSimplePoly, ptArr, 0.0, Adesk::kTrue);

  AcGeMatrix3d comp1_1GeMatrix;  
  AcGeVector3d comp1_1Translation;

  // create rectangle
  pRectangle1->makeClosed();
  postToDb(pRectangle1, rectangleObjId);
  entities.append(rectangleObjId);

  // create the component definition
  amiCreate2dCompDef(pComp1Def, _ACRX_T("Comp1"), Designer_Assemblies);
  amiInstance2dComp(pComp1_1, pComp1Def,NULL);

  // set translation
  comp1_1Translation.set(10,50,00);
  comp1_1GeMatrix.setTranslation(comp1_1Translation);

  // create a component view
  ami2DSCreateCompViewDef(
    pComp1TopDef,
    pComp1_1Top,
    pComp1_1,
    entities,
    NULL,
    comp1_1GeMatrix,
    NULL,
    _ACRX_T("Top")); 

  return true;
}

// --------------- add component view ---------------
  Adesk::Boolean addComponentView(
    AmiCompKey *&pComp1_1,
    AmiCompViewDefKey *&pComp1FrontDef,
    AmiCompViewKey *&pComp1_1Front) {

  AcDbObjectId rectangleObjId;
  AcDbObjectIdArray entities;

  // set rectangle points
  AcGePoint3dArray ptArr;
  ptArr.setLogicalLength(4);
  ptArr[0].set(10, 10, 0.0);
  ptArr[1].set(50, 10, 0.0);
  ptArr[2].set(50, 15, 0.0);
  ptArr[3].set(10, 15, 0.0);
  AcDb2dPolyline *pRectangle1 = new AcDb2dPolyline(AcDb::k2dSimplePoly, ptArr, 0.0, Adesk::kTrue);

  AcGeMatrix3d comp1_1GeMatrix;  
  AcGeVector3d comp1_1Translation;

  // create second rectangle
  pRectangle1->makeClosed();
  postToDb(pRectangle1, rectangleObjId);
  entities.append(rectangleObjId);

  // set translation
  comp1_1Translation.set(10,10,00);
  comp1_1GeMatrix.setTranslation(comp1_1Translation);

  // add second view
  ami2DSCreateCompViewDef(
    pComp1FrontDef,
    pComp1_1Front,
    pComp1_1,
    entities,
    NULL,
    comp1_1GeMatrix,
    NULL,
    _ACRX_T("Front")); 

  return true;
}

// --------------- create assembly component ---------------
Adesk::Boolean createAssemblyComp(
  AmiCompDefKey *pComp1Def,
  AmiCompViewDefKey *&pComp1TopDef,
  AmiCompViewDefKey *&pComp1FrontDef,
  AmiCompViewKey *&pComp1_2Top,
  AmiCompViewKey *&pComp1_2Front,
  AmiCompKey *&pComp1_2) {

  AcGeMatrix3d comp1_2GeMatrix;  
  AcGeVector3d comp1_2Translation;

  // create second component
  amiInstance2dComp(pComp1_2, pComp1Def, NULL);

  // set translations
  comp1_2Translation.set(10,10,00);
  comp1_2GeMatrix.setTranslation(comp1_2Translation);

  // create Top view
  ami2DSInstanceCompView(
    pComp1TopDef,
    NULL,
    pComp1_2,
    comp1_2GeMatrix,
    pComp1_2Top);

  // set translations
  comp1_2Translation.set(10,70,00);
  comp1_2GeMatrix.setTranslation(comp1_2Translation);

  // create Front view
  ami2DSInstanceCompView(
    pComp1FrontDef,
    NULL,
    pComp1_2,
    comp1_2GeMatrix,
    pComp1_2Front);

  return true;
}

// --------------- assemble components ---------------
Adesk::Boolean assembleComponents(
  AmiCompViewKey *&pComp1_1Top,
  AmiCompViewKey *&pComp1_1Front,
  AmiCompViewKey *&pComp1_2Top,
  AmiCompViewKey *&pComp1_2Front,
  AmiCompKey *&pAssy1_1,
  AmiCompViewKey *&pAssy1_1Top,
  AmiCompViewKey *&pAssy1_1Front,
  AmiCompDefKey *&pAssy1Def) {

  AmiCompViewDefKey *pAssy1TopDef = new AmiCompViewDefKey();
  AmiCompViewDefKey *pAssy1FrontDef = new AmiCompViewDefKey();

  AcArray<AmiFolderKey*> assy1_1Views1;
  AcArray<AmiFolderKey*> assy1_1Views2;

  AcDbObjectIdArray entities;
  AcGeMatrix3d assy1_1GeMatrix;  
  AcGeVector3d assy1_1Translation;

  // create assembly component definition and component
  amiCreate2dCompDef(pAssy1Def, _ACRX_T("Assy1"), Designer_Assemblies);
  amiInstance2dComp(pAssy1_1, pAssy1Def, NULL);

  // set translation for view Top
  assy1_1Translation.set(10,50,00);
  assy1_1GeMatrix.setTranslation(assy1_1Translation);

  // create component view Top
  ami2DSCreateCompViewDef(
    pAssy1TopDef,
    pAssy1_1Top,
    pAssy1_1,
    entities,
    NULL,
    assy1_1GeMatrix,
    NULL,
    _ACRX_T("Top"));

  // set translation for view Front
  assy1_1Translation.set(10,10,00);
  assy1_1GeMatrix.setTranslation(assy1_1Translation);

  // create component view Front
  ami2DSCreateCompViewDef(
    pAssy1TopDef,
    pAssy1_1Front,
    pAssy1_1,
    entities,
    NULL,
    assy1_1GeMatrix,
    NULL,
    _ACRX_T("Front"));

  // restructure the components
  assy1_1Views1.append(pComp1_1Top);
  assy1_1Views1.append(pComp1_2Front);
  ami2DSRestructure(assy1_1Views1, pAssy1_1Top);

  assy1_1Views2.append(pComp1_1Front);
  assy1_1Views2.append(pComp1_2Top);
  ami2DSRestructure(assy1_1Views2, pAssy1_1Front);
  
  return true;
}

// --------------- modify assembly component ---------------
  Adesk::Boolean modifyAssemblyComponent(
    AmiCompKey *&pAssy1_1,
    AmiCompKey *&pComp1_1,
    AmiCompKey *&pComp1_2,
    AmiCompViewKey *&pAssy1_1Top,
    AmiCompViewKey *&pAssy1_1Front,
    AmiCompViewKey *&pAssy1_1Side,
    AmiCompViewKey *&pComp1_1Side) {

  AmiCompViewDefKey *pComp1SideDef = new AmiCompViewDefKey();
  AmiCompViewKey *pComp1_2Side = new AmiCompViewKey();
  AmiCompViewDefKey *pAssy1SideDef = new AmiCompViewDefKey();

  AcArray<AmiFolderKey*> assy1_1Views1;
  AcArray<AmiFolderKey*> assy1_1Views2;

  AcDbObjectIdArray entities;
  AcDbObjectId rectangleObjId;

  AcGeMatrix3d comp1SideDefGeMatrix;  
  AcGeVector3d comp1SideDefTranslation;
  AcGeMatrix3d comp1_1SideGeMatrix;  
  AcGeVector3d comp1_1SideTranslation;

  // set rectangle points
  AcGePoint3dArray ptArr;
  ptArr.setLogicalLength(4);
  ptArr[0].set(60, 10, 0.0);
  ptArr[1].set(80, 10, 0.0);
  ptArr[2].set(80, 15, 0.0);
  ptArr[3].set(60, 15, 0.0);
  AcDb2dPolyline *pRectangle1 = new AcDb2dPolyline(AcDb::k2dSimplePoly, ptArr, 0.0, Adesk::kTrue);

  // create rectangle (side view)
  pRectangle1->makeClosed();
  postToDb(pRectangle1, rectangleObjId);

  // set translation
  comp1SideDefTranslation.set(60,10,00);
  comp1SideDefGeMatrix.setTranslation(comp1SideDefTranslation);

  // create component view definitions and first instances for assy1side and comp1side
  ami2DSCreateCompViewDef(
    pAssy1SideDef,
    pAssy1_1Side,
    pAssy1_1,
    entities,
    NULL,
    comp1SideDefGeMatrix,
    NULL,
    _ACRX_T("Side"));

  entities.append(rectangleObjId);

  // create new component definition view Side
  ami2DSCreateCompViewDef(
    pComp1SideDef,
    pComp1_1Side,
    pComp1_1,
    entities,
    NULL,
    comp1SideDefGeMatrix,
    NULL,
    _ACRX_T("Side"));

  // create second instance
  ami2DSInstanceCompView(
    pComp1SideDef,
    NULL,
    pComp1_2,
    comp1_1SideGeMatrix,
    pComp1_2Side);

  // reassemble component views comp1_1Side and comp1_2Side
  assy1_1Views1.append(pComp1_1Side);
  ami2DSRestructure(assy1_1Views1, pAssy1_1Top);
  ami2DSRestructure(assy1_1Views1, pAssy1_1Side);

  assy1_1Views2.append(pComp1_2Side);
  ami2DSRestructure(assy1_1Views2, pAssy1_1Front);
  ami2DSRestructure(assy1_1Views2, pAssy1_1Side);

  // set translation of comp1_1side (reset)
  comp1_1SideTranslation.set(0,0,0);
  comp1_1SideGeMatrix.setTranslation(comp1_1SideTranslation);
  ami2DSSetViewPosition(pComp1_1Side, comp1_1SideGeMatrix);

  // set translation and rotate 90 comp1_2side
  ami2DSGetViewPosition(pComp1_1Side, comp1_1SideGeMatrix);
  comp1_1SideTranslation.set(0,0,1);
  comp1_1SideGeMatrix.setTranslation(comp1_1SideTranslation);
  comp1_1SideTranslation.set(12.5,12.5,0);
  comp1_1SideGeMatrix.setToRotation((atan(1.0)*2), comp1_1SideTranslation, AcGePoint3d(12.5,12.5,0));
  
  return true;
}

// --------------- add assembly component ---------------
Adesk::Boolean addAssemblyComponent(
  AmiCompViewKey *&pAssy1_1Top,
  AmiCompViewKey *&pAssy1_1Front,
  AmiCompViewKey *&pAssy1_1Side,
  AmiCompViewKey *&pComp2_2Front,
  AmiCompViewKey *&pComp2_1Top,
  AmiCompViewKey *&pComp2_1Front) {

  AmiCompDefKey *pComp2Def = new AmiCompDefKey();
  AmiCompKey *pComp2_1 = new AmiCompKey();
  AmiCompViewDefKey *pComp2TopDef = new AmiCompViewDefKey();
  AmiCompViewDefKey *pComp2FrontDef = new AmiCompViewDefKey();

  AcDbObjectId circleObjId;
  AcDbObjectId rectangleObjId;

  // set rectangle points
  AcGePoint3dArray ptArr;
  ptArr.setLogicalLength(4);
  ptArr[0].set(15, 15, 0.0);
  ptArr[1].set(25, 15, 0.0);
  ptArr[2].set(25, 22.5, 0.0);
  ptArr[3].set(15, 22.5, 0.0);
  AcDb2dPolyline *pRectangle1 = new AcDb2dPolyline(AcDb::k2dSimplePoly, ptArr, 0.0, Adesk::kTrue);

  AcDbObjectIdArray entities;
  AcArray<AmiFolderKey*> ass1_1TopViews;
  AcArray<AmiFolderKey*> ass1_1FrontViews;  

  AcGeMatrix3d comp2_1GeMatrix;  
  AcGeVector3d comp2_1Translation;

  AcGePoint3d center = AcGePoint3d(20,60,0);
  double radius = 5;
  AcDbCircle *pCircle1 = new AcDbCircle();

  // draw circle
  pCircle1->setCenter(center);
  pCircle1->setRadius(radius);
  postToDb(pCircle1, circleObjId);
  entities.append(circleObjId);

  // create new component
  amiCreate2dCompDef(pComp2Def, _ACRX_T("Comp2"), Designer_Assemblies);

  // set translation
  comp2_1Translation.set(60,20,00);
  comp2_1GeMatrix.setTranslation(comp2_1Translation);

  // create component view
  ami2DSCreateCompViewDef(
    pComp2TopDef,
    pComp2_1Top,
    pComp2_1,
    entities,
    NULL,
    comp2_1GeMatrix,
    NULL,
    _ACRX_T("Top")); 

  // restructure the components
  ass1_1TopViews.append(pComp2_1Top);
  ami2DSRestructure(ass1_1TopViews, pAssy1_1Top);

  // create rectangle
  pRectangle1->makeClosed();
  postToDb(pRectangle1, rectangleObjId);
  entities.append(rectangleObjId);

  // set translation
  comp2_1Translation.set(20,15,00);
  comp2_1GeMatrix.setTranslation(comp2_1Translation);

  // create component view
  ami2DSCreateCompViewDef(
    pComp2FrontDef,
    pComp2_1Front,
    pComp2_1,
    entities,
    NULL,
    comp2_1GeMatrix,
    NULL,
    _ACRX_T("Front")); 

  // restructure the components
  ass1_1TopViews.append(pComp2_1Front);
  ami2DSRestructure(ass1_1TopViews, pAssy1_1Front);

  // set translation
  comp2_1Translation.set(70,15,00);
  comp2_1GeMatrix.setTranslation(comp2_1Translation);

  // add a new view occurrence of comp2_1Front
  ami2DSInstanceCompView(
    pComp2FrontDef,
    pAssy1_1Side,
    pComp2_1,
    comp2_1GeMatrix,
    pComp2_2Front);
  
  return true;
}


// --------------- creates a sub assembly ---------------
Adesk::Boolean createSubAssembly(
  AmiCompViewKey *&pComp1_1Top,
  AmiCompViewKey *&pComp2_1Top,
  AmiCompViewKey *&pComp1_1Front,
  AmiCompViewKey *&pComp2_2Front,
  AmiCompViewKey *&pComp2_1Front,
  AmiCompViewKey *&pComp1_1Side,
  AmiCompViewKey *&pAssy1_1Top,
  AmiCompViewKey *&pAssy1_1Front,
  AmiCompViewKey *&pAssy1_1Side,
  AmiCompDefKey *&pAssy1Def) {

  AmiCompKey *pSubAssy1_1 = new AmiCompKey();
  AmiCompDefKey *pSubAssy1Def = new AmiCompDefKey();
  AmiCompViewDefKey *pSubAssy1TopDef = new AmiCompViewDefKey();
  AmiCompViewDefKey *pSubAssy1FrontDef = new AmiCompViewDefKey();
  AmiCompViewDefKey *pSubAssy1SideDef = new AmiCompViewDefKey();
  AmiCompViewKey *pSubAssy1_1Top = new AmiCompViewKey();
  AmiCompViewKey *pSubAssy1_1Front = new AmiCompViewKey();
  AmiCompViewKey *pSubAssy1_1Side = new AmiCompViewKey();

  AcDbObjectIdArray entities;
  AcArray<AmiFolderKey*> subAssy1_1Views1;
  AcArray<AmiFolderKey*> subAssy1_1Views2;
  AcArray<AmiFolderKey*> subAssy1_1Views3;

  AcGeMatrix3d subAssy1_1GeMatrix;  

  // create the component definition
  amiCreate2dCompDef(pSubAssy1Def, _ACRX_T("Sub-Assy1"), Designer_Assemblies);
  amiInstance2dComp(pSubAssy1_1, pSubAssy1Def, pAssy1Def);

  // create component view Top
  ami2DSCreateCompViewDef(
    pSubAssy1TopDef,
    pSubAssy1_1Top,
    pSubAssy1_1,
    entities,
    NULL,
    subAssy1_1GeMatrix,
    pAssy1_1Top,
    _ACRX_T("Top")); 

  // restructure component
  subAssy1_1Views1.append(pComp1_1Top);
  subAssy1_1Views1.append(pComp2_1Top);
  ami2DSRestructure(subAssy1_1Views1, pSubAssy1_1Top);

  // create component view Front
  ami2DSCreateCompViewDef(
    pSubAssy1FrontDef,
    pSubAssy1_1Front,
    pSubAssy1_1,
    entities,
    NULL,
    subAssy1_1GeMatrix,
    pAssy1_1Front,
    _ACRX_T("Front")); 

  // restructure component
  subAssy1_1Views2.append(pComp1_1Front);
  subAssy1_1Views2.append(pComp2_2Front); // comp2_2Front is actually the Side view copied from the comp2_1Front
  ami2DSRestructure(subAssy1_1Views2, pSubAssy1_1Front);

  // create component view Side
  ami2DSCreateCompViewDef(
    pSubAssy1SideDef,
    pSubAssy1_1Side,
    pSubAssy1_1,
    entities,
    NULL,
    subAssy1_1GeMatrix,
    pAssy1_1Side,
    _ACRX_T("Side")); 

  // restructure component
  subAssy1_1Views3.append(pComp2_1Front);
  subAssy1_1Views3.append(pComp1_1Side);
  ami2DSRestructure(subAssy1_1Views3, pSubAssy1_1Side);

  return true;
}

