text:
#define FUSION_MAX_VECTOR_SIZE 16

#define BOOST_FUSION_INVOKE_MAX_ARITY 16
#define BOOST_FUSION_INVOKE_PROCEDURE_MAX_ARITY 16
#define BOOST_FUSION_INVOKE_FUNCTION_OBJECT_MAX_ARITY 16
#define BOOST_FUSION_UNFUSED_MAX_ARITY 16
#define BOOST_FUSION_UNFUSED_TYPE_MAX_ARITY 16

#include <iostream>

#include <boost/fusion/include/boost_array.hpp>
#include <entity_as_boost_fusion_sequence.hpp>

#include <core/ENTITY_CONCEPT.hpp>

#include <meta/plaintuple.hpp>
#include <entities/ConceptedRASeq.hpp>
#include <meta/format.hpp>
#include <string>

#define dDOUBLE
#include <ode/ode.h>
#include <ode/odedirect.h>
#include <drawstuff/drawstuff.h>

#include <plainQVM.hpp>
#include <boost_array_as_boost_qvm.hpp>

#include <Ogre.h>
#include <CEGUI.h>
#include <RendererModules/Ogre/CEGUIOgreRenderer.h>
#include "OISRouter.hpp"
#include <map>

namespace EntityConcepts{
	GENSIM_ENTITY_CONCEPT(			RigidBodyDynamics3D,
		PositionVector,
		OrientationQuat,
		LinearVelocityVector,
		AngularVelocityVector
		)

	//This more generic version is reserved for future use
	//GENSIM_ENTITY_CONCEPT(			RigidBodyDynamics,
	//	Position,
	//	Orientation,
	//	LinearVelocity,
	//	AngularVelocity
	//	)

	//discard PR and PU joints (asymmetry)
	//discard Hinge-2 (same as universal)
	//discard Fixed
	//GENSIM_ENTITY_CONCEPT(			JointAttachment,
	//	BodyIdentifier,
	//	SpatialConfiguration
	//)

	GENSIM_ENTITY_CONCEPT(			Joint,
		AttachedObjectIdentifierPair,
		SpatialConfigurationPair
	)

	//namespace JointAttachmentGeometryParam{
	//	GENSIM_ENTITY_CONCEPT(			Ball,
	//		AnchorPosition,
	//	)

	//	GENSIM_ENTITY_CONCEPT(			Hinge,
	//		AnchorPosition,
	//		AxisDirectionVector
	//	)

	//	GENSIM_ENTITY_CONCEPT(			Slider,
	//		AnchorPosition,
	//		AnchorOrientationQuat
	//	)

	//	GENSIM_ENTITY_CONCEPT(			Universal,
	//		AnchorPosition,
	//		AxisDirectionVector
	//	)

	//	GENSIM_ENTITY_CONCEPT(			Piston,
	//		AnchorPosition,
	//		AxisDirectionVector
	//	)
	//}

	GENSIM_ENTITY_CONCEPT(			Component,
		GameplayStates,
		Shape,
		MassDistribution,
		RigidBodyStates
		)

	//GENSIM_ENTITY_CONCEPT(			SeparableComponentParameter,
	//	GameplayStates,
	//	Shape,
	//	MassDistribution
	//	)

	GENSIM_ENTITY_CONCEPT(			Cylinder,
		Length,
		Radius
		)

	GENSIM_ENTITY_CONCEPT(			Box,
		Size
		)

	GENSIM_ENTITY_CONCEPT(			Sphere,
		Radius
		)

	GENSIM_ENTITY_CONCEPT(			ConstantDensityMassDistribution,
		Density
		)

	GENSIM_ENTITY_CONCEPT(			SpatialConfiguration,
		PositionVector,
		OrientationQuat
		)

	GENSIM_ENTITY_CONCEPT(			SpatialTransform,
		Translation,
		Rotation,
		Scale
		)

	GENSIM_ENTITY_CONCEPT(			GeometryInstance,
		Geometry,
		SpatialConfiguration
		)

	//Assume that orientation is always quat for now.
	//GENSIM_ENTITY_CONCEPT(			Orientation,
	//	Quaternion,
	//	LinearTransformMatrix,
	//	AffineTransformMatrix,
	//	EularAngle
	//	)
}

struct EmptyStruct{};

namespace EC = EntityConcepts;

typedef dReal Real;

typedef boost::array<Real,2> Real2;
typedef boost::array<Real,3> Real3;
typedef boost::array<Real,4> Real4;
typedef MakeSquarePlainMatrix<Real,4,false>::Type Real44;
typedef MakeSquarePlainMatrix<Real,3,false>::Type Real33;
typedef PlainMatrix<Real,4,3,false> Real43;
typedef boost::array<Real,4> Quaternion;

typedef Real Scalar;
typedef Real2 Vector2;
typedef Real3 Vector3;
typedef Real4 Vector4;
typedef Real44 Matrix44;
typedef Real43 Matrix43;

typedef Vector3 Vector;
typedef Matrix44 AffineMatrix;

//
typedef Vector3 PositionVector;
typedef Quaternion OrientationQuat;
typedef GenericSim::Meta::MakePlainTuple< EC::RigidBodyDynamics3D, PositionVector, OrientationQuat, Vector, Vector >::Type RigidBodyInst;
typedef GenericSim::Meta::MakePlainTuple< EC::SpatialConfiguration, PositionVector, OrientationQuat >::Type SpatialConfiguration;
//typedef GenericSim::Meta::MakePlainTuple< EC::Component,int,Box,
typedef GenericSim::Meta::MakePlainTuple< EC::ConstantDensityMassDistribution, Real >::Type ConstantDensityMassDistribution;
typedef GenericSim::Meta::MakePlainTuple< EC::SpatialTransform, PositionVector, OrientationQuat, Real >::Type SpatialTransform;
template< typename _Shape > struct MakeSimpleComponent
{
	typedef typename GenericSim::Meta::MakePlainTuple< EC::Component, int, _Shape, ConstantDensityMassDistribution, RigidBodyInst >::Type Type;
};
//typedef boost::array< SpatialConfiguration, 2 > JointAttachmentPair;

typedef int ShortIdentifier;

//typedef GenericSim::Meta::MakePlainTuple< EC::Joint, JointAttachmentPair>::Type BallJoint;
typedef boost::array< ShortIdentifier, 2 > JointAttachedObjectIdentifierPair;
typedef boost::array< SpatialConfiguration, 2> JointSpatialConfigurationPair;
typedef GenericSim::Meta::MakePlainTuple< EC::Joint, JointAttachedObjectIdentifierPair, JointSpatialConfigurationPair >::Type BallJoint;

#include "utility/PairedCall.hpp"

#include <vector>

template< class _EntityConcept, BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( GENSIM_PLAIN_TUPLE_MAX_SIZE, class _T, void ) >
struct MakeRenderListItem{
	typedef typename GenericSim::Meta::MakePlainTuple< _EntityConcept, BOOST_PP_ENUM_PARAMS( GENSIM_PLAIN_TUPLE_MAX_SIZE, _T ) >::Type Type;
};

typedef GenericSim::Meta::MakePlainTuple< EC::Cylinder, Scalar, Scalar >::Type Cylinder;
typedef GenericSim::Meta::MakePlainTuple< EC::Box, Vector >::Type Box;
typedef GenericSim::Meta::MakePlainTuple< EC::Sphere, Scalar >::Type Sphere;

//typedef MakeSimpleComponent<Cylinder>::Type SimpleCylinderComponent;
typedef MakeSimpleComponent<Box>::Type SimpleBoxComponent;
//typedef MakeSimpleComponent<Sphere>::Type SimpleSphereComponent;

static dWorldID world;
static dSpaceID space;
//static dBodyID body;
//static dGeomID geom;
//static dMass m;
static dJointGroupID contactgroup;

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);
    dContact contact;
    contact.surface.mode = dContactBounce | dContactSoftCFM;
    // friction parameter
    contact.surface.mu = dInfinity;
    // bounce is the amount of "bouncyness".
    contact.surface.bounce = 0.9;
    // bounce_vel is the minimum incoming velocity to cause a bounce
    contact.surface.bounce_vel = 0.01;
    // constraint force mixing parameter
    contact.surface.soft_cfm = 0.001;
    if (int numc = dCollide (o1,o2,1,&contact.geom,sizeof(dContact))) {
        dJointID c = dJointCreateContact (world,contactgroup,&contact);
        dJointAttach (c,b1,b2);
    }
	//std::cout<<"nearCallack\n";
}

static void start()
{
    static float xyz[3] = {2.0f,-2.0f,1.7600f};
    static float hpr[3] = {140.000f,-17.0000f,0.0000f};
    dsSetViewpoint (xyz,hpr);
}

#include <algorithm>
#include <short_array.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>

static void simLoop (int pause)
{
    dSpaceCollide (space,0,&nearCallback);
    dWorldStep (world,0.01);
    dJointGroupEmpty (contactgroup);
}

template< int N, typename T >
T (&PointerAsCArray( T *p ))[N]{
	return
		static_cast<T (&)[N]>(
			*static_cast<T(*)[N]>(
				static_cast<typename boost::mpl::if_<boost::is_const<T>,const void *,void*>::type>(p)
			)
		);
}

#include <boost/qvm/v_traits_array.hpp>
#include <boost/qvm/sw.hpp>

template<typename _SpatialConfigurationPair>
void SetOpenDEBallJointSpatialConfiguration( const _SpatialConfigurationPair &c, dxJointBall *p ){
	using namespace boost::qvm;
	using namespace boost::fusion;
	boost::qvm::assign( p->anchor1,	at_c<0>(c).at_e<EC::SpatialConfiguration::PositionVector>()%XYZ0() );
	boost::qvm::assign( p->anchor2, at_c<1>(c).at_e<EC::SpatialConfiguration::PositionVector>()%XYZ0() );
	//p->anchor1[3]=p->anchor2[3]=0;
}

#include <boost/foreach.hpp>
#include <boost/range.hpp>
#include <boost/fusion/functional/invocation/invoke_procedure.hpp>
#include <boost/fusion/include/push_front.hpp>
#include <boost/fusion/include/array.hpp>
#include <boost/qvm/qvm.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/adapted/boost_tuple.hpp>
#include <boost/fusion/include/make_fused.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/range/algorithm/equal.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/irange.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <iterator>
#include <boost/qvm/v_traits_array.hpp>
#include <boost/range/metafunctions.hpp>
#include <WRAP_TMP_PROC.hpp>
#include <boost/fusion/include/boost_array.hpp>

template< typename _RigidBody3DEntity >
typename boost::enable_if_c
<
	GenericSim::Meta::IsEntity<_RigidBody3DEntity>::value
	&& boost::is_same<typename _RigidBody3DEntity::entity_concept_type, EC::RigidBodyDynamics3D>::value
>::type
SetOpenDERigidBody( const _RigidBody3DEntity &body, dBodyID odeBodyID )
{
	//using namespace boost::qvm;
	//dBodySetPosition
	//(
	//	*itrOdeBody,
	//	itrBody->at_e<EC::RigidBodyDynamics3D::PositionVector>()%X,
	//	itrBody->at_e<EC::RigidBodyDynamics3D::PositionVector>()%Y,
	//	itrBody->at_e<EC::RigidBodyDynamics3D::PositionVector>()%Z
	//);
	boost::fusion::invoke_procedure
	(
		dBodySetPosition,
		boost::fusion::push_front( body.at_e<EC::RigidBodyDynamics3D::PositionVector>(), odeBodyID )
	);
	dQuaternion q;
	boost::qvm::assign( q,body.at_e<EC::RigidBodyDynamics3D::OrientationQuat>() );
	//dBodySetQuaternion( odeBodyID, boost::qvm::make<dQuaternion>(body.at_e<EC::RigidBodyDynamics3D::OrientationQuat>()) );
	dBodySetQuaternion( odeBodyID, q );
	boost::fusion::invoke_procedure
	(
		dBodySetLinearVel,
		boost::fusion::push_front( body.at_e<EC::RigidBodyDynamics3D::LinearVelocityVector>(), odeBodyID )
	);
	boost::fusion::invoke_procedure
	(
		dBodySetAngularVel,
		boost::fusion::push_front( body.at_e<EC::RigidBodyDynamics3D::AngularVelocityVector>(), odeBodyID )
	);
}
WRAP_TMP_PROC( 2, SetOpenDERigidBody );

template< typename _RigidBody3DEntity >
typename boost::enable_if_c
<
	GenericSim::Meta::IsEntity<_RigidBody3DEntity>::value
	&& boost::is_same<typename _RigidBody3DEntity::entity_concept_type, EC::RigidBodyDynamics3D>::value
>::type
GetOpenDERigidBody( _RigidBody3DEntity &body, dBodyID odeBodyID )
{
	//exit(0);
	//typedef const dReal r3[3];
	//TODO: change to fusion algorithm   assign() and make()
	boost::qvm::assign( body.at_e<EC::RigidBodyDynamics3D::PositionVector>(), PointerAsCArray<3>(dBodyGetPosition(odeBodyID)) );
	boost::qvm::assign(	body.at_e<EC::RigidBodyDynamics3D::OrientationQuat>(), PointerAsCArray<4>(dBodyGetQuaternion(odeBodyID)) );
	boost::qvm::assign( body.at_e<EC::RigidBodyDynamics3D::LinearVelocityVector>(), PointerAsCArray<3>(dBodyGetLinearVel(odeBodyID)) );
	boost::qvm::assign( body.at_e<EC::RigidBodyDynamics3D::AngularVelocityVector>(), PointerAsCArray<3>(dBodyGetAngularVel(odeBodyID)) );
}
WRAP_TMP_PROC( 2, GetOpenDERigidBody );

template<
	typename _Deletion_SinglePassReadableRange,
	typename _Moving_SinglePassReadableRange,
	typename _Mapping_AssociativeContainer,
	typename _ValuePredestructionProc
