/*************************************************************************
*  Copyright (C) 2013 by Burak ER                                 	 *
*									 *
*                                                                        *
*  This program is free software; it is licensed under the terms of the  *
*  GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/
#ifdef YADE_FEM

#include <pkg/fem/DeformableElement.hpp>
#include <pkg/fem/FEInternalForceDispatchers.hpp>
#include <pkg/fem/FEInternalForceEngine.hpp>

namespace yade { // Cannot have #include directive inside.

YADE_PLUGIN((FEInternalForceEngine));
CREATE_LOGGER(FEInternalForceEngine);

void FEInternalForceEngine::pyHandleCustomCtorArgs(boost::python::tuple& t, boost::python::dict& /*d*/){
	cout<<"Entered the initialization function";
	if(boost::python::len(t)==0) return; // nothing to do

	if(boost::python::len(t)!=1) throw invalid_argument("At least 1 functors must be given");



	boost::python::list vv=boost::python::extract<boost::python::list>(t[0])();

//	FOREACH(shared_ptr<InternalForceFunctor> iff, vv) this->internalforcedispatcher->add(iff);

	for( int i=0;i<len(vv);i++) this->internalforcedispatcher->add(boost::python::extract<shared_ptr<InternalForceFunctor>>(vv[i]));
	

	t=boost::python::tuple(); // empty the args; not sure if this is OK, as there is some refcounting in raw_constructor code
	cout<<"Added to the list";
}


void FEInternalForceEngine::action(){

	// update Scene* of the dispatcher
	internalforcedispatcher->scene=scene;
	// ask dispatcher to update Scene* of their functors
	internalforcedispatcher->updateScenePtr();

	// call InternalForceFunctor::preStep
	//FOREACH(const shared_ptr<InternalForceFunctor>& iff, internalforcedispatcher->functors) iff->preStep();

	/*
		initialize callbacks; they return pointer (used only in this timestep) to the function to be called
		returning NULL deactivates the callback in this timestep
	*/
//	// pair of callback object and pointer to the function to be called
//	vector<IntrCallback::FuncPtr> callbackPtrs;
//	FOREACH(const shared_ptr<IntrCallback> cb, callbacks){
//		cb->scene=scene;
//		callbackPtrs.push_back(cb->stepInit());
//	}
//	assert(callbackPtrs.size()==callbacks.size());
//	size_t callbacksSize=callbacks.size();

	// cache transformed cell size
	//	Matrix3r cellHsize; if(scene->isPeriodic) cellHsize=scene->cell->hSize;


	#ifdef YADE_OPENMP
	const long size=scene->bodies->size();
	#pragma omp parallel for schedule(guided) num_threads(ompThreads>0 ? ompThreads : omp_get_max_threads())
	for(long i=0; i<size; i++){
		shared_ptr<Body>& bdy=(*scene->bodies)[i];
	#else
	FOREACH(const shared_ptr<Body>& bdy, *scene->bodies){
	#endif

			//Try to get internal functor
			if(bdy->shape->internalforcefunctor.get()==0) {
				//If there isn't any internalforcefunctor; try to get one
				bdy->shape->internalforcefunctor=internalforcedispatcher->getFunctor(bdy->shape,bdy->material);
				//İf we found any of them that is suitable to this element???
				if(bdy->shape->internalforcefunctor!=0){
					//If yes try to apply internal force functor
					shared_ptr<DeformableElement> deformableElement=YADE_PTR_CAST<DeformableElement>(bdy->shape);
					bdy->shape->internalforcefunctor->go(deformableElement,bdy->material,bdy);
				}
			}
			else{
				//Take functor from cache and call it's go functor
				shared_ptr<DeformableElement> deformableElement=YADE_PTR_CAST<DeformableElement>(bdy->shape);
				bdy->shape->internalforcefunctor->go(deformableElement,bdy->material,bdy);
			}

	}
}

} // namespace yade

#endif //YADE_FEM

