#ifndef _CLI_CAST_INTROSPECTION_COMMAND_H_
#define _CLI_CAST_INTROSPECTION_COMMAND_H_

#include <command/Command.h>
#include <environment/Environment.h>
#include <alib/list>

namespace cli {

class CastsIntrospectionCommand : public Command {
	std::unique_ptr < cli::Arg > m_param;
	bool m_from;
	bool m_to;

public:
	CastsIntrospectionCommand (std::unique_ptr < cli::Arg > param, bool from, bool to ) : m_param ( std::move ( param ) ), m_from ( from ), m_to ( to ) {
	}

	void printTypes ( const ext::list < ext::pair < std::string, bool > > & types ) const {
		for ( const ext::pair < std::string, bool > & type : types ) {
			common::Streams::out << type.first;
			if ( type.second )
				common::Streams::out << " explicit ";
			common::Streams::out << std::endl;
		}
	}

	void printCasts ( const ext::list < ext::tuple < std::string, std::string, bool > > & casts ) const {
		for ( const ext::tuple < std::string, std::string, bool > & cast : casts ) {
			common::Streams::out << std::get < 0 > ( cast ) << ", " << std::get < 1 > ( cast );
			if ( std::get < 2 > ( cast ) )
				common::Streams::out << " explicit";
			common::Streams::out << std::endl;
		}
	}

	Command::Result run ( Environment & environment ) const override {
		std::string param;
		if ( m_param != nullptr )
			param = m_param->eval ( environment );

		if ( m_from )
			printTypes ( abstraction::Registry::listCastsFrom ( param ) );

		if ( m_to )
			printTypes ( abstraction::Registry::listCastsTo ( param ) );

		if ( ! m_from && ! m_to )
			printCasts ( abstraction::Registry::listCasts ( ) );

		return Command::Result::OK;
	}
};

} /* namespace cli */

#endif /* _CLI_CAST_INTROSPECTION_COMMAND_H_ */