>
void MappingFollowDeletionAndMoving(
	const _Deletion_SinglePassReadableRange &deletionList,
	const _Moving_SinglePassReadableRange &movingList,
	_Mapping_AssociativeContainer &map,
	_ValuePredestructionProc f
){
	using namespace boost::fusion;
	typedef typename _Mapping_AssociativeContainer::iterator itr_type;
	BOOST_FOREACH( typename boost::range_reference<const _Deletion_SinglePassReadableRange>::type p, deletionList )
	{
		assert(0);// simple deletion is not used for now.
		itr_type i = map.find(p);
		assert(i!=map.end());
		f(i->second);
		map.erase(i);
	}
	BOOST_FOREACH( typename boost::range_reference<const _Moving_SinglePassReadableRange>::type p, movingList )
	{
		using namespace boost::fusion;
		itr_type from = map.find(at_c<0>(p));
		assert(from!=map.end());
		if( (!map.key_comp()(at_c<0>(p),at_c<1>(p))) &&
			(!map.key_comp()(at_c<1>(p),at_c<0>(p)))
		){
			f(from->second);
		}else{
			itr_type to = map.lower_bound(at_c<1>(p));
			assert(from!=to);
			if( map.end()!=to && !map.key_comp()(at_c<1>(p),to->first) ){
				f(to->second);
				to->second = from->second;
			}else{
				assert(0);//This should not happen for now.
				map.insert(to,std::make_pair(at_c<1>(p),from->second));
			}
		}
		map.erase(from);
	}
}

void DestroyODEBody(dBodyID b){
	assert(0==dBodyGetNumJoints(b));
	dBodyDestroy(b);
}

template<
	typename _RigidBodyInstHandleDeletion_SinglePassReadableRange,
	typename _RigidBodyInstHandleMoving_SinglePassReadableRange,
	typename _RigidBodyInstHandleInsertion_SinglePassReadableRange,
	typename _BallJointHandleDeletion_SinglePassReadableRange,
	typename _BallJointHandleMoving_SinglePassReadableRange,
	typename _BallJointHandleInsertion3tuple_SinglePassReadableRange,
	typename _RigidBodyInstHandleODEMapping_AssociativeContainer,
	typename _BallJointHandleODEMapping_AssociativeContainer
>
void ManageODEObjectLifetime(
	const _RigidBodyInstHandleDeletion_SinglePassReadableRange		&rigidBodyDeletionList,
	const _RigidBodyInstHandleMoving_SinglePassReadableRange		&rigidBodyMovingList,
	const _RigidBodyInstHandleInsertion_SinglePassReadableRange		&rigidBodyInsertionList,
	const _BallJointHandleDeletion_SinglePassReadableRange			&ballJointDeletionList,
	const _BallJointHandleMoving_SinglePassReadableRange			&ballJointMovingList,
	const _BallJointHandleInsertion3tuple_SinglePassReadableRange	&ballJointInsertionList,
	_RigidBodyInstHandleODEMapping_AssociativeContainer		&odeRigidBodies,
	_BallJointHandleODEMapping_AssociativeContainer			&odeBallJoints,
	dWorldID	odeWorld
)
{
	using namespace boost::fusion;
	typedef typename _RigidBodyInstHandleODEMapping_AssociativeContainer::iterator itrRigidBody;
	MappingFollowDeletionAndMoving(ballJointDeletionList,ballJointMovingList,odeBallJoints,&dJointDestroy);
	MappingFollowDeletionAndMoving(rigidBodyDeletionList,rigidBodyMovingList,odeRigidBodies,&DestroyODEBody);
	BOOST_FOREACH( typename boost::range_reference<const _RigidBodyInstHandleInsertion_SinglePassReadableRange>::type p, rigidBodyInsertionList )
	{
		assert( odeRigidBodies.find(p)==odeRigidBodies.end() );
		odeRigidBodies.insert(std::make_pair(p,dBodyCreate(odeWorld)));
	}
	BOOST_FOREACH( typename boost::range_reference< const _BallJointHandleInsertion3tuple_SinglePassReadableRange >::type p, ballJointInsertionList )
	{
		dJointID j = dJointCreateBall(odeWorld,0);
		odeBallJoints.insert(std::make_pair(at_c<0>(p),j));
		dJointAttach(j, odeRigidBodies.find(at_c<1>(p))->second, odeRigidBodies.find(at_c<2>(p))->second);
		SetOpenDEBallJointSpatialConfiguration( at_c<0>(p)->at_e<EC::Joint::SpatialConfigurationPair>() , dynamic_cast<dxJointBall*>(j) );
	}
}

template<typename _ODEStepProc>
class ODEWorldVariableStrideStep:public std::binary_function<dWorldID,dReal,void>,boost::noncopyable
{
	_ODEStepProc m_odeStepProc;
	dReal m_fixedODEStepSize;
	dReal m_remainingTime;
	dReal m_stopCriteria;
public:
	void operator()( dWorldID world, dReal deltaTime )
	{
		m_remainingTime+=deltaTime;
		while(m_remainingTime>m_stopCriteria){
			m_odeStepProc(world, m_fixedODEStepSize);
			m_remainingTime-=m_fixedODEStepSize;
		}
	}
	ODEWorldVariableStrideStep(_ODEStepProc odeProc, dReal fixedStep, dReal stopRatio):
		m_odeStepProc(odeProc),
		m_fixedODEStepSize(fixedStep),
		m_remainingTime(0),
		m_stopCriteria(stopRatio*fixedStep)
	{}
};

template< class F, class _Pair >
void CallHandleToObjectMappingPairProc( const F &f, const _Pair &p ){
	f( *p.first, p.second );
}
WRAP_TMP_PROC( 2, CallHandleToObjectMappingPairProc );

template<class _Proc>
class SimpleProcCEGUIEventHandler{
	_Proc m_p;
public:
	explicit SimpleProcCEGUIEventHandler(const _Proc &p):m_p(p){}
	bool operator()(const CEGUI::EventArgs&){
		m_p();
		return true;
	}
};

template <typename _ProcL, typename _ProcR>
class CEGUIMouseEventSimpleSplitter2{
	_ProcL m_l;
	_ProcR m_r;
public:
	CEGUIMouseEventSimpleSplitter2(const _ProcL &l, const _ProcR &r):m_l(l),m_r(r){}
	bool operator()(const CEGUI::EventArgs& e){
		switch(dynamic_cast<const CEGUI::MouseEventArgs &>(e).button)
		{
		case CEGUI::LeftButton:
			m_l();
			break;
		case CEGUI::RightButton:
			m_r();
			break;
		}
		return true;
	}
};

#include <boost/qvm/v.hpp>
template<typename V>
const V VectorParallelToCoordSysBase(unsigned iDim,typename boost::qvm::v_traits<V>::scalar_type const &signedLength){
	assert(iDim<boost::qvm::v_traits<V>::dim);
	V v;
	boost::qvm::set_zero(v);
	boost::qvm::v_traits<V>::iw(iDim,v) = signedLength;
	return v;
}

#include <Ogre_boost_qvm.hpp>
#include <boost/qvm/v.hpp>
#include <boost/qvm/q.hpp>

template<typename E>
typename boost::enable_if<GenericSim::Meta::IsEntity<E>>::type
SetOgreSceneNodeSpatialConfig(Ogre::SceneNode *sn, const E &e){
	SetOgreSceneNodeSpatialConfigByEntityConcept(sn, e, typename GenericSim::Meta::GetEntityConcept<E>::Type());
}

template<typename E>
void SetOgreSceneNodeSpatialConfigByEntityConcept(Ogre::SceneNode *sn, const E &e, EC::RigidBodyDynamics3D){
	sn->setPosition( boost::qvm::make<Ogre::Vector3>(
		e.at_e<EC::RigidBodyDynamics3D::PositionVector>()
	) );
	sn->setOrientation( boost::qvm::make<Ogre::Quaternion>(
		e.at_e<EC::RigidBodyDynamics3D::OrientationQuat>()
	) );
}

//struct NullProc(){
//	template<typename T>
//	void operator(T &){}
//};
//
//namespace Tree{
//	template<typename T,typename _PreProc,typename _PostProc>
//	std::pair<_PreProc,_PostProc> Traversal(T &treeNode, _PreProc pre, _PostProc post ){
//		struct impl{ void operator()( T &treeNode,_PreProc &pre,_PostProc &post ){
//			pre(treeNode);
//			std::for_each(TreeChildrenBegin(treeNode),TreeChildrenEnd(treeNode),impl());
//			post(treeNode);
//		} };
//		return std::make_pair(pre,post);
//	}
//}

//void DestroyOgreSceneNodeAttachedMovableObjects(Ogre::SceneNode *sn,Ogre::SceneManager *pScene){
//	struct impl{
//		Ogre::SceneManager *pScene;
//		void operator()( Ogre::SceneNode &nd ) const{
//			for(Ogre::SceneNode::ObjectIterator i = nd.getAttachedObjectIterator();i.hasMoreElements();){
//				Ogre::MovableObject *p = i.getNext();
//				pScene->destroyMovableObject( p );
//			}
//		}
//	};
//	Tree::Traversal(*sn,NullProc(),Utility::MakeAggr<impl>(pScene));
//}

void DestroyOgreSceneNodeAttachedMovableObjects(Ogre::SceneNode *sn,Ogre::SceneManager *pScene){
	for(Ogre::SceneNode::ChildNodeIterator i = sn->getChildIterator();i.hasMoreElements();){
		DestroyOgreSceneNodeAttachedMovableObjects(static_cast<Ogre::SceneNode*>(i.getNext()),pScene);
	}
	for(Ogre::SceneNode::ObjectIterator i = sn->getAttachedObjectIterator();i.hasMoreElements();){
		Ogre::MovableObject *p = i.getNext();
		pScene->destroyMovableObject( p );
	}
}

#include "GenericShapeToOCCT.hpp"
#include <boost/fusion/include/io.hpp>
#include <fstream>
#include <serialization/NaiveTabularTupleListStream.hpp>
//#include <sqlite3.h>
#include <boost/random.hpp>
#include <boost/functional/value_factory.hpp>
#include "OCCTMesh2OGRE.hpp"
#include <boost/lexical_cast.hpp>
#include <ctime>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/nview.hpp>
#include "NumericRange.hpp"
#include <boost/variant.hpp>
#include <conio.h>
#include <Utility/Make.hpp>
#include <Handles/HandleToElementOfRandomAccessRange.hpp>
#include <Handles/HandleToEntityState.hpp>
#include <Handles/PolyHandle.hpp>
#include <boost/range/algorithm/max_element.hpp>
#include <Ogre_boost_qvm.hpp>
#include "OCCTMeshUtils.hpp"
#include <Standard_TypeDef.hxx>
#include <BRepClass3d_SolidExplorer.hxx>
#include <TopoDS_Shape.hxx>
#include <BRepMesh.hxx>
#include <BRep_Tool.hxx>
#include <Poly_Triangulation.hxx>
#include <TShort_Array1OfShortReal.hxx>
#include <StdPrs_ToolShadedShape.hxx>
#include <Poly_Connect.hxx>
#include <TColgp_Array1OfDir.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <gce_MakeTranslation.hxx>
#include <gce_MakeRotation.hxx>
#include <gp_Quaternion.hxx>
#include <IntCurvesFace_ShapeIntersector.hxx>
#include <gp_Lin.hxx>
#include "EditMode.hpp"

//#include <boost/statechart/event.hpp>
//#include <boost/statechart/state_machine.hpp>
//#include <boost/statechart/simple_state.hpp>
//#include <boost/statechart/transition.hpp>

