////////////////////////////////////////////////////////////////////////////////
//
// Orifice.cpp -  
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Orifice.h"


extern IApplicationPtr appl;
extern HINSTANCE g_hInstance;

//-------------------------------------------------------------------------------
//   
// ---
struct MacroPar 
{
  double diam;
};


//-------------------------------------------------------------------------------
//  
// ---
void SelectFaces( IEntityPtr & face1, IEntityPtr & face2 )
{
  IDocument3DPtr doc( ksGetActive3dDocument(), false );
  if ( doc )
  {
    IChooseMngPtr chMng( doc->GetChooseMng(), false );
    if ( chMng )
    {
      chMng->Choose( face1 );
      chMng->Choose( face2 );
    }  
  } 
}


//-------------------------------------------------------------------------------
// 
// ---
Orifice::Orifice()
  : diameter ( 5 ),
    face1 ( 0 ),
    face2 ( 0 )
{
  IDocument3DPtr doc( ksGetActive3dDocument(), false );
  if ( doc )
  {
    macroObject.Attach( doc->GetEditMacroObject() );
    if ( (bool)macroObject && macroObject->IsCreated() )
    {
      bool err = false;
      IFeaturePtr macroFeature ( macroObject->GetFeature(), false );
      rolbackFeature.Attach( doc->GetRollBackFeature(), false );
      if ( macroFeature )
      {
        doc->SetRollBackFeature( macroFeature );
        IFeatureCollectionPtr featureCol( macroFeature->SubFeatureCollection(true, true), false );
        if ( featureCol )
        {
          //    
          IFeaturePtr feature( featureCol->First(), false );
          if ( (bool)feature && feature->IsValid() )
          {
            oldExclude = !!feature->GetExcluded();
            doc->ExcludeFeaturesAfter( feature, true );
            feature->SetExcluded( true );
          }
          else 
            err = true; 
        }
      }
      if ( err )
        MessageT( _T("   .     .") );
      GetUserData();
      if ( (bool)face1 || (bool)face2 )
      {
        if ( (bool)face1 && !face1->IsCreated() )
          face1 = NULL;
        if ( (bool)face2 && !face2->IsCreated() )
          face2 = NULL;

        SelectFaces( face1, face2 );
      }
    }
  }  
}  


//-------------------------------------------------------------------------------
//   
// ---
void Orifice::SetFace1( IEntityPtr & face )
{
  face1 = face;
}


//-------------------------------------------------------------------------------
//   
// ---
void Orifice::SetFace2( IEntityPtr & face )
{
  face2 = face;
}


//-------------------------------------------------------------------------------
//   
// ---
IEntity* Orifice::GetFace1( bool addRef )
{
  if ( addRef && (bool)face1 )
    face1->AddRef();
  return face1;
}


//-------------------------------------------------------------------------------
//   
// ---
IEntity* Orifice::GetFace2( bool addRef )
{
  if ( addRef && (bool)face2 )
    face2->AddRef();
  return face2;
}


//-------------------------------------------------------------------------------
//     
// ---
void Orifice::SetUserData()
{
  if ( !(bool)params )
  {
    IKompasDocument3DPtr doc = appl->GetActiveDocument();
    if ( doc )
    {
      IUserDataStoragesMngPtr storageMng = doc->GetUserDataStoragesMng();
      if ( storageMng )
      {
        IKompasAPIObjectPtr macro3D( IUnknownPtr(ksTransferInterface(macroObject, ksAPI7Dual, 0), false) );
        if ( macro3D )
        {
          IUserDataStoragesPtr storages = storageMng->Add( macro3D );
          if ( storages )
          {
            IUserDataStoragePtr macroPars = storages->Add( _bstr_t(LoadStr(IDS_CAPTION)) );
            if ( macroPars )
            {
              params = macroPars;
            }  
          }
        }
      }  
    }
  }
  params->Clear( _bstr_t("") );
  params->AddObject( _bstr_t(""), diameter, _bstr_t(LoadStr(ID_DIAMETER)) );
  IDispatchPtr facet1( IUnknownPtr(ksTransferInterface(face1, ksAPI7Dual, 0), false) );
  if ( facet1 )
  {  
    _variant_t f1 = (IDispatch*)facet1;
    params->AddObject( _bstr_t(""), f1, _bstr_t(LoadStr(ID_FACE1)) );
  }
  IDispatchPtr facet2( IUnknownPtr(ksTransferInterface(face2, ksAPI7Dual, 0), false) );
  if ( facet2 )
  {  
    _variant_t f2 = (IDispatch*)facet2;
    params->AddObject( _bstr_t(""), f2, _bstr_t(LoadStr(ID_FACE2)) );
  }
  params->AddObject( _bstr_t(""), varName, _bstr_t(LoadStr(ID_VARIABLE_NAME)) );
  
}


