/*
 * ValueOperationAbstraction.hpp
 *
 *  Created on: 11. 7. 2017
 *	  Author: Jan Travnicek
 */

#ifndef _VALUE_OPERATION_ABSTRACTION_HPP_
#define _VALUE_OPERATION_ABSTRACTION_HPP_

#include <alib/array>
#include <alib/memory>

#include <common/ParamQualifiers.hpp>

#include <abstraction/ValueHolder.hpp>
#include <common/AbstractionHelpers.hpp>

namespace abstraction {

template < class ReturnType >
class ValueOperationAbstraction : virtual public OperationAbstraction {
public:
	template < typename ... ParamTypes, typename Callable >
	inline std::shared_ptr < abstraction::Value > run_helper ( Callable callback, const ext::array < std::pair < std::shared_ptr < abstraction::Value >, bool >, sizeof ... ( ParamTypes ) > & inputs ) {
		return std::make_shared < abstraction::ValueHolder < ReturnType > > ( this->getProxyAbstraction ( ), abstraction::apply < ParamTypes ... > ( callback, inputs ) );
	}

	ext::set < abstraction::ParamQualifiers::ParamQualifier > getReturnTypeQualifiers ( ) const override {
		return abstraction::ParamQualifiers::paramQualifiers < ReturnType > ( );
	}

	ext::type_index getReturnTypeIndex ( ) const override {
		return ext::type_index ( typeid ( ReturnType ) );
	}

};

template < >
class ValueOperationAbstraction < void > : virtual public OperationAbstraction {
public:
	template < typename ... ParamTypes, typename Callable >
	inline std::shared_ptr < abstraction::Value > run_helper ( Callable callback, const ext::array < std::pair < std::shared_ptr < abstraction::Value >, bool >, sizeof ... ( ParamTypes ) > & inputs ) {
		abstraction::apply < ParamTypes ... > ( callback, inputs );
		return std::make_shared < abstraction::Void > ( this->getProxyAbstraction ( ) );
	}

	ext::type_index getReturnTypeIndex ( ) const override;

	ext::set < abstraction::ParamQualifiers::ParamQualifier > getReturnTypeQualifiers ( ) const override;
};

} /* namespace abstraction */

#endif /* _VALUE_OPERATION_ABSTRACTION_HPP_ */