int main(int argc, char **argv){
	boost::mt19937 randGen;
	std::auto_ptr<Ogre::Root> pOgreRoot(new Ogre::Root(
#ifdef _DEBUG
		"plugins_d.cfg",
#else
		"plugins.cfg",
#endif
		"graphics.cfg",
		"graphics.log"
	));

	if(!pOgreRoot->showConfigDialog()){
		return 0;
	}
	Ogre::RenderWindow *pWindow = pOgreRoot->initialise(true,"The Catapult Game");

	OISSystem ois(pWindow);
	assert(ois.Keyboards().size()==1);
	assert(ois.Mice().size() == 1);

	{
		Ogre::ResourceGroupManager& lRgMgr = Ogre::ResourceGroupManager::getSingleton();
		pOgreRoot->addResourceLocation("datafiles","FileSystem","CEGUI",true);
		pOgreRoot->addResourceLocation("gui","FileSystem","CEGUI",true);
		pOgreRoot->addResourceLocation("","FileSystem");
		lRgMgr.initialiseAllResourceGroups();
	}
	CEGUI::OgreRenderer &ceguiRenderer = CEGUI::OgreRenderer::bootstrapSystem(*pWindow);
	{
		CEGUI::ResourceProvider* rp = //dynamic_cast<CEGUI::DefaultResourceProvider*>
			(CEGUI::System::getSingleton().getResourceProvider());/*
		rp->setResourceGroupDirectory("schemes", "datafiles/schemes/");
		rp->setResourceGroupDirectory("imagesets", "datafiles/imagesets/");
		rp->setResourceGroupDirectory("fonts", "datafiles/fonts/");
		rp->setResourceGroupDirectory("layouts", "datafiles/layouts/");
		rp->setResourceGroupDirectory("looknfeels", "datafiles/looknfeel/");
		rp->setResourceGroupDirectory("lua_scripts", "datafiles/lua_scripts/");
		rp->setResourceGroupDirectory("schemas", "datafiles/xml_schemas/");*/
		// set the default resource groups to be used
		CEGUI::Imageset::setDefaultResourceGroup("CEGUI");
		CEGUI::Font::setDefaultResourceGroup("CEGUI");
		CEGUI::Scheme::setDefaultResourceGroup("CEGUI");
		CEGUI::WidgetLookManager::setDefaultResourceGroup("CEGUI");
		CEGUI::WindowManager::setDefaultResourceGroup("CEGUI");
		CEGUI::ScriptModule::setDefaultResourceGroup("CEGUI");

		// setup default group for validation schemas
		CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
		if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))
			parser->setProperty("SchemaDefaultResourceGroup", "CEGUI");
	}
	{
		using namespace CEGUI;
		std::string a,b,c;
		std::ifstream("gui/r.cfg")>>a>>b>>c;
		SchemeManager::getSingleton().createAll( a,"CEGUI" );
		FontManager::getSingleton().createAll( b,"CEGUI" );
		ImagesetManager::getSingleton().createAll( c,"CEGUI" );
		std::ifstream("gui/d.cfg")>>a>>b>>c;
		System::getSingleton().setDefaultFont(a);
		System::getSingleton().setDefaultMouseCursor(b,c);
		Window* myRoot = WindowManager::getSingleton().loadWindowLayout( "game.layout" );
		System::getSingleton().setGUISheet( myRoot );
	}

	Utility::PairedCall<dInitODE,dCloseODE> ode;

	CEGUI::Window *pSceneWindow = CEGUI::WindowManager::getSingleton().getWindow("_scene");
	assert(pSceneWindow);
	Ogre::SceneManager *pSceneManager(pOgreRoot->createSceneManager(Ogre::ST_GENERIC));
	Ogre::Camera *pCam = pSceneManager->createCamera("zzz");
	Ogre::Viewport *pViewport = pWindow->addViewport(pCam);
	{
		float x=8,y=8,z=8;
		std::ifstream("cam.txt")>>x>>y>>z;
		pCam->setPosition(Ogre::Vector3(x,y,z));
	}
	pCam->lookAt(Ogre::Vector3(0,0,0));
	pCam->setNearClipDistance(0.1);
	pCam->setFarClipDistance(20000);
	//pCam->setNearClipDistance(4);
	//pCam->setFarClipDistance(8);

	pSceneManager->showBoundingBoxes(true);
	pSceneManager->setSkyDome(true,"sky",10,8,4000,true,Ogre::Quaternion::IDENTITY,16,16);
	//{
	//	Ogre::StaticGeometry *pSG = pSceneManager->createStaticGeometry("floor");
	//	pSG->addEntity(pSceneManager->createEntity("tqqq","zzz.mesh"),Ogre::Vector3(0,0,0));
	//	pSG->build();
	//}
	{
		Ogre::Light *pL = pSceneManager->createLight("lll");
		pL->setType(Ogre::Light::LT_DIRECTIONAL);
		pL->setDirection(-1,-1,-3);
		pL->setDiffuseColour(1,1,1);
		pL->setSpecularColour(1,1,1);
		pSceneManager->setAmbientLight(Ogre::ColourValue(0,0,0));
	}

	Ogre::ResourceGroupManager::getSingleton().createResourceGroup("__OCCTGEN");
	bool go = true;

	std::vector<SimpleBoxComponent> boxes;
	std::vector<SimpleBoxComponent> protoBoxes;
	NaiveTabularTupleListStream::UseAsTupleListStream( std::ifstream("boxesIn.txt") )>>boxes;
	NaiveTabularTupleListStream::UseAsTupleListStream( std::ifstream("protoBoxes.txt") )>>protoBoxes;

	typedef GenericSim::Handles::HandleToElementOfRandomAccessRange< std::vector<SimpleBoxComponent>* > SimpleBoxComponentHandle;
	std::vector<SimpleBoxComponentHandle> sbcDeletionList;
	std::vector< boost::array<SimpleBoxComponentHandle,2> > sbcMovingList;
	std::vector<SimpleBoxComponentHandle> sbcInsertionList;

	typedef GenericSim::Handles::PolyHandle<RigidBodyInst> RigidBodyInstHandle;
	std::vector<RigidBodyInstHandle> rigidBodyDeletionList;
	std::vector< boost::array<RigidBodyInstHandle,2> > rigidBodyMovingList;
	std::vector<RigidBodyInstHandle> rigidBodyInsertionList;

	struct PostSimpleBoxComponentConstruction{
		std::vector<SimpleBoxComponent> &boxes;
		std::vector<SimpleBoxComponentHandle> &sbcInsertionList;
		std::vector<RigidBodyInstHandle> &rigidBodyInsertionList;
		void operator()(std::size_t i){
			using namespace GenericSim::Handles;
			rigidBodyInsertionList.push_back( MakePoly(
				MakeHandleToEntityState<EC::Component,EC::Component::RigidBodyStates >(
					Utility::Make<HandleToElementOfRandomAccessRange>( &boxes, i )
				)
			));
			sbcInsertionList.push_back( Utility::Make<HandleToElementOfRandomAccessRange>( &boxes, i ) );
		}
	};
	PostSimpleBoxComponentConstruction postAddingSimpleBoxComponent = { boxes, sbcInsertionList, rigidBodyInsertionList };

	struct ToAddSimpleBoxComponent{
		std::vector<SimpleBoxComponent> &boxes;
		GenericSim::Handles::PolyHandle< SimpleBoxComponent > hProto;
		PostSimpleBoxComponentConstruction postProc;
		void operator()(){
			int j = boxes.size();
			boxes.push_back(*hProto);
			postProc(j);
		}
	};

	BOOST_FOREACH( std::size_t i, boost::irange<std::size_t>(0,boxes.size()) ){
		postAddingSimpleBoxComponent(i);
	}

	BOOST_FOREACH( std::size_t i, boost::irange<std::size_t>(0,protoBoxes.size()) ){
		using namespace GenericSim::Handles;
		CEGUI::PushButton *pBtnSBCAdd = dynamic_cast<CEGUI::PushButton *>(
			CEGUI::WindowManager::getSingleton().getWindow( "_simpleBoxComponentAdd" + boost::lexical_cast<std::string>(i) )
		);
		assert(pBtnSBCAdd);
		pBtnSBCAdd->subscribeEvent(
			CEGUI::PushButton::EventClicked,
			Utility::Make<SimpleProcCEGUIEventHandler>(
				Utility::TieIntoAggr<ToAddSimpleBoxComponent>(
					boxes,
					MakePoly( Utility::Make<HandleToElementOfRandomAccessRange>( &protoBoxes, i ) ),
					postAddingSimpleBoxComponent
				)
			)
		);
	}

	std::vector<BallJoint> ballJoints;
	typedef GenericSim::Handles::HandleToElementOfRandomAccessRange< std::vector<BallJoint>* > BallJointHandle;

	NaiveTabularTupleListStream::UseAsTupleListStream( std::ifstream("BallJointsIn.txt") )>>ballJoints;
	std::vector< BallJointHandle > ballJointDeletionList;
	std::vector< boost::array<BallJointHandle,2> > ballJointMovingList;
	std::vector< boost::fusion::vector<BallJointHandle,RigidBodyInstHandle, RigidBodyInstHandle> > ballJointInsertionList;
	BOOST_FOREACH( std::size_t i, boost::irange<std::size_t>(0,ballJoints.size()) )
	{
		using namespace boost::fusion;
		using namespace GenericSim::Handles;
		ballJointInsertionList.push_back( make_vector(
			Utility::Make<HandleToElementOfRandomAccessRange>( &ballJoints, i),
			MakePoly(	MakeHandleToEntityState<EC::Component,EC::Component::RigidBodyStates>(
				Utility::Make<HandleToElementOfRandomAccessRange>( &boxes, at_c<0>(ballJoints[i].at_e<EC::Joint::AttachedObjectIdentifierPair>()) )
			) ),
			MakePoly(	MakeHandleToEntityState<EC::Component,EC::Component::RigidBodyStates>(
				Utility::Make<HandleToElementOfRandomAccessRange>( &boxes, at_c<1>(ballJoints[i].at_e<EC::Joint::AttachedObjectIdentifierPair>()) )
			) )
		) );
	}

	std::map< SimpleBoxComponentHandle, Ogre::SceneNode *> pBoxOgreSceneNodes;

    static dWorldID odeWorld = dWorldCreate();
	{
		dWorldSetGravity (odeWorld,0,0,0);
		dWorldSetERP(odeWorld,0.8);
	}

	ODEWorldVariableStrideStep<int (*)(dWorldID,dReal)> odeWorldStepper(dWorldStep,0.02,0.5);

	std::map<RigidBodyInstHandle, dBodyID> odeRigidBodies;
	std::map<BallJointHandle, dJointID> odeBallJoints;

	pCam->setAutoAspectRatio(true);
	time_t currentTime = clock();

	//Ogre::SceneNode *pTestSceneNode = pSceneManager->getRootSceneNode()->createChildSceneNode();
	//pTestSceneNode->attachObject(pSceneManager->createEntity("testSceneNode","unitSphere.mesh"));

	std::vector<std::size_t> sbcToDelete;

	CEGUI::PushButton *pBtnBJAdd = dynamic_cast<CEGUI::PushButton *>(CEGUI::WindowManager::getSingleton().getWindow("_ballJointAdd"));
	assert(pBtnBJAdd);

	std::size_t sbcSelected = std::numeric_limits<std::size_t>::max();

	EditMode::GameStatesRef emgs = {boxes,protoBoxes,sbcToDelete};
	EditMode editMode(emgs);
	editMode.SetOgreScene(pSceneManager);
	pSceneWindow->subscribeEvent(
		CEGUI::Window::EventMouseButtonDown,
		Utility::Make<CEGUIMouseEventSimpleSplitter2>(
			boost::bind(&EditMode::OnPrimaryPointerDown,&editMode),
			boost::bind(&EditMode::OnSecondaryPointerDown,&editMode)
		)
		//Utility::Make<SimpleProcCEGUIEventHandler>(boost::bind(&EditMode::OnMouseDown,&editMode))
	);
	pSceneWindow->subscribeEvent(
		CEGUI::Window::EventMouseButtonUp,
		Utility::Make<CEGUIMouseEventSimpleSplitter2>(
			boost::bind(&EditMode::OnPrimaryPointerUp,&editMode),
			boost::bind(&EditMode::OnSecondaryPointerUp,&editMode)
		)
		//Utility::Make<SimpleProcCEGUIEventHandler>(boost::bind(&EditMode::OnMouseUp,&editMode))
	);
	struct SceneWindowKeyHandler{
		EditMode &editMode;
		bool OnKeyDown(const CEGUI::EventArgs &e){
			const CEGUI::Key::Scan k = dynamic_cast<const CEGUI::KeyEventArgs &>(e).scancode;
			using namespace CEGUI;
			switch(k){
				case Key::Delete: editMode.DeleteSelected(); break;
				//case Key::LeftShift: editMode.SetRotatingMode(true); break;
			}
			return true;
		}
		bool OnKeyUp(const CEGUI::EventArgs &e){
			const CEGUI::Key::Scan k = dynamic_cast<const CEGUI::KeyEventArgs &>(e).scancode;
			using namespace CEGUI;
			switch(k){
				//case Key::Delete: editMode.DeleteSelected(); break;
				//case Key::LeftShift: editMode.SetRotatingMode(false); break;
			}
			return true;
		}
	};
	SceneWindowKeyHandler keyHandler = {editMode};
	pSceneWindow->subscribeEvent(
		CEGUI::Window::EventKeyDown,
		CEGUI::SubscriberSlot(&SceneWindowKeyHandler::OnKeyDown,&keyHandler)
	);
	pSceneWindow->subscribeEvent(
		CEGUI::Window::EventKeyUp,
		CEGUI::SubscriberSlot(&SceneWindowKeyHandler::OnKeyUp,&keyHandler)
	);
	pSceneWindow->subscribeEvent(
		CEGUI::Window::EventMouseEnters,
		Utility::Make<SimpleProcCEGUIEventHandler>(boost::bind(&CEGUI::Window::activate,pSceneWindow))
	);
	//pSceneWindow->subscribeEvent(
	//	CEGUI::Window::EventMouseClick,
	//	Utility::Make<SimpleProcCEGUIEventHandler>(boost::bind(&EditMode::OnMouseClick,&editMode))
	//);

	//ToProcessSceneWindowMouseDown sceneWindowMouseDown;
	//ToProcessSceneWindowMouseUp sceneWindowMouseUp;
	///ToProcessSceneWindowMouseClick sceneWindowMouseClick;
	//pSceneWindow->subscribeEvent(CEGUI::Window::EventMouseButtonDown,sceneWindowMouseDown);
	//pSceneWindow->subscribeEvent(CEGUI::Window::EventMouseButtonUp,sceneWindowMouseUp);
	//pSceneWindow->subscribeEvent(CEGUI::Window::EventMouseClick,sceneWindowMouseClick);
	//pSceneWindow->subscribeEvent(CEGUI::Window::EventMouseButtonMove,sceneWindowMouseEventHandler);

	while(go&&!pWindow->isClosed()){
		{
			assert(sbcToDelete.empty()||*boost::max_element(sbcToDelete)<boxes.size());
			for(std::vector<std::size_t>::iterator i = sbcToDelete.begin(); i != sbcToDelete.end(); ++i)
			{
				std::size_t &p = *i; // the deletion query list is to be modified.
				if(p>=boxes.size()){
					p = *(i-(p-boxes.size()+1));
				}
				boxes[p] = boxes.back();
				boxes.pop_back();
				using namespace GenericSim::Handles;
				{
					boost::array<SimpleBoxComponentHandle,2> a = {
						Utility::Make<HandleToElementOfRandomAccessRange>( &boxes,boxes.size() ),
						Utility::Make<HandleToElementOfRandomAccessRange>( &boxes,p )
					};
					sbcMovingList.push_back(a);
				}
				{
					boost::array<RigidBodyInstHandle,2> a = {
						MakePoly( MakeHandleToEntityState<EC::Component,EC::Component::RigidBodyStates >(
							Utility::Make<HandleToElementOfRandomAccessRange>( &boxes, boxes.size() )
						) ),
						MakePoly( MakeHandleToEntityState<EC::Component,EC::Component::RigidBodyStates >(
							Utility::Make<HandleToElementOfRandomAccessRange>( &boxes, p )
						) )
					};
					rigidBodyMovingList.push_back(a);
				}
			}
			sbcToDelete.clear();
		}
		if(_kbhit()){
			char ch = _getch();
			if('`'==ch) while(true){
				//PLAN:(first step - just box components and ball joints)
				//0. just get the console working
				//1. refactor into 1 stateless function call each console command
				//2. build the gui calling the functions

				int cmd = _getch();
				if('a'==cmd){
					std::cout<<"\nadd:";
					std::size_t i = protoBoxes.size();
					std::cin>>i;
					assert(i<protoBoxes.size());
					if(i<protoBoxes.size()){
						//Insertions can happen any time in the loop between a deletion sweep and the simulation
						//boxes.push_back( protoBoxes[i] );
						//rigidBodyInsertionList.push_back( &boxes.back().at_e<EC::Component::RigidBodyStates>() );
					}
				}else if('r'==cmd){
					std::cout<<"\nremove:";
					std::size_t i = boxes.size();
					std::cin>>i;
					assert(i<boxes.size());
					if(i<boxes.size()){
						sbcToDelete.push_back(i);
						//Actual deletions must be centralized. Insertions must happen after deletions.
						//But deletions caused by deletions( e.g. joint deletions caused by a rigid body deletion ) should be resolved here
					}
				}else if('p'==cmd){
					std::cout<<"\nid:";
					std::size_t i = boxes.size();
					std::cin>>i;
					assert(i<boxes.size());
					std::cout<<"\nset position:";
					NaiveTabularTupleListStream::UseAsTupleStream( std::cin )>>boxes[i].at_e<EC::Component::RigidBodyStates>().at_e<EC::RigidBodyDynamics3D::PositionVector>();
				}else if('o'==cmd){
					std::cout<<"\nid:";
					std::size_t i = boxes.size();
					std::cin>>i;
					assert(i<boxes.size());
					std::cout<<"\nset orientation:";
					NaiveTabularTupleListStream::UseAsTupleStream( std::cin )>>boxes[i].at_e<EC::Component::RigidBodyStates>().at_e<EC::RigidBodyDynamics3D::OrientationQuat>();
				}else if('z'==cmd){
					std::cout<<"\nid:";
					std::size_t i = boxes.size();
					std::cin>>i;
					assert(i<boxes.size());
					std::cout<<"\nset size:";
					NaiveTabularTupleListStream::UseAsTupleStream( std::cin )>>boxes[i].at_e<EC::Component::Shape>().at_e<EC::Box::Size>();
					assert(0);
				}else if('s'==cmd){ // this command is irrelevant to UI
					std::cout<<"\nsave to file.\n";
					NaiveTabularTupleListStream::UseAsTupleListStream( std::ofstream("boxesOut.txt") )<<boxes;
				}else if('`'==cmd){
					break;
				}
			}else if('w'==ch){
				pCam->setPolygonMode (Ogre::PM_WIREFRAME);
			}else if('s'==ch){
				pCam->setPolygonMode (Ogre::PM_SOLID);
			}else if('p'==ch){
				pCam->setPolygonMode (Ogre::PM_POINTS);
			}
		}

		time_t elapsedTime;
		{
			time_t nextTime = clock();
			elapsedTime = nextTime-currentTime;
			currentTime = nextTime;
			if(elapsedTime>100) elapsedTime = 100;
		}
		Real elapsedSeconds = elapsedTime*(1.0e-3);
		CEGUI::System::getSingleton().injectTimePulse(elapsedSeconds);

		{	//apply drag in edit mode
			Real c = exp(-elapsedSeconds);
			BOOST_FOREACH( SimpleBoxComponent &sbc, boxes ){
				using namespace boost::qvm;
				sbc.at_e<EC::Component::RigidBodyStates>().at_e<EC::RigidBodyDynamics3D::LinearVelocityVector>()*=c;
				sbc.at_e<EC::Component::RigidBodyStates>().at_e<EC::RigidBodyDynamics3D::AngularVelocityVector>()*=c;
			}
		}

		ManageODEObjectLifetime(
			rigidBodyDeletionList, rigidBodyMovingList, rigidBodyInsertionList,
			ballJointDeletionList, ballJointMovingList, ballJointInsertionList,
			odeRigidBodies, odeBallJoints, odeWorld
		);

		boost::for_each( odeRigidBodies, boost::bind( CallHandleToObjectMappingPairProc_PROC_OBJ_2(),SetOpenDERigidBody_PROC_OBJ_2(),_1 ) );

		odeWorldStepper(odeWorld,elapsedSeconds);

		boost::for_each( odeRigidBodies, boost::bind( CallHandleToObjectMappingPairProc_PROC_OBJ_2(),GetOpenDERigidBody_PROC_OBJ_2(),_1 ) );

		{
			class ToDestroyComponentOgreSceneNode{
				Ogre::SceneManager *m_pSceneManager;
			public:
				void operator()(Ogre::SceneNode *p){
					//for(Ogre::SceneManager::MovableObjectIterator i = m_pSceneManager->getMovableObjectIterator("Entity"); i.hasMoreElements(); ){
					//	std::cout<<i.getNext()->getName()<<'\n';
					//}
					//std::cout<<"===\n";
					//for(Ogre::SceneNode::ObjectIterator i = p->getAttachedObjectIterator();i.hasMoreElements();){
					//	Ogre::MovableObject *p = i.getNext();
					//	m_pSceneManager->destroyMovableObject( p );
					//}
					DestroyOgreSceneNodeAttachedMovableObjects(p,m_pSceneManager);
					m_pSceneManager->destroySceneNode(p);
					//for(Ogre::MeshManager::ResourceMapIterator &i = Ogre::MeshManager::getSingleton().getResourceIterator(); i.hasMoreElements(); ){
					//	std::cout<<i.getNext()->getName()<<'\n';
					//}
					//std::cout<<"---\n";
					//for(Ogre::SceneManager::MovableObjectIterator i = m_pSceneManager->getMovableObjectIterator("Entity"); i.hasMoreElements(); ){
					//	std::cout<<i.getNext()->getName()<<'\n';
					//}
					//std::cout<<"===\n";
				}

				ToDestroyComponentOgreSceneNode(Ogre::SceneManager *pSM):m_pSceneManager(pSM){ assert(pSM); }
			};
			MappingFollowDeletionAndMoving(sbcDeletionList,sbcMovingList,pBoxOgreSceneNodes,ToDestroyComponentOgreSceneNode(pSceneManager));
			if(sbcDeletionList.size())	Ogre::MeshManager::getSingleton().removeUnreferencedResources(false);
		}

		BOOST_FOREACH( const SimpleBoxComponentHandle &hSBC, sbcInsertionList )
		{
			TopoDS_Shape box = GenericShapeToOCCT(hSBC->at_e<EC::Component::Shape>());
			BRepFilletAPI_MakeFillet mf(box);
			for(TopExp_Explorer e(box,TopAbs_EDGE);e.More();e.Next()){
				mf.Add(TopoDS::Edge(e.Current()));
			}
			Real r=0.02;
			std::ifstream("fillet.txt")>>r;
			for (Standard_Integer i = 1;i<=mf.NbContours();++i) {
				mf.SetRadius(r,i,1);
			}
			//boxEntityNames.push_back("boxEntityNames"+boost::lexical_cast<std::string>(boxEntityNames.size()));
			std::string meshName = "boxMeshName"+boost::lexical_cast<std::string>(clock())+"|"+boost::lexical_cast<std::string>(pBoxOgreSceneNodes.size());
			std::string entityName = "boxEntityName"+boost::lexical_cast<std::string>(clock())+"|"+boost::lexical_cast<std::string>(pBoxOgreSceneNodes.size());
			OCCTMesh2OGRE::FillBlankOgreMeshUsingOCCTShape(
				Ogre::MeshManager::getSingleton().createManual( meshName , "__OCCTGEN" ),
				mf.Shape(),
				1
			);
			Ogre::SceneNode *pSN = pSceneManager->getRootSceneNode()->createChildSceneNode();
			pSN->attachObject( pSceneManager->createEntity(entityName,meshName,"__OCCTGEN") );
			pBoxOgreSceneNodes.insert( std::make_pair( hSBC, pSN ) );
		}
		{
			typedef const std::pair< SimpleBoxComponentHandle, Ogre::SceneNode *> &ptype;
			BOOST_FOREACH( ptype p , pBoxOgreSceneNodes ){
				SetOgreSceneNodeSpatialConfig(p.second,p.first->at_e<EC::Component::RigidBodyStates>());
			}
		}

		sbcDeletionList.clear();
		sbcMovingList.clear();
		sbcInsertionList.clear();
		rigidBodyDeletionList.clear();
		rigidBodyMovingList.clear();
		rigidBodyInsertionList.clear();
		ballJointDeletionList.clear();
		ballJointMovingList.clear();
		ballJointInsertionList.clear();

		{
			CEGUI::Rect r = pSceneWindow->getClipRect();
			CEGUI::Vector2 mousePos = CEGUI::MouseCursor::getSingleton().getPosition() - r.getPosition();
			Ogre::Real
				xh = mousePos.d_x / r.getWidth() * 2 - 1,
				yh = -(mousePos.d_y / r.getHeight() * 2 - 1);
			editMode.Update(elapsedSeconds,Ogre::Vector2(xh,yh),pCam);
		}

		pViewport->setDimensions(
			pSceneWindow->getClipRect().getPosition().d_x/pWindow->getWidth(),
			pSceneWindow->getClipRect().getPosition().d_y/pWindow->getHeight(),
			pSceneWindow->getClipRect().getWidth()/pWindow->getWidth(),
			pSceneWindow->getClipRect().getHeight()/pWindow->getHeight()
		);
		//pCam->setAspectRatio(Ogre::Real(pViewport->getActualWidth())/Ogre::Real(pViewport->getActualHeight()));
		{
			boost::uniform_real<float> dist(0.4f,0.6f);
			boost::variate_generator< boost::mt19937&,boost::uniform_real<float> > die(randGen,dist);
			pViewport->setBackgroundColour(Ogre::ColourValue(die(),die(),die()));
		}
		unsigned int windowWidthToHold=50,windowHeightToHold=50;
		{
			unsigned int a=0;
			int b=0,c=0;
			pWindow->getMetrics(windowWidthToHold,windowHeightToHold,a,b,c);
		}
		Ogre::WindowEventUtilities::messagePump();
		{
			unsigned int w=50,h=50,a=0;
			int b=0,c=0;
			pWindow->getMetrics(w,h,a,b,c);
			if(w!=windowWidthToHold || h!=windowHeightToHold){
				pWindow->resize(windowWidthToHold,windowHeightToHold);
			}
		}
		RouteOISUserInput(*ois.Mice().front(),OIS2CEGUIMouseListener(CEGUI::System::getSingleton()));
		RouteOISUserInput(*ois.Keyboards().front(),OIS2CEGUIKeyListener(CEGUI::System::getSingleton()));
		//System::injectTimePulse( float timeElapsed );
		pOgreRoot->renderOneFrame();
	}
	NaiveTabularTupleListStream::UseAsTupleListStream( std::ofstream("boxesOut.txt") )<<boxes;

	return 0;

    dsFunctions fn;
    fn.version = DS_VERSION;
    fn.start = &start;
    fn.step = &simLoop;
    fn.stop = 0;
    fn.command = 0;
    fn.path_to_textures = "E:\\Libraries\\dynamics\\opende\\drawstuff\\textures";
    world = dWorldCreate();
    space = dHashSpaceCreate (0);
    dWorldSetGravity (world,0,0,-9.8);
	dWorldSetERP(world,0.8);
	dCreatePlane(space,0,0,1,0);
    contactgroup = dJointGroupCreate (0);
