#ifndef _CLI_HELP_COMMAND_H_
#define _CLI_HELP_COMMAND_H_

#include <ast/Command.h>
#include <environment/Environment.h>

namespace cli {

class HelpCommand : public Command {
	std::unique_ptr < cli::Arg > m_command;

public:
	HelpCommand ( std::unique_ptr < cli::Arg > command ) : m_command ( std::move ( command ) ) {
	}

	CommandResult run ( Environment & environment ) const override {
		std::string command;
		if ( m_command != nullptr )
			command = m_command->eval ( environment );

		if ( command == "execute" ) {
			common::Streams::out << "Execute command executes statements and either prints the result or writes the result to a file" << std::endl;
			common::Streams::out << "The qualification of the type of the result is remembered and when connecting statements together the compatibility with respective param is checked." << std::endl;
			common::Streams::out << "It is possible to use ^ symbol to move the result value of a statement to a parameter of another statement." << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "statement_list:" << std::endl;
			common::Streams::out << "statement ( | statement )* - at least one statement followed by a pipe separated sequence of other statements" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "arg:" << std::endl;
			common::Streams::out << "value  - immediate string value" << std::endl;
			common::Streams::out << "#value - string value from environmet variable" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "template_param:" << std::endl;
			common::Streams::out << "@ arg       - template param given by arg value" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "param:" << std::endl;
			common::Streams::out << "[^] -                   - a value from the previous result (PreviousResultParam)" << std::endl;
			common::Streams::out << "[^] <( statement_list ) - a statement list serving as a param (StatementParam)" << std::endl;
			common::Streams::out << "[^] ( arg ) param       - a casted parameter, type is given by arg value (CastParam)" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "identifier  - a string param - the value is a immediate string (ImmediateParam)" << std::endl;
			common::Streams::out << "number      - a number param - the value is a immediate integer (ImmediateParam)" << std::endl;
			common::Streams::out << "#identifier - a string param - identified by an environment variable (ValueParam)" << std::endl;
			common::Streams::out << "[^] $arg    - a value from a variable, name is given by arg value (VariableParam)" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "<arg        - a value from a xml file, filename is given by arg value (FileParam)" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "statement:" << std::endl;
			common::Streams::out << "name ( template_param )* ( param )* output_spec - a statement with params, name is an immediate value (SingleStatement)" << std::endl;
			common::Streams::out << "( type ) [^] statement      - the result of a statement is casted, type is given by value (CastedStatement)" << std::endl;
			common::Streams::out << "{ :type ( statement ) * }   - creates a set of type given by arg value with content values from individual statements" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "#identifier   - an immediate value from an environment (ValueStatement)" << std::endl;
			common::Streams::out << "$identifier   - a value from a variable, identifier is an immediate value (VariableStatement)" << std::endl;
			common::Streams::out << "$#identifier  - a value from a variable, identified by an environment variable (VariableStatement)" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "< [:type] arg - a value from a xml file, identifier is given by arg value, type of the value can be hinted with optional parameter (FileStatement)" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "output_spec:" << std::endl;
			common::Streams::out << ">arg     - a value to a xml file, identifier is given by arg value (ResultFileStatement)" << std::endl;
			common::Streams::out << ">$arg    - a value to a variable, identifier is given by arg value  (ResultVariableStatement)" << std::endl;
			common::Streams::out << ">        - a value is discarded" << std::endl;
			common::Streams::out << "         - an empty output specifier prints the result to the stdout (ResultPrintStatement)" << std::endl;
		} else if ( command.empty ( ) ) {
			common::Streams::out << "Simple help for the query language" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "command quit: quits the processor." << std::endl;
			common::Streams::out << "command help: shows this help." << std::endl;
			common::Streams::out << "command introspect: prints available algorithms, algorithm overloads, casts, and datatypes." << std::endl;
			common::Streams::out << "command execute: executes statements" << std::endl;
			common::Streams::out << "" << std::endl;
			common::Streams::out << "for details use help of individual command" << std::endl;
		} else {
			common::Streams::out << "The command " << command << " either does not exist or does not have a help entry." << std::endl;
		}
		return CommandResult::OK;
	}
};

} /* namespace cli */

#endif /* _CLI_HELP_COMMAND_H_ */