//-------------------------------------------------------------------------------
//     
// ---
void Orifice::GetUserData()
{
  IKompasDocument3DPtr doc = appl->GetActiveDocument();
  if ( doc )
  {
    IUserDataStoragesMngPtr storageMng = doc->GetUserDataStoragesMng();
    if ( storageMng )
    {
      IKompasAPIObjectPtr macro3D( IUnknownPtr(ksTransferInterface(macroObject, ksAPI7Dual, 0), false) );
      if ( macro3D )
      {
        IUserDataStoragesPtr storages = storageMng->GetItem( (LPDISPATCH)macro3D );
        if ( storages )
        {
          IUserDataStoragePtr macroPars = storages->GetItem( _bstr_t(LoadStr(IDS_CAPTION)) );
          if ( macroPars )
          {
            long numb;
            {
              _variant_t obj;
              macroPars->GetObject( _bstr_t(LoadStr(ID_DIAMETER)), &obj, &numb );
              diameter = (double)obj;
              macroPars->GetObject( _bstr_t(LoadStr(ID_FACE1)), &obj, &numb );
              IDispatchPtr facet1( (LPDISPATCH)obj, false );
              if ( facet1 )
                face1 = ( IUnknownPtr(ksTransferInterface( facet1, ksAPI3DCom, o3d_entity ), false) );
            }
            {
              _variant_t obj1;
              macroPars->GetObject( _bstr_t(LoadStr(ID_FACE2)), &obj1, &numb );
              IDispatchPtr facet2( (LPDISPATCH)obj1, false );
              if ( facet2 )
                face2 = ( IUnknownPtr(ksTransferInterface( facet2, ksAPI3DCom, o3d_entity ), false) );
            }
            {
              _variant_t obj2;
              macroPars->GetObject( _bstr_t(LoadStr(ID_VARIABLE_NAME)), &obj2, &numb );
              varName = obj2;
            }
            params = macroPars;
          }  
        }  
      }  
    }  
  }  
}

#define KS_MAXDOUBLE (1.0E+300) // 1.7976931348623158E+308


//-------------------------------------------------------------------------------
//      
// ---
void ClearCurrentSketch()
{  
  //         
  
//  reference rIterator = CreateIterator( ALL_OBJ, 0 );
//  if ( rIterator )
//  {
//    reference rObject = MoveIterator( rIterator, 'F' ); //       
//    //              
//    while ( rObject )
//    {
//      //     
//      if ( ExistObj( rObject ) )
//        DeleteObj( rObject );
//      //    
//      rObject = MoveIterator( rIterator, 'N' );
//    }
//    DeleteIterator( rIterator ); //  
//  }
  reference gr = NewGroup( 1 );
  EndGroup();
  SelectGroup( gr, 3, -KS_MAXDOUBLE, -KS_MAXDOUBLE, KS_MAXDOUBLE, KS_MAXDOUBLE );
  DeleteObj( gr );
}


//-----------------------------------------------------------------------------
//
// ---
bool Orifice::OnChangeControlValue( long ctrlID, const VARIANT & newVal )
{ 
  bool res = false;
  switch ( ctrlID )
  {  
    case ID_DIAMETER:  diameter = newVal.dblVal; res = true; break;
  }
  return res; 
}