//    body = dBodyCreate (world);
//    geom = dCreateSphere (space,0.5);
//    dMassSetSphere (&m,1,0.5);
//    dBodySetMass (body,&m);
//    dGeomSetBody (geom,body);
//    dBodySetPosition (body,0,0,3);
    dsSimulationLoop (argc,argv,1280,720,&fn);
    dJointGroupDestroy (contactgroup);
    dSpaceDestroy (space);
    dWorldDestroy (world);
	return 0;
}

max_stars_repo_name: ducis/pile-of-cpp

max_issues_repo_name: ducis/pile-of-cpp

max_forks_repo_name: ducis/pile-of-cpp


text:
/*
 *   Repast for High Performance Computing (Repast HPC)
 *
 *   Copyright (c) 2010 Argonne National Laboratory
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with
 *   or without modification, are permitted provided that the following
 *   conditions are met:
 *
 *     Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *     Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *     Neither the name of the Argonne National Laboratory nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *   PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 *   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  logger.cpp
 *
 *  Created on: Dec 16, 2008
 *      Author: nick
 */

#include <mpi.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <map>
#include <ctime>

#include <boost/filesystem.hpp>
#include <boost/mpi/collectives.hpp>

#include "logger.h"
#include "io.h"
#include "RepastErrors.h"

namespace fs = boost::filesystem;

using namespace std;

