CStatus AlembicWriteJob::Process()
{
    // check filenames
    if(mFileName.IsEmpty())
    {
        Application().LogMessage(L"[alembic] No filename specified.",siErrorMsg);
        return CStatus::InvalidArgument;
    }

    // check objects
    if(mSelection.GetCount() == 0)
    {
        Application().LogMessage(L"[alembic] No objects specified.",siErrorMsg);
        return CStatus::InvalidArgument;
    }

    // check frames
    if(mFrames.size() == 0)
    {
        Application().LogMessage(L"[alembic] No frames specified.",siErrorMsg);
        return CStatus::InvalidArgument;
    }

    // init archive (use a locally scoped archive)
    CString sceneFileName = L"Exported from: "+Application().GetActiveProject().GetActiveScene().GetParameterValue(L"FileName").GetAsText();
    mArchive = CreateArchiveWithInfo(
                   Alembic::AbcCoreHDF5::WriteArchive(),
                   mFileName.GetAsciiString(),
                   "Softimage Alembic Plugin",
                   sceneFileName.GetAsciiString(),
                   Alembic::Abc::ErrorHandler::kThrowPolicy);

    // get the frame rate
    double frameRate = 25.0;
    CValue returnVal;
    CValueArray args(1);
    args[0] = L"PlayControl.Rate";
    Application().ExecuteCommand(L"GetValue",args,returnVal);
    frameRate = returnVal;
    if(frameRate == 0.0)
        frameRate = 25.0;
    double timePerSample = 1.0 / frameRate;

    // create the sampling
    AbcA::TimeSampling sampling(timePerSample,0.0);
    mTs = mArchive.addTimeSampling(sampling);

    Alembic::Abc::OBox3dProperty boxProp = Alembic::AbcGeom::CreateOArchiveBounds(mArchive,mTs);

    // create object for each
    std::vector<AlembicObjectPtr> objects;
    for(LONG i=0; i<mSelection.GetCount(); i++)
    {
        X3DObject xObj(mSelection[i]);
        if(xObj.GetType().IsEqualNoCase(L"camera"))
        {
            AlembicObjectPtr ptr;
            ptr.reset(new AlembicCamera(xObj.GetActivePrimitive().GetRef(),this));
            objects.push_back(ptr);
        }
        else if(xObj.GetType().IsEqualNoCase(L"polymsh"))
        {
            AlembicObjectPtr ptr;
            ptr.reset(new AlembicPolyMesh(xObj.GetActivePrimitive().GetRef(),this));
            objects.push_back(ptr);
        }
    }

    ProgressBar prog;
    prog = Application().GetUIToolkit().GetProgressBar();
    prog.PutMinimum(0);
    prog.PutMaximum((LONG)(mFrames.size() * objects.size()));
    prog.PutValue(0);
    prog.PutCancelEnabled(true);
    prog.PutVisible(true);

    for(unsigned int frame=0; frame < (unsigned int)mFrames.size(); frame++)
    {
        for(size_t i=0; i<objects.size(); i++)
        {
            prog.PutCaption(L"Frame "+CString(mFrames[frame])+L" of "+objects[i]->GetRef().GetAsText());
            CStatus status = objects[i]->Save(mFrames[frame]);
            if(status != CStatus::OK)
                return status;
            if(prog.IsCancelPressed())
                break;
            prog.Increment();
        }
        if(prog.IsCancelPressed())
            break;
    }

    prog.PutVisible(false);

    return CStatus::OK;
}
XSIPLUGINCALLBACK CStatus Coat3DExport_Execute( CRef& in_ctxt )
{
	// Unpack the command argument values
	Context ctxt( in_ctxt );
	CValueArray args = ctxt.GetAttribute(L"Arguments");
	CString string;

	// A 3d object with a mesh geometry must be selected
	Selection selection(app.GetSelection());

	bool isPolymesh = true;
	for(int i =0; i< selection.GetCount(); i++)
	{
		X3DObject obj(selection[i]);
		//app.LogMessage(L"obj.IsA(siPolygonMeshID): " + CString(obj.GetType()));
		if(obj.GetType() != L"polymsh" )
		{
			isPolymesh = false;
			break;
		}
	}

	if (selection.GetCount() > 0 && isPolymesh)
	{
		gV = 0; gVn = 0; gVt = 0;
		gVprev = 0; gVnPrev = 0; gVtPrev = 0;
		// prepare the output text file
		CString strOut = Get3DCoatParam( L"tempLocation" ).GetValue();
		
		std::ofstream mfw;
		mfw.open(strOut.GetAsciiString(), std::ios_base::out | std::ios_base::trunc);
		if (mfw.is_open())
		{
			bar.PutMaximum( selection.GetCount() );
			bar.PutStep( 1 );
			bar.PutVisible( true );		

			OutputHeader( mfw);				
			// output the data
			for (int i=0; i < selection.GetCount(); i++)
			{
				gObjCnt = i;
				gVprev = gV;
				gVtPrev = gVt;
				gVnPrev = gVn;
				X3DObject xobj(selection.GetItem(i));

				bar.PutValue(i);
				bar.PutCaption( L"Exporting " + xobj.GetName());

				mfw << "\n";
				mfw << "# Hierarchy (from self to top father)\n";
				string = L"g " + xobj.GetName() + L"\n";
				mfw << string.GetAsciiString();
				mfw << "\n";

				// Get a geometry accessor from the selected object	
				Primitive prim = xobj.GetActivePrimitive();
				PolygonMesh mesh = prim.GetGeometry();
				if (!mesh.IsValid()) return CStatus::False;

				CGeometryAccessor ga = mesh.GetGeometryAccessor();

				OutputVertices( mfw, ga, xobj );
				if (bar.IsCancelPressed()) return CStatus::False;
				OutputPolygonComponents( mfw, ga );
				if (bar.IsCancelPressed()) return CStatus::False;
				//bar.Increment();		
			}
		}
		mfw.close();

		if(Get3DCoatParam(L"bExpMat").GetValue())
		{
			OutputMaterials(selection );
		}
		bar.PutStatusText( L"import.txt" );
		OutputImportTxt();
		bar.PutVisible(false);
                app.LogMessage(L"Export done!");
	}
	else
	{
		app.LogMessage(L"Please, select objects!", siWarningMsg);
		return CStatus::False;
	}

	return CStatus::OK;
}