bool CSkeletonCandidate::AddNode(CBaseNode *pNode, int parentId)
{
	// check if the node is valid
	if(pNode == 0)
	{
		theExporter.SetLastError("Invalid handle!", __FILE__, __LINE__);
		return false;
	}

        // Don't add any nodes that have already been added.
        for (size_t i = 0; i < m_vectorBoneCandidate.size(); ++i)
        {
            if (*m_vectorBoneCandidate[i]->GetNode() == *pNode)
            {
                delete pNode;
                return true;
            }
        }

	// if the node does not get used, we have to delete it!
	bool bDeleteNode = true;

	// Check if the node is a candidate
	//We want to be able to export all type of nodes as bones...
	//if(theExporter.GetInterface()->IsBone(pNode) || theExporter.GetInterface()->IsDummy(pNode))
	{
		// allocate a new bone candidate
		CBoneCandidate *pBoneCandidate = new CBoneCandidate;
		if(pBoneCandidate == 0)
		{
			delete pNode;
			theExporter.SetLastError("Memory allocation failed!", __FILE__, __LINE__);
			return false;
		}

		// create the bone candidate
		if(!pBoneCandidate->Create(m_vectorBoneCandidate.size(), parentId, pNode))
		{
			delete pBoneCandidate;
			return false;
		}

		//when the node is a dummy, it's not selected, so select it anyway...
		pBoneCandidate->SetSelected(true);

		// insert node element into hierarchy
		m_vectorBoneCandidate.push_back(pBoneCandidate);

		// insert node element id into parent node element
		if(parentId == -1)
		{
			// no parent -> this is a root node
			m_listRootBoneCandidateId.push_back(pBoneCandidate->GetId());
		}
		else
		{
			// valid parent -> this is a child node
			m_vectorBoneCandidate[parentId]->AddChildId(pBoneCandidate->GetId());
		}

		// set parent id for the children
		parentId = pBoneCandidate->GetId();

		bDeleteNode = false;
	}

	// handle all children of the node
	for(int childId = 0; childId < pNode->GetChildCount(); childId++)
	{
		if(!AddNode(pNode->GetChild(childId), parentId))
		{
			// free the node of needed
			if(bDeleteNode)
			{
				delete pNode;
			}

			return false;
		}
	}

	// free the node of needed
	if(bDeleteNode)
	{
		delete pNode;
	}

	return true;
}
bool CMaxInterface::ExportAnimationFromMaxscriptCall(const std::string& strFilename, void* _AnimExportParams)
{
	if (!_AnimExportParams)
	{
		theExporter.SetLastError("_AnimExportParams pointer is null.", __FILE__, __LINE__);
		return false;
	}

	AnimExportParams*	param = reinterpret_cast<AnimExportParams*>(_AnimExportParams);


	// build a skeleton candidate
	CSkeletonCandidate skeletonCandidate;

	//Remove user interface
	/*// show export wizard sheet
	CAnimationExportSheet sheet("Cal3D Animation Export", GetMainWnd());
	sheet.SetSkeletonCandidate(&skeletonCandidate);
	sheet.SetAnimationTime(GetStartFrame(), GetEndFrame(), GetCurrentFrame(), GetFps());
	sheet.SetWizardMode();
	if(sheet.DoModal() != ID_WIZFINISH) return true;
	*/

	//Following block replaces the user interface interactions
	{
		// create the skeleton candidate from the skeleton file
		if(! skeletonCandidate.CreateFromSkeletonFile(param->m_skeletonfilepath))
		{
			AfxMessageBox(theExporter.GetLastError().c_str(), MB_OK | MB_ICONEXCLAMATION);
			return false;
		}	

		//Set all bones in our array of nodes selected
		std::vector<CBoneCandidate *>& vectorBoneCandidate = skeletonCandidate.GetVectorBoneCandidate();

		int NumElemInTabMaxscript = param->m_tabbones.Count();

		// Select bone candidates that are in our array
		int idx = 0;
		const int numelems = vectorBoneCandidate.size();
		for (idx = 0;idx<numelems;idx++)
		{
			CBoneCandidate * bonecandidate = vectorBoneCandidate[idx];
			if (! bonecandidate)return false;

			//Deselect it
			bonecandidate->SetSelected(false);
			
			int j;
			for (j=0;j<NumElemInTabMaxscript;j++)
			{
				std::string bcname		= bonecandidate->GetNode()->GetName();
				std::string	bonename	= param->m_tabbones[j]->GetName();

				if (bcname == bonename)
				{
					//This bone candidate is in the array passed by maxscript, so select it.
					bonecandidate->SetSelected(true);
					break;
				}
			}
		}
	}

  CalCoreAnimationPtr coreAnimation = theExporter.ExtractAnimation(
      skeletonCandidate,
      param->m_startframe,
      param->m_endframe,
      param->m_frameoffset,
      GetFps(),
      param->m_framerate);
  if (!coreAnimation)
  {
    return false;
  }

  // save core animation to the file
	if(!CalSaver::saveCoreAnimation(strFilename, coreAnimation.get()))
	{
		theExporter.SetLastError(CalError::getLastErrorText(), __FILE__, __LINE__);
		return false;
	}

	return true;
}