namespace repast {

typedef enum _TOKEN {
	END = 0, ROOT, LOGGER, APPENDER, APPENDER_FILE, APPENDER_SIZE, APPENDER_BIDX, ERRORT
} TOKEN;

const string ROOT_LOGGER_TAG = "logger.root";
const string LOGGER_TAG = "logger.";
const string APPENDER_TAG = "appender.";
const string FILE_TAG = ".File";
const string SIZE_TAG = ".MaxFileSize";
const string BACK_IDX_TAG = ".MaxBackupIndex";

// DEBUG, INFO, WARN, ERROR, FATAL
const int LEVEL_COUNT = 5;
const char *LEVELS[5] = { "DEBUG", "INFO", "WARN", "ERROR", "FATAL" };

int count_char(const string& str, const char& to_count) {
	int count = 0;
	for (int i = 0, n = str.length(); i < n; i++) {
		if (str[i] == to_count)
			count++;
	}
	return count;
}

bool ends_with(const string& str, const string& ends) {
	size_t pos = str.rfind(ends, str.length());
	if (pos == string::npos)
		return false;

	return str.length() - pos == ends.length();
}

class ConfigLexer {

private:
	int _line;
//	ifstream* in;
	istringstream* in;

	string _value, _key, _error;

	void format_error(const char* msg);
	bool is_root();
	bool is_logger();
	bool is_appender();
	bool is_appender_file();
	bool is_appender_size();
	bool is_appender_bidx();

public:
	ConfigLexer(const string& file_name, boost::mpi::communicator* comm = 0, int maxConfigFileSize = MAX_CONFIG_FILE_SIZE);
	~ConfigLexer();

	TOKEN next_token();
	string key();
	string value();
	string error();
	int line();
	void reset();
};

ConfigLexer::ConfigLexer(const string& file_name, boost::mpi::communicator* comm, int maxConfigFileSize) :
	_line(0), _value(""), _key(""), _error("") {

  char* CONFIGFILEBUFFER = new char[maxConfigFileSize];                            // All procs allocate memory for the properties file

  if(comm == 0 || comm->rank() == 0){                                          // If no communicator is passed, all ranks read props file
    ifstream fileInStream(file_name.c_str());
    if (fileInStream.is_open()){
      fileInStream.read(CONFIGFILEBUFFER, maxConfigFileSize);
      // Check if fail:
      if(fileInStream.gcount() >= (maxConfigFileSize - 1)){
        throw repast::Repast_Error_41(maxConfigFileSize, fileInStream.gcount(), file_name); // Config file exceeds maximum allowed size
      }
      CONFIGFILEBUFFER[fileInStream.gcount()] = '\0'; // Add a null terminator
      fileInStream.close();
    } else {
      throw repast::Repast_Error_42(file_name); // Config file not found
    }
  }
  if(comm != 0){                                                               // If a communicator was passed, proc 0 broadcasts to all other procs
    MPI_Bcast(CONFIGFILEBUFFER, maxConfigFileSize, MPI_CHAR, 0, *comm);
  }

  std::string P(CONFIGFILEBUFFER);
  delete[] CONFIGFILEBUFFER;

  in = new istringstream(P, ios_base::in);

	if (in == NULL || in->fail()) {
		string err = "Error opening config file '" + file_name + "'";
		if (in != NULL)
			delete in;
		throw repast::Repast_Error_43(file_name); // Unknown error
	}
}

ConfigLexer::~ConfigLexer() {
//	if (in != NULL)
//		in->close();
	delete in;
}

bool ConfigLexer::is_root() {
	return _key == ROOT_LOGGER_TAG;
}

bool ConfigLexer::is_logger() {
	return _key.find(LOGGER_TAG) == 0;
}

// its an appender if it starts with appender
// and there is a single dot
bool ConfigLexer::is_appender() {
	return _key.find(APPENDER_TAG) == 0 && count_char(_key, '.') == 1;
}

// its an appender.File if starts with
// appender., has two dots, and ends with File.
bool ConfigLexer::is_appender_file() {
	return _key.find(APPENDER_TAG) == 0 && count_char(_key, '.') == 2 && ends_with(_key, FILE_TAG);
}

// starts with appender, has two dots
// and ends with SIZE tag.
bool ConfigLexer::is_appender_size() {
	return _key.find(APPENDER_TAG) == 0 && count_char(_key, '.') == 2 && ends_with(_key, SIZE_TAG);
}

// starts with appender, has two dots
// and ends with BAC_IDX tag
bool ConfigLexer::is_appender_bidx() {
	return _key.find(APPENDER_TAG) == 0 && count_char(_key, '.') == 2 && ends_with(_key, BACK_IDX_TAG);
}

void ConfigLexer::format_error(const char* msg) {
	stringstream str;
	str << "Error in line " << _line << ": " << msg << endl;
	_error = str.str();
}

string ConfigLexer::key() {
	return _key;
}

string ConfigLexer::value() {
	return _value;
}

string ConfigLexer::error() {
	return _error;
}

int ConfigLexer::line() {
	return _line;
}

TOKEN ConfigLexer::next_token() {
	string str;
	while (getline(*in, str)) {
		_line++;
		repast::str_trim(str);
		if (str.length() > 0 && str[0] != '#') {
			size_t pos = str.find_first_of("=");
			if (pos == string::npos) {
				format_error("'=' is missing.");
				return ERRORT;
			}

			_key = str.substr(0, pos);
			repast::str_trim(_key);
			if (_key.length() == 0) {
				format_error("key is missing.");
				return ERRORT;
			}

			_value = "";
			if (str.length() > pos) {
				_value = str.substr(pos + 1, str.length());
			}
			repast::str_trim(_value);
			if (_value.length() == 0) {
				format_error("value is missing.");
				return ERRORT;
			}

			if (is_root())
				return ROOT;
			if (is_logger())
				return LOGGER;
			if (is_appender())
				return APPENDER;
			if (is_appender_file())
				return APPENDER_FILE;

			if (is_appender_size())
				return APPENDER_SIZE;
			if (is_appender_bidx())
				return APPENDER_BIDX;

			format_error("unexpected token");
			return ERRORT;
		}
	}
	return END;
}

void ConfigLexer::reset() {
	in->seekg(0, ios_base::beg);
}

Appender::Appender(const string name) :
	_name(name) {
}
Appender::~Appender() {
}

class CoutAppender: public Appender {

public:
	CoutAppender();
	~CoutAppender() {
	}
	;
	void write(const string& line);
};

class CerrAppender: public Appender {

public:
	CerrAppender();
	~CerrAppender() {
	}

	void write(const string& line);
};

CerrAppender::CerrAppender() :
	Appender("stderr") {
}

void CerrAppender::write(const string& line) {
	cout << line;
}

CoutAppender::CoutAppender() :
	Appender("stdout") {
}

void CoutAppender::write(const string& line) {
	cout << line;
}

class RollingFileAppender: public Appender {

public:
	RollingFileAppender(const string name, const string file_name, int max_backup, int max_size);
	~RollingFileAppender();

	virtual void write(const string& log_line);
	virtual void close();

private:
	MPI_File out;
	string file_name;
	int max_backup;
	long max_size, cur_size;
	bool isOpen;

	void resize_check();
	void init_cur_size();

};

RollingFileAppender::RollingFileAppender(const string name, const string file_name, int max_backup, int max_size) :
	Appender(name), file_name(file_name), max_backup(max_backup), max_size(max_size), cur_size(-1), isOpen(false) {

}

RollingFileAppender::~RollingFileAppender() {
	if (isOpen) {
		MPI_File_sync(out);
		MPI_File_close(&out);
	}
}

void RollingFileAppender::close() {
	if (isOpen) {
		MPI_File_sync(out);
		MPI_File_close(&out);
		isOpen = false;
	}
}

void RollingFileAppender::init_cur_size() {

	// check to see if the file exists
	ifstream fin(file_name.c_str(), ifstream::in);
	if (fin.fail()) {
		// file does not yet exist
		cur_size = 0;
	} else {
		fin.seekg(0, ios_base::end);
		// size in bytes
		cur_size = fin.tellg();
		fin.close();
	}

}

void RollingFileAppender::resize_check() {

	if (cur_size == -1)
		init_cur_size();

	if (cur_size > max_size) {
		if (isOpen) {
			// close the file
			MPI_File_sync(out);
			MPI_File_close(&out);
			isOpen = false;
		}

		for (int i = max_backup - 1; i >= 0; i--) {
			ostringstream from;
			if (i == 0) {
				from << file_name;
			} else {
				from << file_name << i;
			}

			ifstream fin(from.str().c_str(), ifstream::in);

			if (!fin.fail()) {
				fin.close();
				ostringstream to;
				to << file_name << (i + 1);
				rename(from.str().c_str(), to.str().c_str());
			}
		}

		cur_size = 0;
	}

	if (!isOpen) {

		// reopen the mpi out
		int mode = MPI_MODE_CREATE | MPI_MODE_WRONLY | MPI_MODE_APPEND;
		fs::path filepath(file_name);
		if (!fs::exists(filepath.parent_path())) {
			fs::create_directories(filepath.parent_path());
		}
		//out = MPI::File::Open(MPI::COMM_SELF, file_name.c_str(), mode, MPI::INFO_NULL);
		MPI_File_open(MPI_COMM_SELF, (char*)file_name.c_str(), mode, MPI_INFO_NULL, &out);
		isOpen = true;
	}
}

void RollingFileAppender::write(const string& log_line) {
	resize_check();
	int count = log_line.length();
	MPI_Status status;
	MPI_File_write(out, (void*)log_line.c_str(), count, MPI_CHAR, &status);
	cur_size += count;
}

Logger::Logger(const string name, LOG_LEVEL level, int proc_id) :
	name(name), level(level), proc_id(proc_id) {
}

void Logger::format_msg(LOG_LEVEL level, const string& msg, string& to_format) {
	string ts;
	repast::timestamp(ts);
	ostringstream os;
	os << ts << " [" << proc_id << "] " << LEVELS[level] << " " << name << " " << msg << endl;
	to_format = os.str();
}

void Logger::log(LOG_LEVEL level, const std::string msg) {
	string formatted_msg;
	if (level >= this->level) {
		formatted_msg = "";
		format_msg(level, msg, formatted_msg);
		for (vector<Appender*>::iterator iter = appenders.begin(); iter != appenders.end(); ++iter) {
			Appender* app = *iter;
			app->write(formatted_msg);
		}
	}
}

void Logger::close() {
	for (vector<Appender*>::iterator iter = appenders.begin(); iter != appenders.end(); ++iter) {
		Appender* app = *iter;
		app->close();
	}
}

void Logger::add_appender(Appender *appender) {
	appenders.push_back(appender);
}

AppenderBuilder::AppenderBuilder(const string name) :
	name(name) {
}

Appender* AppenderBuilder::build() {
	if (name == "stdout") {
		return new CoutAppender();
	} else if (name == "stderr") {
		return new CerrAppender();
	} else {
		return new RollingFileAppender(name, file_name, max_idx, max_size);
	}
}

Log4CLConfigurator::Log4CLConfigurator() :
	line(0) {
	app_map["stdout"] = new AppenderBuilder("stdout");
	app_map["stderr"] = new AppenderBuilder("stderr");
}

void Log4CLConfigurator::error_warn() {
	cerr << "WARN: " << error << endl;
}

int Log4CLConfigurator::parse_level(const string& str) const {
	for (int i = 0; i < LEVEL_COUNT; i++) {
		if (str == LEVELS[i])
			return i;
	}
	return -1;
}

void Log4CLConfigurator::create_root_logger(const string& value) {
	create_named_logger("root", value);
}

void Log4CLConfigurator::create_logger(const string& key, const string& value) {
	string name = key.substr(LOGGER_TAG.length());
	if (name.length() == 0) {
		ostringstream os;
		os << "Error in line " << line << ", logger is missing a name";
		error = os.str();
		error_warn();
		return;
	}

	create_named_logger(name, value);
}

void Log4CLConfigurator::create_appender(const string& key, const string& value) {
	string name = key.substr(APPENDER_TAG.length());
	if (name.length() == 0) {
		ostringstream os;
		os << "Error in line " << line << ", appender is missing a name";
		error = os.str();
		error_warn();
		return;
	}

	if (app_map.find(name) == app_map.end()) {
		// add an appender builder for this appender name
		AppenderBuilder* builder = new AppenderBuilder(name);
		app_map[name] = builder;
		builder->max_idx = 1;
		// megabyte
		builder->max_size = 1024 * 1024 * 10;
	}
}

AppenderBuilder* Log4CLConfigurator::get_appender_builder(const string& key) {
	size_t start_pos = APPENDER_TAG.length();
	size_t end_pos = key.rfind(".", key.length());
	if (start_pos == end_pos) {
		ostringstream os;
		os << "Error in line " << line << ", appender is missing a name";
		error = os.str();
		error_warn();
		return NULL;
	}

	ostringstream stream;
	for (size_t i = start_pos; i < end_pos; i++) {
		stream << key[i];
	}
	string name = stream.str();

	AppenderBuilder *builder;
	map<string, AppenderBuilder*>::const_iterator item = app_map.find(name);
	if (item == app_map.end()) {
		builder = new AppenderBuilder(name);
		app_map[name] = builder;
		builder->max_idx = 1;
		// megabyte
		builder->max_size = 1024 * 1024 * 10;
	} else {
		builder = item->second;
	}

	return builder;
}

void Log4CLConfigurator::create_appender_file(const string& key, const string& value) {
	AppenderBuilder *builder = get_appender_builder(key);
	if (builder != NULL) {
		// split file_name on last "." and append a _proc_id to it
		// if no "." then just append "_"
		string file_name = value;
		string parent_path;
		size_t pos = value.find_last_of('/');
		if (pos != string::npos) {
			file_name = value.substr(pos + 1);
			parent_path = value.substr(0, pos + 1);
		}

		pos = file_name.find_last_of('.');
		ostringstream os;
		if (pos != string::npos) {
			os << file_name.substr(0, pos) << "_" << proc_id << file_name.substr(pos, file_name.length());
		} else {
			os << file_name << "_" << proc_id;
		}
		file_name = os.str();

		builder->file_name = parent_path + file_name;
	}
}

void Log4CLConfigurator::create_appender_size(const string& key, const string& value) {
	AppenderBuilder* builder = get_appender_builder(key);
	if (builder != NULL) {
		// given in K but we store in bytes
		builder->max_size = atol(value.c_str()) * 1024;
	}

}

void Log4CLConfigurator::create_appender_bidx(const string& key, const string& value) {
	AppenderBuilder* builder = get_appender_builder(key);
	if (builder != NULL) {
		builder->max_idx = atoi(value.c_str());
	}
}

void Log4CLConfigurator::create_named_logger(const string& name, const string& value) {

	string token;
	istringstream stream(value);
	int level = -1;
	bool do_level = true;
	while (getline(stream, token, ',')) {
		repast::str_trim(token);
		if (do_level) {
			transform(token.begin(), token.end(), token.begin(), ::toupper);
			level = parse_level(token);
			do_level = false;
		} else {
			// its an appender name
			if (app_map.find(token) == app_map.end()) {
				// add an appender builder for this appender name
				AppenderBuilder* builder = new AppenderBuilder(token);
				app_map[token] = builder;
			}

			vector<string> *v;
			map<string, vector<string>*>::const_iterator item = logger_app_map.find(name);
			if (item == logger_app_map.end()) {
				v = new vector<string> ();
				logger_app_map[name] = v;
			} else {
				v = item->second;
			}
			v->push_back(token);

		}
	}

	if (level == -1) {
		error = "Invalid log level for " + name + " logger";
		error_warn();
		return;

	}

	Logger* logger = new Logger(name, (LOG_LEVEL) level, proc_id);
	logger_map[name] = logger;
}

Log4CL* Log4CLConfigurator::configure(const string& config_file, int proc_id, boost::mpi::communicator* comm, int maxConfigFileSize) {
	ConfigLexer lexer(config_file, comm, maxConfigFileSize);
	this->proc_id = proc_id;

	TOKEN tok;

	while (((tok = lexer.next_token()) != END)) {
		line = lexer.line();
		switch (tok) {
		case ROOT:
			create_root_logger(lexer.value());
			break;
		case LOGGER:
			create_logger(lexer.key(), lexer.value());
			break;
		case APPENDER:
			create_appender(lexer.key(), lexer.value());
			break;
		case APPENDER_FILE:
			create_appender_file(lexer.key(), lexer.value());
			break;
		case APPENDER_SIZE:
			create_appender_size(lexer.key(), lexer.value());
			break;
		case APPENDER_BIDX:
			create_appender_bidx(lexer.key(), lexer.value());
			break;
		case ERRORT:
			error = lexer.error();
			error_warn();
			break;
		default:
			error_warn();
		}
	}

	return create_log4cl();
}

Log4CL* Log4CLConfigurator::create_log4cl() {
	Log4CL* log4CL = new Log4CL();
	// create the appenders
	map<string, Appender*> amap;

	for (map<string, AppenderBuilder*>::const_iterator iter = app_map.begin(); iter != app_map.end(); ++iter) {
		AppenderBuilder *builder = iter->second;
		Appender *appender = builder->build();
		amap[iter->first] = appender;
		log4CL->appenders.push_back(appender);
	}

	for (map<string, Logger*>::const_iterator iter = logger_map.begin(); iter != logger_map.end(); ++iter) {

		Logger* logger = iter->second;
		log4CL->logger_map[iter->first] = logger;
		vector<string>* app_list = logger_app_map[iter->first];

		for (vector<string>::const_iterator siter = app_list->begin(); siter != app_list->end(); ++siter) {
			string app_name = *siter;
			logger->add_appender(amap[app_name]);
		}
	}

	// make sure there is a root logger and if not make one.
	if (logger_map.find("root") == logger_map.end()) {
		Logger *root = new Logger("root", WARN, proc_id);
		log4CL->logger_map["root"] = root;

		if (amap.find("stdout") == amap.end()) {
			Appender* out = new CoutAppender();
			root->add_appender(out);
			log4CL->appenders.push_back(out);
		} else {
			root->add_appender(amap["stdout"]);
		}
	}

	for (map<string, AppenderBuilder*>::const_iterator iter = app_map.begin(); iter != app_map.end(); ++iter) {
		AppenderBuilder *builder = iter->second;
		delete builder;
	}
	app_map.clear();

	for (map<string, Logger*>::const_iterator iter = logger_map.begin(); iter != logger_map.end(); ++iter) {

		vector<string>* app_list = logger_app_map[iter->first];
		delete app_list;
	}
	logger_map.clear();

	return log4CL;
}

Logger& Log4CL::get_logger(std::string logger_name) {
	map<string, Logger*>::const_iterator item = logger_map.find(logger_name);
	if (item == logger_map.end()) {
		cerr << "Unable to find logger '" << logger_name << "'. Returning root logger." << endl;
		return *logger_map["root"];
	}

	return *(item->second);
}

Log4CL::Log4CL() {
}

Log4CL::~Log4CL() {
	for (map<string, Logger*>::iterator iter = logger_map.begin(); iter != logger_map.end(); ++iter) {
		Logger *logger = iter->second;
		logger->close();
		delete logger;
	}

	for (vector<Appender *>::iterator iter = appenders.begin(); iter != appenders.end(); ++iter) {
		Appender *appender = *iter;
		delete appender;
	}

	delete _instance;
}

Log4CL* Log4CL::_instance = 0;

Log4CL* Log4CL::instance() {
	return _instance;
}

void Log4CL::configure(int proc_id, const std::string& config_file, boost::mpi::communicator* comm, int maxConfigFileSize) {

	try {
		Log4CLConfigurator configurator;
		_instance = configurator.configure(config_file, proc_id, comm, maxConfigFileSize);

	} catch (invalid_argument& ex) {
		cerr << "ERROR opening logging config file " << ex.what() << endl;
		delete _instance;
		_instance = NULL;
		return;
	}
}

void Log4CL::configure(int proc_id) {
	_instance = new Log4CL();
	Logger *root = new Logger("root", WARN, proc_id);
	_instance->logger_map["root"] = root;

	CoutAppender *out = new CoutAppender();
	root->add_appender(out);
	_instance->appenders.push_back(out);

}

void Log4CL::close() {
	for (map<string, Logger*>::iterator iter = logger_map.begin(); iter != logger_map.end(); ++iter) {
		Logger *logger = iter->second;
		logger->close();
	}
}

}