//-------------------------------------------------------------------------------
//   - 
// ---
void Orifice::Create()
{
  m_objectIndex = -1;

  //  
  double rad = diameter * 0.5;
  //   
  if ( (bool)face1 && (bool)face2 )
  {
    //   3D 
    IDocument3DPtr doc( ksGetActive3dDocument(), false );
    if ( doc )
    {
      //   , 
      if ( !(bool)macroObject )
      {
        //  
        IPartPtr part( doc->GetPart(pTop_Part), false );
        if ( part )
        {
          // 
          IEntityPtr sketch( part->NewEntity(o3d_sketch), false );
          if ( sketch )
          {
            //   
            ISketchDefinitionPtr sketchDef( IUnknownPtr(sketch->GetDefinition(), false) );
            if ( sketchDef )
            {
              //  -    
              sketchDef->SetPlane( face1 );
              //  
              sketchDef->SetAngle( 0 );
              // 
              sketch->Create();
              // 
              if ( sketchDef->BeginEdit() )
              {
                //   
                reference  c = Circle( 0, 0, rad, 1/*  - */);
                varName = CreateVariable( c );
                sketchDef->EndEdit();
              }
              //   
              IEntityPtr cutExtrusion( part->NewEntity(o3d_cutExtrusion), false );
              if ( cutExtrusion )
              {
                int resCreate = 0;
                //      
                ICutExtrusionDefinitionPtr cutDef( IUnknownPtr(cutExtrusion->GetDefinition(), false) );
                if ( cutDef )
                {
                  //  - 
                  cutDef->SetDirectionType( dtNormal );
                  // 
                  cutDef->SetSketch( sketch );
                  cutDef->SetDirectionType( dtNormal );
                  cutDef->SetSideParam( TRUE, etUpToSurfaceTo, 0, 0, FALSE );
                  //  
                  cutDef->SetDepthObject( TRUE, face2 );
                  //   
                  resCreate = cutExtrusion->Create();
                }
                //  
                if ( resCreate )
                {  
                  // 
                  macroObject.Attach( part->NewEntity(o3d_MacroObject), false );
                  if ( macroObject )
                  {
                    // 
                    macroObject->Create();
                    //   
                    IMacro3DDefinitionPtr macroDef( IUnknownPtr(macroObject->GetDefinition(), false) );
                    if ( macroObject )
                    {
                      //  
                      macroDef->SetStaffVisible( FALSE );
                      //     
                      macroDef->Add( cutExtrusion );
                      MacroPar pars;
                      pars.diam = diameter;
 //                     macroDef->SetDoubleClickEditOff( TRUE ); //   
                      TCHAR buf[255];
                      GetModuleFileName( g_hInstance, buf, sizeof(buf) );
                      macroDef->SetUserParam( &pars, sizeof(pars), _bstr_t(buf), _bstr_t(LoadStr(IDR_LIBID)), 1 );
                    }
                    macroObject->Update();
                    //     
                    SetUserData();
                  } 
                }
              }  
            }  
          }  
        }
      }
      //   
      else
      {
        IPartPtr part( macroObject->GetParent(), false );
        if ( part )
        {
//            part->SetNeedRebuild( false );  
          //    
          IMacro3DDefinitionPtr macroDef( IUnknownPtr(macroObject->GetDefinition(), false) );
          if ( macroDef )
          {

            //     
            IFeatureCollectionPtr featureCol( macroDef->FeatureCollection(), false );
            if ( featureCol )
            {
              //    
              IFeaturePtr feature( featureCol->First(), false );
              if ( feature )
              {
                //    
                IEntityPtr cutExtrusion( IUnknownPtr(feature->GetObject(), false) );
                if ( cutExtrusion )
                {
                  feature->SetExcluded( oldExclude );
                  //       
                  ICutExtrusionDefinitionPtr cutDef( IUnknownPtr(cutExtrusion->GetDefinition(), false) );
                  {
                    //  
                    IEntityPtr sketch( cutDef->GetSketch(), false );
                    if ( sketch )
                    {
                      //    
                      ISketchDefinitionPtr sketchDef( IUnknownPtr(sketch->GetDefinition(), false) );
                      // 
                      if ( sketchDef )
                      {
                        sketchDef->SetPlane( face1 );
                        sketch->Update();
                        //   
                        if ( !UpdateVariable( sketch ) )
                        {
                          if ( sketchDef->BeginEdit() )
                          {
                            ClearCurrentSketch();
                            reference c = Circle( 0, 0, rad, 1/*  - */);
                            varName = CreateVariable( c );
                            sketchDef->EndEdit();
                          }
                        }  
                      }  
                    }
                    //   
                    cutDef->SetDirectionType( dtNormal );
                    cutDef->SetSideParam( TRUE, etUpToSurfaceTo, 0, 0, FALSE );
                    cutDef->SetDepthObject( TRUE, face2 );
                  }
                  //    
                  cutExtrusion->Update();
                }
                doc->ExcludeFeaturesAfter( feature, FALSE );
              }
            }  
          }
          //  
          macroObject->Update();
          SetUserData();
//            part->RebuildModelEx( true );  
          doc->RebuildDocument();
        }  
      }  
    }  
  }
}