/*
 int main(int argc, char **argv) {

 MPI::Init(argc, argv);
 int proc_id = MPI::COMM_WORLD.Get_rank();

 Log4CL::configure(proc_id, "../config.props");
 Logger& logger = Log4CL::instance()->get_logger("root");
 logger.log(ERROR, "root msg\n");

 Logger& logger2 = Log4CL::instance()->get_logger("debug.log");
 logger2.log(ERROR, "logger msg\n");

 Log4CL::instance()->close();

 MPI::Finalize();
 }
 */

ext: cpp

max_stars_repo_name: etri/dtsim

max_issues_repo_name: etri/dtsim

max_forks_repo_name: etri/dtsim


text:
/** @file project_manager_test.h
 *  @brief tests for project_manager.cc
 *  @author Abhishek Dutta
 *  @date 04 Dec. 2019
 */
#include "project_manager.h"
#include "http_response.h"
#include "vise_util.h"

#include <boost/filesystem.hpp>
#include <Magick++.h>

#include <string>
#include <map>
#include <chrono>
#include <thread>
#include <cassert>

int main(int argc, char** argv) {
  if(argc != 2) {
    std::cout << "Usage: " << argv[0] << " TEST_IMAGES_DIR" << std::endl;
    return 1;
  }

  std::cout << "running project_manager_test" << std::endl;
  std::chrono::steady_clock::time_point tstart = std::chrono::steady_clock::now();

  boost::filesystem::path imdir(argv[1]);
  Magick::InitializeMagick(*argv);

  const boost::filesystem::path visehome = vise::vise_home();
  std::cout << "visehome=" << visehome.string() << std::endl;
  boost::filesystem::path vise_settings = visehome / "vise_settings.txt";
  ASSERT(boost::filesystem::exists(vise_settings));

  // load VISE configuration
  std::map<std::string, std::string> conf;
  vise::configuration_load(vise_settings.string(), conf);
  ASSERT(!conf.empty());

  vise::project_manager manager(conf);
  std::string pname("_test_project_manager");
  vise::http_response last_http_response;

  if(manager.project_exists(pname)) {
    std::map<std::string, std::string> del_pname_list;
    del_pname_list[pname] = "1";
    manager.vise_project_delete(del_pname_list, last_http_response);
    std::cout << last_http_response.d_status_code << " " << last_http_response.d_status
              << " : " << last_http_response.d_payload << std::endl;
    ASSERT(last_http_response.d_status_code == 303); // redirect to settings page
  }
  vise::http_response project_create_response;
  std::map<std::string, std::string> create_pname_list;
  create_pname_list["pname"] = pname;
  manager.vise_project_create(create_pname_list, last_http_response);
  std::cout << "manager.vise_project_create(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(last_http_response.d_status_code == 303);
  bool load_success = manager.project_load(pname);
  ASSERT(load_success);

  // count number of image files in image folder
  uint32_t img_count = 0;
  boost::filesystem::directory_iterator end_itr;
  for (boost::filesystem::directory_iterator it(imdir); it!=end_itr; ++it) {
    if(boost::filesystem::is_regular_file(it->path())) {
      if(it->path().extension() == ".jpg" ||
         it->path().extension() == ".JPG" ||
         it->path().extension() == ".jpeg" ||
         it->path().extension() == ".JPEG" ||
         it->path().extension() == ".png" ||
         it->path().extension() == ".PNG" ||
         it->path().extension() == ".TIF" ||
         it->path().extension() == ".tif" ||
         it->path().extension() == ".TIFF" ||
         it->path().extension() == ".tiff"
         ) {
        img_count++;
      }
    }
  }

  std::map<std::string, std::string> param
    {
     {"source_type", "local_folder"},
     {"source_loc", imdir.string()}
    };
  vise::http_response file_add_response;
  manager.project_file_add(pname, param, last_http_response);
  std::cout << "manager.project_file_add(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(last_http_response.d_status_code == 303);
  ASSERT(manager.project_image_src_count(pname) == img_count);

  // set configuration to auto
  std::string preset_id = "preset_conf_manual";
  manager.project_config_use_preset(pname, preset_id, last_http_response);
  std::cout << "manager.project_config_use_preset(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(last_http_response.d_status_code == 200);
  std::ostringstream config;
  config << "search_engine=relja_retrival\n";
  config << "use_root_sift=true\n";
  config << "sift_scale_3=true\n";
  config << "bow_descriptor_count=-1\n";
  config << "bow_cluster_count=1000\n";
  config << "cluster_num_iteration=3\n";
  config << "hamm_embedding_bits=32\n";
  config << "resize_dimension=200x200\n";
  std::string config_str(config.str());
  manager.project_config_save(pname, config_str, last_http_response);
  std::cout << "manager.project_config_save(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(last_http_response.d_status_code == 200);

  vise::http_response index_create_response;
  bool block_until_done = true;
  std::cout << "Creating index ... (blocking until done)" << std::endl;
  manager.project_index_create(pname, last_http_response, block_until_done);
  std::cout << "manager.project_index_create(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(manager.project_index_is_done(pname));

  //uint32_t wait_time_ms = 3000;
  //std::cout << "waiting for " << wait_time_ms << " ms to allow loading of index ..." << std::endl;
  //std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms));
  ASSERT(manager.project_index_is_loaded(pname));

  vise::http_response index_unload_response;
  manager.project_index_unload(pname, last_http_response);
  std::cout << "manager.project_index_inload(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(last_http_response.d_status_code == 200);
  ASSERT(!manager.project_index_is_loaded(pname));

#ifdef _WIN32
  std::cout << "Skipping deletion of test project as Windows locks folders created by an application"
            << std::endl;
#endif

#ifdef __linux__
  // delete test project
  std::map<std::string, std::string> delete_pname_list;
  delete_pname_list[pname] = "1";
  manager.vise_project_delete(delete_pname_list, last_http_response);
  std::cout << "manager.vise_project_delete(): "
            << last_http_response.d_status_code << " " << last_http_response.d_status << std::endl;
  ASSERT(last_http_response.d_status_code == 303);
  ASSERT(!manager.project_exists(pname));
#endif

  std::chrono::steady_clock::time_point tend = std::chrono::steady_clock::now();
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tend - tstart);
  std::cout << "project_manager_test,ok," << ms.count() << "ms" << std::endl;
  return 0;
}

ext: cc

max_stars_repo_name: alexanderwilkinson/visenew

max_issues_repo_name: alexanderwilkinson/visenew

max_forks_repo_name: alexanderwilkinson/visenew


text:
/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_COMPUTER_VISION_SIMPLE_PLY_HPP
#define PIC_COMPUTER_VISION_SIMPLE_PLY_HPP

#include <vector>
#include <random>
#include <stdlib.h>

#include "../base.hpp"

#include "../util/math.hpp"

#include "../util/eigen_util.hpp"

#ifndef PIC_DISABLE_EIGEN

#ifndef PIC_EIGEN_NOT_BUNDLED
    #include "../externals/Eigen/Dense"
    #include "../externals/Eigen/SVD"
    #include "../externals/Eigen/Geometry"
#else
    #include <Eigen/Dense>
    #include <Eigen/SVD>
    #include <Eigen/Geometry>
#endif

#endif

namespace pic {

#ifndef PIC_DISABLE_EIGEN

PIC_INLINE bool writeSimplePLY(std::string name,
                               std::vector< Eigen::Vector3d > &points_3d,
                               std::vector< unsigned char > &colors)
{
    //write a PLY file
    FILE *file = fopen(name.c_str(), "w");

    if (file == NULL) {
        return false;
    }

    bool bColor = colors.size() == (points_3d.size() * 3);

    fprintf(file,"ply\n");
    fprintf(file,"format ascii 1.0\n");
    fprintf(file,"element vertex %d\n", int(points_3d.size()));

    fprintf(file,"property float x\n");
    fprintf(file,"property float y\n");
    fprintf(file,"property float z\n");

    if(bColor) {
        fprintf(file,"property uchar red\n");
        fprintf(file,"property uchar green\n");
        fprintf(file,"property uchar blue\n");
        fprintf(file,"property uchar alpha\n");
    }
    fprintf(file,"end_header\n");

    for(unsigned int i = 0; i < points_3d.size(); i++) {
        //write position information
        fprintf(file, "%3.4f %3.4f %3.4f ", points_3d[i][0], points_3d[i][1], points_3d[i][2]);

        //write color information
        if(bColor) {
            auto k = i * 3;
            fprintf(file, " %d %d %d 255\n", colors[k], colors[k + 1], colors[k + 2]);
        }
    }

    fclose(file);
    return true;
}

#endif // PIC_DISABLE_EIGEN

} // end namespace pic

#endif // PIC_COMPUTER_VISION_SIMPLE_PLY_HPP

ext: hpp


text:
//
// fiber/basic_fiber_demux_service.ipp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2014-2015
//

#ifndef SSF_COMMON_BOOST_ASIO_FIBER_BASIC_FIBER_DEMUX_SERVICE_IMPL_IPP_
#define SSF_COMMON_BOOST_ASIO_FIBER_BASIC_FIBER_DEMUX_SERVICE_IMPL_IPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
#pragma once
#endif  // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include <ctime>
#include <functional>
#include <limits>
#include <mutex>

#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/system/error_code.hpp>

#include <ssf/log/log.h>

#include "common/boost/fiber/detail/basic_fiber_demux_impl.hpp"
#include "common/boost/fiber/detail/fiber_buffer.hpp"
#include "common/boost/fiber/detail/fiber_header.hpp"
#include "common/boost/fiber/detail/fiber_id.hpp"
#include "common/error/error.h"