//-----------------------------------------------------------------------------
//   
// ---
void Orifice::EndProcess() 
{
  if ( rolbackFeature )
  {
    IDocument3DPtr doc( ksGetActive3dDocument(), false );
    if ( doc )
    {
      doc->SetRollBackFeature( rolbackFeature );  
      if ( macroObject )
      {
        IFeaturePtr macroFeature ( macroObject->GetFeature(), false );

        IFeatureCollectionPtr featureCol( macroFeature->SubFeatureCollection(true, true), false );
        if ( featureCol )
        {
          //    
          IFeaturePtr feature( featureCol->First(), false );
          if ( feature )
          {
            doc->ExcludeFeaturesAfter( feature, false );
            feature->SetExcluded( oldExclude );
          }
        }
      }
    } 
  }
  PropertyManagerObject::EndProcess();
}


//-----------------------------------------------------------------------------
//
// ---
_bstr_t Orifice::CreateVariable( reference c )
{
  _bstr_t res;
  if ( c )
  {
    CircleParam par;
    GetObjParam( c, &par, sizeof(par), ALLPARAM );
//    IDrawingObjectPtr obj( IUnknownPtr(ksTransferReference(c, activeDoc->Reference), false/*addref*/) ); 

    RDimParam parRDim; //       
    memset( &parRDim, 0, sizeof( parRDim ) );
    parRDim.dPar.pt1      = 1;   //       ( 0 -  , 1 - , 2 - , 3 - , 4 -  )
    parRDim.dPar.pt2      = 1;   //       ( 0 -  , 1 - , 2 - , 3 - , 4 -  )

    //   
    parRDim.tPar.sign    = 1; //      ( 0 -  , 1 - , 2 - ,
    // 3 - , > 3 -     Symbol type A )
 
    parRDim.tPar.bitFlag = _AUTONOMINAL; 
  
    //   
    parRDim.sPar.xc  = par.xc;  //  
    parRDim.sPar.yc  = par.yc; 
    parRDim.sPar.rad = par.rad; // 
    
    //   
    reference rDiamDimension = DiamDimension( &parRDim );

    IKompasDocument2DPtr activeDoc( appl->ActiveDocument );
     
    if ( activeDoc )
    {
      //    API7   reference
      IDrawingObject1Ptr obj( IUnknownPtr(ksTransferReference(rDiamDimension, activeDoc->Reference), false/*addref*/) ); 
      if ( obj )
      {
        obj->Associate(); 
        IParametriticConstraintPtr constraint( obj->NewConstraint() );
        if ( constraint )
        {
          constraint->ConstraintType = ksCFixedDim;
          constraint->Comment        = _bstr_t( " " );
          
          constraint->Create();
        }  
        constraint = obj->NewConstraint();
        if ( constraint )
        {
          constraint->ConstraintType = ksCDimWithVariable;
          constraint->Comment        = _bstr_t( "" );
          
          BOOL r = constraint->Create();
          if ( r )
            res = constraint->Variable;
        }  
      }
    }                         
  } 
  return res;
}


//-----------------------------------------------------------------------------
//
// ---
bool Orifice::UpdateVariable( IEntityPtr & sketch )
{
  bool res = false;
  if ( sketch )
  {
    IFeaturePtr sketchFeat( sketch->GetFeature(), false );
    if ( sketchFeat )
    {
      IVariableCollectionPtr coll( sketchFeat->VariableCollection(), false );
      if ( (bool)coll && coll->GetCount() > 0  )
      {
        IVariablePtr var( coll->GetByName(varName, TRUE, TRUE), false );
        if ( var )
        {
          res = !!var->SetValue( diameter );
        }   
      }  
    }
  }
  return res;
}