namespace boost {
namespace asio {
namespace fiber {

template <typename S>
void basic_fiber_demux_service<S>::fiberize(implementation_type impl) {
  if (!impl) {
    SSF_LOG("demux", debug, "fiberizing NOK {}", ::error::broken_pipe);
    return;
  }

  SSF_LOG("demux", trace, "fiberizing");

  async_poll_packets(impl);
}

template <typename S>
void basic_fiber_demux_service<S>::bind(implementation_type impl,
                                        local_port_type local_port,
                                        fiber_impl_type fib_impl,
                                        boost::system::error_code& ec) {
  if (!impl) {
    SSF_LOG("demux", debug, "error bind NOK {}", ::error::broken_pipe);
    ec.assign(::error::broken_pipe, ::error::get_ssf_category());
    return;
  }

  if (!local_port) {
    local_port = get_available_local_port(impl);
  }

  fib_impl->id.set_local_port(local_port);
  fiber_id id = fib_impl->id;

  fiber_id receiving_id = id.returning_id();

  {
    std::unique_lock<std::recursive_mutex> lock1(impl->bound_mutex);
    std::unique_lock<std::recursive_mutex> lock2(impl->used_ports_mutex);
    SSF_LOG("demux", trace, "try to bind fiber to {}:{}", id.local_port(),
            id.remote_port());
    if (receiving_id.remote_port() && !impl->bound.count(receiving_id)) {
      SSF_LOG("demux", trace, "bind OK");
      impl->bound[receiving_id] = fib_impl;
      impl->used_ports.insert(id.local_port());

      {
        std::unique_lock<std::recursive_mutex> lock_state(
            fib_impl->state_mutex);
        fib_impl->closed = false;
      }

      ec.assign(::error::success, ::error::get_ssf_category());
    } else {
      SSF_LOG("demux", debug, "bind NOK {}", ::error::device_or_resource_busy);
      ec.assign(::error::device_or_resource_busy, ::error::get_ssf_category());
    }
  }
}

template <typename S>
bool basic_fiber_demux_service<S>::is_bound(implementation_type impl,
                                            const fiber_id& id) {
  if (!impl) {
    SSF_LOG("demux", debug, "is_bound NOK {}", ::error::broken_pipe);
    return false;
  }

  std::unique_lock<std::recursive_mutex> lock(impl->bound_mutex);
  return !!impl->bound.count(id.returning_id());
}

template <typename S>
void basic_fiber_demux_service<S>::unbind(implementation_type impl,
                                          const fiber_id& id) {
  if (!impl) {
    SSF_LOG("demux", debug, "unbind NOK {}", ::error::broken_pipe);
    return;
  }

  std::unique_lock<std::recursive_mutex> lock1(impl->bound_mutex);
  std::unique_lock<std::recursive_mutex> lock2(impl->used_ports_mutex);
  SSF_LOG("demux", trace, "unbind {}, {}", id.local_port(), id.remote_port());

  impl->bound.erase(id.returning_id());
  impl->used_ports.erase(id.local_port());
}

template <typename S>
void basic_fiber_demux_service<S>::listen(implementation_type impl,
                                          local_port_type local_port,
                                          boost::system::error_code& ec) {
  if (!impl) {
    SSF_LOG("demux", debug, "[demux] listen NOK {}", ::error::broken_pipe);
    ec.assign(::error::broken_pipe, ::error::get_ssf_category());
    return;
  }

  std::unique_lock<std::recursive_mutex> lock(impl->listening_mutex);

  if (!impl->listening.count(local_port) &&
      is_bound(impl, fiber_id(0, local_port))) {
    SSF_LOG("demux", trace, "fiber listening on {}", local_port);

    impl->listening.insert(local_port);

    ec.assign(::error::success, ::error::get_ssf_category());
  } else if (impl->listening.count(local_port)) {
    ec.assign(::error::device_or_resource_busy, ::error::get_ssf_category());
  } else {
    ec.assign(::error::protocol_error, ::error::get_ssf_category());
  }
}

template <typename S>
bool basic_fiber_demux_service<S>::is_listening(implementation_type impl,
                                                local_port_type local_port) {
  if (!impl) {
    SSF_LOG("demux", debug, "is_listening NOK {}", ::error::broken_pipe);
    return false;
  }

  std::unique_lock<std::recursive_mutex> lock(impl->listening_mutex);
  return !!impl->listening.count(local_port);
}

template <typename S>
void basic_fiber_demux_service<S>::stop_listening(implementation_type impl,
                                                  local_port_type local_port) {
  if (!impl) {
    SSF_LOG("demux", debug, "stop_listening NOK {}", ::error::broken_pipe);
    return;
  }

  std::unique_lock<std::recursive_mutex> lock1(impl->listening_mutex);
  std::unique_lock<std::recursive_mutex> lock2(impl->used_ports_mutex);
  SSF_LOG("demux", trace, "stopped listening on {}", local_port);

  impl->listening.erase(local_port);
  impl->used_ports.erase(local_port);
}

template <typename S>
void basic_fiber_demux_service<S>::async_poll_packets(
    implementation_type impl) {
  auto p_fiber_buff =
      std::make_shared<boost::asio::fiber::detail::fiber_buffer>();

  /////////////////// BEGIN HANDLER ///////////////////////////////
  auto dispatch_handler = [this, p_fiber_buff, impl](
      const boost::system::error_code& ec, std::size_t bytes_transferred) {
    std::unique_lock<std::recursive_mutex> lock(impl->closing_mutex);
    if (impl->closing) {
      return;
    }

    if (!ec) {
      this->dispatch_buffer(impl, p_fiber_buff);
      this->async_poll_packets(impl);
    } else {
      SSF_LOG("demux", debug,
              "error in dispatch handler {}: {} | {} bytes transferred",
              ec.value(), ec.message(), bytes_transferred);
      this->close(impl);
    }
  };
  //////////////////// END HANDLER ///////////////////////////////

  std::unique_lock<std::recursive_mutex> lock(impl->closing_mutex);
  if (!impl->closing) {
    async_read_fiber_buffer(impl->socket, *p_fiber_buff, dispatch_handler);
  }
}

template <typename S>
void basic_fiber_demux_service<S>::async_push_packets(
    implementation_type impl) {
  std::unique_lock<std::recursive_mutex> lock(impl->send_mutex);
  const auto& to_send_priority = impl->toSendPriority.front();

  auto handler = [this, impl, to_send_priority](
      const boost::system::error_code& ec, size_t transferred_bytes) {
    std::unique_lock<std::recursive_mutex> lock(impl->send_mutex);
    impl->toSendPriority.pop();
    impl->socket.get_io_service().post(
        std::bind(to_send_priority.handler, ec, transferred_bytes));
    if (!impl->toSendPriority.empty()) {
      impl->socket.get_io_service().post(std::bind(
          &basic_fiber_demux_service<S>::async_push_packets, this, impl));
    }
  };

  std::unique_lock<std::recursive_mutex> lock2(impl->closing_mutex);
  if (!impl->closing) {
    boost::asio::async_write(impl->socket, to_send_priority.buffer, handler);
  } else {
    impl->socket.get_io_service().post(std::bind(
        handler, boost::system::error_code(::error::connection_aborted,
                                           ::error::get_ssf_category()),
        0));
  }
}

template <typename S>
void basic_fiber_demux_service<S>::dispatch_buffer(
    implementation_type impl, p_fiber_buffer p_fiber_buff) {
  const auto& header = p_fiber_buff->header();

  const auto flags = header.flags();

  SSF_LOG("demux", trace, "dispatch {} {} {} {} {}", uint32_t(header.version()),
          header.id().remote_port(), header.id().local_port(), uint32_t(flags),
          header.data_size());

  switch (flags) {
    case kFlagPush:
      handle_push(impl, p_fiber_buff);
      break;
    case kFlagSyn:
      handle_syn(impl, p_fiber_buff);
      break;
    case kFlagReset:
      handle_rst(impl, p_fiber_buff);
      break;
    case kFlagAck:
      handle_ack(impl, p_fiber_buff);
      break;
    case kFlagDatagram:
      handle_dgr(impl, p_fiber_buff);
      break;
    default:
      break;
  }
}

template <typename S>
void basic_fiber_demux_service<S>::handle_dgr(implementation_type impl,
                                              p_fiber_buffer p_fiber_buff) {
  SSF_LOG("demux", trace, "handle dgr");
  const auto& full_id = p_fiber_buff->header().id();
  const auto& half_id = fiber_id(p_fiber_buff->header().id().remote_port(), 0);
  std::unique_lock<std::recursive_mutex> lock(impl->bound_mutex);

  if (impl->bound.count(full_id) != 0) {
    if (impl->bound[full_id]->accepts_dgr) {
      auto on_new_packet = impl->bound[full_id]->access_receive_dgr_handler();
      on_new_packet(p_fiber_buff->take_data(),
                    p_fiber_buff->header().id().local_port(),
                    p_fiber_buff->data_size());
    }
  } else if (impl->bound.count(half_id) != 0) {
    if (impl->bound[half_id]->accepts_dgr) {
      auto on_new_packet = impl->bound[half_id]->access_receive_dgr_handler();
      on_new_packet(p_fiber_buff->take_data(),
                    p_fiber_buff->header().id().local_port(),
                    p_fiber_buff->data_size());
    }
  }
}

template <typename S>
void basic_fiber_demux_service<S>::handle_push(implementation_type impl,
                                               p_fiber_buffer p_fiber_buff) {
  SSF_LOG("demux", trace, "handle push");
  const auto& header = p_fiber_buff->header();
  std::unique_lock<std::recursive_mutex> lock(impl->bound_mutex);

  if (impl->bound.count(header.id()) != 0) {
    auto on_new_packet = impl->bound[header.id()]->access_receive_handler();
    on_new_packet(p_fiber_buff->take_data(), p_fiber_buff->data_size());
  } else {
    async_send_rst(impl, header.id().returning_id(), []() {});
  }
}

template <typename S>
void basic_fiber_demux_service<S>::handle_ack(implementation_type impl,
                                              p_fiber_buffer p_fiber_buff) {
  const auto& header = p_fiber_buff->header();
  std::unique_lock<std::recursive_mutex> lock_bound(impl->bound_mutex);
  SSF_LOG("demux", trace, "handle ack");

  if (impl->bound.count(header.id())) {
    auto p_fib_impl = impl->bound[header.id()];
    p_fib_impl->toggle_out();

    std::unique_lock<std::recursive_mutex> lock_state(p_fib_impl->state_mutex);

    if (p_fib_impl->connecting) {
      p_fib_impl->set_connected();
      auto on_ack = p_fib_impl->access_connect_handler();
      on_ack(boost::system::error_code(::error::success,
                                       ::error::get_ssf_category()));
    }
  } else {
    async_send_rst(impl, header.id().returning_id(), []() {});
  }
}

template <typename S>
void basic_fiber_demux_service<S>::handle_syn(implementation_type impl,
                                              p_fiber_buffer p_fiber_buff) {
  SSF_LOG("demux", trace, "handle syn");
  const auto& header = p_fiber_buff->header();
  std::unique_lock<std::recursive_mutex> lock_listening(impl->listening_mutex);
  std::unique_lock<std::recursive_mutex> lock_bound(impl->bound_mutex);

  if (impl->listening.count(header.id().remote_port())) {
    auto on_new_fiber = impl->bound[fiber_id(header.id().remote_port())]
                            ->access_accept_handler();
    io_service_.post(std::bind(on_new_fiber, header.id().local_port()));
  } else {
    async_send_rst(impl, header.id().returning_id(), []() {});
  }
}

template <typename S>
void basic_fiber_demux_service<S>::handle_rst(implementation_type impl,
                                              p_fiber_buffer p_fiber_buff) {
  SSF_LOG("demux", trace, "handle rst");
  const auto& header = p_fiber_buff->header();
  auto returning_id = header.id().returning_id();
  std::unique_lock<std::recursive_mutex> lock_bound(impl->bound_mutex);
  if ((impl->bound).count(header.id())) {
    auto p_fib_impl = impl->bound[header.id()];
    auto on_close = p_fib_impl->access_close_handler();

    std::unique_lock<std::recursive_mutex> lock_state(p_fib_impl->state_mutex);

    if (p_fib_impl->connecting || p_fib_impl->connected) {
      if (p_fib_impl->connecting) {
        p_fib_impl->set_disconnected();
        auto on_connection = p_fib_impl->access_connect_handler();
        on_connection(boost::system::error_code(::error::connection_refused,
                                                ::error::get_ssf_category()));
      } else {
        p_fib_impl->set_disconnected();
        auto rst_sent = [this, impl, returning_id, p_fib_impl]() {
          this->unbind(impl, returning_id);
          p_fib_impl->access_close_handler()();
        };
        async_send_rst(impl, returning_id, std::move(rst_sent));
      }
    } else if (p_fib_impl->disconnecting) {
      p_fib_impl->set_disconnected();
      unbind(impl, returning_id);
      on_close();
    }
  }
}

template <typename S>
template <typename ConstBufferSequence, typename Handler>
void basic_fiber_demux_service<S>::async_send_push(implementation_type impl,
                                                   fiber_id id,
                                                   ConstBufferSequence& buffer,
                                                   Handler& handler) {
  std::unique_lock<std::recursive_mutex> lock1(impl->bound_mutex);

  if (impl->bound.count(id.returning_id())) {
    auto p_fiber_impl = impl->bound[id.returning_id()];
    if (p_fiber_impl->ready_out) {
      async_send(impl, id, kFlagPush, buffer, handler, p_fiber_impl->priority);
    } else {
      auto p_timer = std::make_shared<boost::asio::steady_timer>(io_service_);
      p_timer->expires_from_now(std::chrono::milliseconds(10));

      auto lambda = [handler,
                     p_timer](const boost::system::error_code&) mutable {
        handler(boost::system::error_code(), 0);
      };

      p_timer->async_wait(lambda);
    }
  } else {
    handler(boost::system::error_code(::error::protocol_error,
                                      ::error::get_ssf_category()),
            0);
  }
}

template <typename S>
template <typename ConstBufferSequence, typename Handler>
void basic_fiber_demux_service<S>::async_send_dgr(implementation_type impl,
                                                  remote_port_type remote_port,
                                                  fiber_impl_type fib_impl,
                                                  ConstBufferSequence& buffer,
                                                  Handler& handler) {
  std::unique_lock<std::recursive_mutex> lock1(impl->bound_mutex);

  if (fib_impl->id.local_port() == 0) {
    fib_impl->id.set_local_port(get_available_local_port(impl));
    boost::system::error_code ec;
    bind(impl, fib_impl->id.local_port(), fib_impl, ec);
    if (ec) {
      SSF_LOG("demux", debug, "error dgr {} {}", ec.message(), ec.value());
      io_service_.post(std::bind(handler, ec, 0));
      return;
    }
  }

  if (impl->bound.count(fib_impl->id.returning_id())) {
    if (fib_impl->ready_out) {
      async_send(impl, fiber_id(remote_port, fib_impl->id.local_port()),
                 kFlagDatagram, buffer, handler, fib_impl->priority);
    } else {
      auto p_timer = std::make_shared<boost::asio::steady_timer>(io_service_);
      p_timer->expires_from_now(std::chrono::milliseconds(10));

      auto lambda = [handler,
                     p_timer](const boost::system::error_code&) mutable {
        handler(boost::system::error_code(), 0);
      };

      p_timer->async_wait(lambda);
    }
  } else {
    io_service_.post(std::bind(
        handler, boost::system::error_code(::error::protocol_error,
                                           ::error::get_ssf_category()),
        0));
  }
}

template <typename S>
void basic_fiber_demux_service<S>::async_send_ack(implementation_type impl,
                                                  fiber_impl_type fib_impl,
                                                  accept_op* op) {
  fib_impl->toggle_in();

  if (op) {
    boost::system::error_code ec;
    bind(impl, fib_impl->id.local_port(), fib_impl, ec);
    fib_impl->set_connected();
    if (ec) {
      SSF_LOG("demux", debug, "error send ack {} {}", ec.message(), ec.value());
      op->complete(ec, 0);
    } else {
      auto handler = [impl, fib_impl, op](const boost::system::error_code& ec, std::size_t) {
        if (ec) {
          SSF_LOG("demux", debug, "error send ack handler {}", ec.message());
        } else {
          SSF_LOG("demux", trace, "ack sent");
        }

        op->complete(ec, 0);
      };

      boost::asio::const_buffer pre_buffer;
      boost::asio::const_buffers_1 buffer(pre_buffer);
      async_send(impl, fib_impl->id, kFlagAck, buffer, handler, 0);
    }
  } else {
    boost::asio::const_buffer pre_buffer;
    boost::asio::const_buffers_1 buffer(pre_buffer);

    auto lambda = [](const boost::system::error_code&, std::size_t) {};
    async_send(impl, fib_impl->id, kFlagAck, buffer, lambda, 0);
  }
}

template <typename S>
void basic_fiber_demux_service<S>::async_send_syn(implementation_type impl,
                                                  fiber_id id) {
  std::unique_lock<std::recursive_mutex> lock_bound(impl->bound_mutex);
  // Bind reverse the id in bound map so reverse it...
  if ((impl->bound).count(id.returning_id())) {
    auto p_fib_impl = impl->bound[id.returning_id()];
    SSF_LOG("demux", trace, "async send syn");

    std::unique_lock<std::recursive_mutex> lock_state(p_fib_impl->state_mutex);

    if (!p_fib_impl->connecting) {
      p_fib_impl->set_connecting();
      auto handler = [impl, p_fib_impl](const boost::system::error_code& ec,
                                        std::size_t) {
        if (ec) {
          SSF_LOG("demux", debug, "syn error {}", ec.message());
          auto connection_failed = [p_fib_impl, ec]() {
            p_fib_impl->access_connect_handler()(ec);
          };
          impl->socket.get_io_service().post(connection_failed);
        } else {
          SSF_LOG("demux", trace, "syn sent");
        }
      };

      boost::asio::const_buffer pre_buffer;
      boost::asio::const_buffers_1 buffer(pre_buffer);
      async_send(impl, id, kFlagSyn, buffer, handler, 0);
    }
  }
}

template <typename S>
template <typename Handler>
void basic_fiber_demux_service<S>::async_send_rst(
    implementation_type impl, fiber_id id, const Handler& close_handler) {
  SSF_LOG("demux", trace, "async send rst");
  auto handler = [this, impl, id, close_handler](const boost::system::error_code& ec,
                                           std::size_t) {
    if (ec) {
      SSF_LOG("demux", debug, "async send rst error {}: {}", ec.value(),
              ec.message());
    } else {
      SSF_LOG("demux", trace, "rst sent {} {}", id.local_port(),
              id.remote_port());
    }

    this->get_io_service().dispatch(close_handler);
  };
  boost::asio::const_buffer pre_buffer;
  boost::asio::const_buffers_1 buffer(pre_buffer);

  async_send(impl, id, kFlagReset, buffer, handler, 0);
}

template <typename S>
boost::asio::fiber::detail::fiber_id::local_port_type
basic_fiber_demux_service<S>::get_available_local_port(
    implementation_type impl) {
  local_port_type new_port = (1 << 17) + 1024, rand_port = 0;
  std::unique_lock<std::recursive_mutex> lock1(impl->used_ports_mutex);

  boost::random::uniform_int_distribution<uint32_t> dist(
      new_port, std::numeric_limits<uint32_t>::max());
  for (uint32_t i = 0; i < 100; ++i) {
    rand_port = dist(gen_);
    if (impl->used_ports.count(rand_port) == 0) {
      return rand_port;
    }
  }

  return 0;
}

template <typename S>
void basic_fiber_demux_service<S>::async_connect(
    implementation_type impl,
    boost::asio::fiber::detail::fiber_id::remote_port_type remote_port,
    fiber_impl_type fib_impl) {
  SSF_LOG("demux", trace, "async connect to remote port: {}", remote_port);

  fib_impl->id.set_remote_port(remote_port);

  boost::system::error_code ec;

  bind(impl, 0, fib_impl, ec);

  if (ec) {
    auto connection_failed = [=]() { fib_impl->access_connect_handler()(ec); };
    impl->socket.get_io_service().post(connection_failed);
  } else {
    async_send_syn(impl, fib_impl->id);
  }
}

template <typename S>
template <typename ConstBufferSequence, typename Handler>
void basic_fiber_demux_service<S>::async_send(
    implementation_type impl, fiber_id id,
    boost::asio::fiber::detail::fiber_header::flags_type flags,
    ConstBufferSequence& buffers, Handler handler, uint8_t priority) {
  auto buffers_size = boost::asio::buffer_size(buffers);

  if (buffers_size > impl->mtu) {
    if (flags & kFlagDatagram) {
      io_service_.post(std::bind(
          handler, boost::system::error_code(::error::message_too_long,
                                             ::error::get_ssf_category()),
          0));
      return;
    }
    buffers_size = impl->mtu;
  }

  auto new_buffers =
      get_partial_buffer_sequence<ConstBufferSequence>(buffers, buffers_size);

  fiber_header header(id, flags, (uint16_t)buffers_size);

  auto p_fiber_buffer = std::make_shared<fiber_buffer>();
  p_fiber_buffer->set_header(header);
  auto raw_buffer_to_send = p_fiber_buffer->const_buffer(new_buffers);

  auto do_user_handler = [p_fiber_buffer, handler](
      const boost::system::error_code& ec, size_t transferred_bytes) mutable {
    handler(ec, transferred_bytes - fiber_header::pod_size());
  };

  detail::extended_raw_fiber_buffer toSend(raw_buffer_to_send, do_user_handler,
                                           priority);

  auto do_push_packets = [this, toSend, impl]() {
    std::unique_lock<std::recursive_mutex> lock(impl->send_mutex);
    impl->toSendPriority.push(toSend);

    if (impl->toSendPriority.size() > 1) {
      return;
    }

    this->async_push_packets(impl);
  };

  auto& header_b = p_fiber_buffer->header();
  auto flags_b = header_b.flags();

  SSF_LOG("demux", trace, "sending {} {} {} {} {}",
          static_cast<uint32_t>(header_b.version()),
          header_b.id().remote_port(), header_b.id().local_port(),
          static_cast<uint32_t>(flags_b), header_b.data_size());

  impl->socket.get_io_service().post(do_push_packets);
}

template <typename S>
template <typename ConstBufferSequence>
std::vector<boost::asio::const_buffer>
basic_fiber_demux_service<S>::get_partial_buffer_sequence(
    ConstBufferSequence buffers, size_t length) {
  std::vector<boost::asio::const_buffer> new_buffers;

  for (auto& buffer : buffers) {
    auto buffer_size = boost::asio::buffer_size(buffer);
    if (length >= buffer_size) {
      new_buffers.push_back(buffer);
      length -= buffer_size;
    } else {
      const unsigned char* p1 =
          boost::asio::buffer_cast<const unsigned char*>(buffer);
      new_buffers.push_back(boost::asio::const_buffer(p1, length));
      length = 0;
      break;
    }
  }

  return new_buffers;
}

template <typename S>
void basic_fiber_demux_service<S>::close_fiber(implementation_type impl,
                                               fiber_impl_type fib_impl) {
  std::unique_lock<std::recursive_mutex> lock_state(fib_impl->state_mutex);
  auto on_close = fib_impl->access_close_handler();

  if (fib_impl->id.remote_port() == 0) {
    // fiber acceptor
    if (!fib_impl->closed) {
      stop_listening(impl, fib_impl->id.local_port());
      unbind(impl, fib_impl->id);
      impl->socket.get_io_service().post(on_close);
    }
  } else {
    // fiber
    if (!fib_impl->disconnecting && !fib_impl->disconnected) {
      if (fib_impl->connecting || fib_impl->connected) {
        fib_impl->set_disconnecting();
        async_send_rst(impl, fib_impl->id, [impl, fib_impl, on_close] { on_close(); });
      }
    }
  }
}

template <typename S>
void basic_fiber_demux_service<S>::close_all_fibers(implementation_type impl) {
  std::map<fiber_id, fiber_impl_type> fibers;
  {
    std::unique_lock<std::recursive_mutex> lock1(impl->bound_mutex);
    fibers = impl->bound;
  }

  for (auto& fiber : fibers) {
    close_fiber(impl, fiber.second);
  }
}

template <typename S>
void basic_fiber_demux_service<S>::close(implementation_type impl) {
  if (impl) {
    std::unique_lock<std::recursive_mutex> lock(impl->closing_mutex);
    if (!impl->closing) {
      impl->closing = true;
      close_all_fibers(impl);
      auto close_handler = [impl]() {
        impl->close_handler();
        // reset close handler (circular dependency)
        impl->close_handler = []() {};
      };
      impl->socket.get_io_service().post(close_handler);
      // not enough: have to close socket...
      boost::system::error_code ec;
      impl->socket.close(ec);
    }
  }
}

template <typename S>
void basic_fiber_demux_service<S>::shutdown_service() {}

}  // namespace fiber
}  // namespace asio
}  // namespace boost

#endif  // SSF_COMMON_BOOST_ASIO_FIBER_BASIC_FIBER_DEMUX_SERVICE_IMPL_IPP_

ext: ipp

max_stars_repo_name: ZhiQiAnSecFork/ssf

max_issues_repo_name: ZhiQiAnSecFork/ssf

max_forks_repo_name: ZhiQiAnSecFork/ssf