mirror of https://github.com/JAJames/Jupiter.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
8.9 KiB
269 lines
8.9 KiB
/**
|
|
* Copyright (C) 2015-2016 Jessica James.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Written by Jessica James <jessica.aj@outlook.com>
|
|
*/
|
|
|
|
#include "GenericCommand.h"
|
|
#include "Plugin.h"
|
|
|
|
using namespace Jupiter::literals;
|
|
|
|
constexpr const char GENERIC_COMMAND_WORD_DELIMITER = ' ';
|
|
constexpr const char *GENERIC_COMMAND_WORD_DELIMITER_CS = " ";
|
|
|
|
Jupiter::GenericCommandNamespace o_generic_commands;
|
|
Jupiter::GenericCommandNamespace &Jupiter::g_generic_commands = o_generic_commands;
|
|
|
|
/** GenericCommand */
|
|
|
|
Jupiter::GenericCommand::GenericCommand()
|
|
{
|
|
if (&o_generic_commands != this)
|
|
Jupiter::GenericCommand::setNamespace(o_generic_commands);
|
|
}
|
|
|
|
Jupiter::GenericCommand::~GenericCommand()
|
|
{
|
|
// Inform the parent
|
|
if (GenericCommand::m_parent != nullptr)
|
|
GenericCommand::m_parent->removeCommand(*this);
|
|
|
|
// Notify plugins
|
|
for (size_t index = 0; index != Jupiter::plugins->size(); ++index)
|
|
Jupiter::plugins->get(index)->OnGenericCommandRemove(*this);
|
|
}
|
|
|
|
bool Jupiter::GenericCommand::isNamespace() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void Jupiter::GenericCommand::setNamespace(const Jupiter::ReadableString &in_namespace)
|
|
{
|
|
if (in_namespace.wordCount(GENERIC_COMMAND_WORD_DELIMITER_CS) == 0)
|
|
return; // We're already here
|
|
|
|
if (Jupiter::GenericCommand::m_parent == nullptr)
|
|
return; // We have no parent to start from
|
|
|
|
Jupiter::GenericCommand *command = Jupiter::GenericCommand::m_parent->getCommand(in_namespace);
|
|
if (command != nullptr && command->isNamespace())
|
|
Jupiter::GenericCommand::setNamespace(*reinterpret_cast<Jupiter::GenericCommandNamespace *>(command));
|
|
}
|
|
|
|
void Jupiter::GenericCommand::setNamespace(Jupiter::GenericCommandNamespace &in_namespace)
|
|
{
|
|
if (Jupiter::GenericCommand::m_parent != nullptr) // Remove from previous parent
|
|
Jupiter::GenericCommand::m_parent->removeCommand(*this);
|
|
|
|
// Add to new parent
|
|
Jupiter::GenericCommand::m_parent = &in_namespace;
|
|
in_namespace.addCommand(*this);
|
|
}
|
|
|
|
Jupiter::GenericCommandNamespace *Jupiter::GenericCommand::getNamespace() const
|
|
{
|
|
return Jupiter::GenericCommand::m_parent;
|
|
}
|
|
|
|
/** GenericCommand::ResponseLine */
|
|
|
|
Jupiter::GenericCommand::ResponseLine::ResponseLine(const Jupiter::ReadableString &response_, GenericCommand::DisplayType type_)
|
|
{
|
|
GenericCommand::ResponseLine::response = response_;
|
|
GenericCommand::ResponseLine::type = type_;
|
|
}
|
|
|
|
Jupiter::GenericCommand::ResponseLine *Jupiter::GenericCommand::ResponseLine::set(const Jupiter::ReadableString &response_, GenericCommand::DisplayType type_)
|
|
{
|
|
GenericCommand::ResponseLine::response = response_;
|
|
GenericCommand::ResponseLine::type = type_;
|
|
return this;
|
|
}
|
|
|
|
/** GenericCommandNamespace */
|
|
|
|
Jupiter::GenericCommandNamespace::~GenericCommandNamespace()
|
|
{
|
|
// Murder the children
|
|
Jupiter::GenericCommandNamespace::m_commands.emptyAndDelete();
|
|
}
|
|
|
|
Jupiter::GenericCommand::ResponseLine *Jupiter::GenericCommandNamespace::trigger(const Jupiter::ReadableString &in_input)
|
|
{
|
|
GenericCommand *command;
|
|
Jupiter::ReferenceString input(in_input);
|
|
|
|
if (input.wordCount(GENERIC_COMMAND_WORD_DELIMITER_CS) == 0) // No parameters; list commands
|
|
return new Jupiter::GenericCommand::ResponseLine(Jupiter::GenericCommandNamespace::m_help, Jupiter::GenericCommand::DisplayType::PrivateSuccess);
|
|
|
|
command = Jupiter::GenericCommandNamespace::getCommand(input.getWord(0, GENERIC_COMMAND_WORD_DELIMITER_CS));
|
|
if (command != nullptr)
|
|
return command->trigger(input.gotoWord(1, GENERIC_COMMAND_WORD_DELIMITER_CS));
|
|
|
|
return new Jupiter::GenericCommand::ResponseLine(Jupiter::ReferenceString::empty, Jupiter::GenericCommand::DisplayType::PrivateError);
|
|
}
|
|
|
|
const Jupiter::ReadableString &Jupiter::GenericCommandNamespace::getHelp(const Jupiter::ReadableString ¶meters)
|
|
{
|
|
static Jupiter::ReferenceString not_found = "Error: Command not found"_jrs;
|
|
|
|
if (parameters.wordCount(GENERIC_COMMAND_WORD_DELIMITER_CS) == 0) // No parameters; list commands
|
|
{
|
|
if (Jupiter::GenericCommandNamespace::m_should_update_help)
|
|
Jupiter::GenericCommandNamespace::updateHelp();
|
|
|
|
return Jupiter::GenericCommandNamespace::m_help;
|
|
}
|
|
|
|
Jupiter::ReferenceString input(parameters);
|
|
GenericCommand *command;
|
|
|
|
// Search for command
|
|
command = Jupiter::GenericCommandNamespace::getCommand(input.getWord(0, GENERIC_COMMAND_WORD_DELIMITER_CS));
|
|
if (command != nullptr)
|
|
return command->getHelp(input.gotoWord(1, GENERIC_COMMAND_WORD_DELIMITER_CS));
|
|
|
|
// Command not found
|
|
return not_found;
|
|
}
|
|
|
|
bool Jupiter::GenericCommandNamespace::isNamespace() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool Jupiter::GenericCommandNamespace::isUsing() const
|
|
{
|
|
return m_using;
|
|
}
|
|
|
|
void Jupiter::GenericCommandNamespace::setUsing(bool in_value)
|
|
{
|
|
m_using = in_value;
|
|
|
|
if (Jupiter::GenericCommand::m_parent != nullptr)
|
|
Jupiter::GenericCommand::m_parent->updateHelp();
|
|
}
|
|
|
|
Jupiter::ArrayList<Jupiter::GenericCommand> Jupiter::GenericCommandNamespace::getCommands() const
|
|
{
|
|
Jupiter::ArrayList<Jupiter::GenericCommand> result(Jupiter::GenericCommandNamespace::m_commands.size());
|
|
Jupiter::GenericCommand *command;
|
|
size_t tmp_index;
|
|
|
|
for (size_t command_index = 0; command_index != Jupiter::GenericCommandNamespace::m_commands.size(); ++command_index)
|
|
{
|
|
command = Jupiter::GenericCommandNamespace::m_commands.get(command_index);
|
|
result.add(command);
|
|
|
|
if (command->isNamespace() && reinterpret_cast<GenericCommandNamespace *>(command)->isUsing())
|
|
{
|
|
// Add commands from namespace
|
|
Jupiter::ArrayList<Jupiter::GenericCommand> tmp = reinterpret_cast<GenericCommandNamespace *>(command)->getCommands();
|
|
|
|
for (tmp_index = 0; tmp_index != tmp.size(); ++tmp_index)
|
|
result.add(tmp.get(tmp_index));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Jupiter::GenericCommand *Jupiter::GenericCommandNamespace::getCommand(const Jupiter::ReadableString &in_command) const
|
|
{
|
|
Jupiter::GenericCommand *command;
|
|
size_t command_index, namespaces = 0;
|
|
|
|
/** This is broken into 2 loops in order to insure that exact matches are ALWAYS prioritized over inexact matches */
|
|
|
|
// Search commands
|
|
for (command_index = 0; command_index != Jupiter::GenericCommandNamespace::m_commands.size(); ++command_index)
|
|
{
|
|
command = Jupiter::GenericCommandNamespace::m_commands.get(command_index);
|
|
|
|
if (command->matches(in_command)) // Command found
|
|
return command;
|
|
else if (command->isNamespace() && reinterpret_cast<GenericCommandNamespace *>(command)->isUsing()) // Search namespace for matches
|
|
++namespaces;
|
|
}
|
|
|
|
// None found; check namespaces
|
|
for (command_index = 0; namespaces != 0; ++command_index)
|
|
{
|
|
command = Jupiter::GenericCommandNamespace::m_commands.get(command_index);
|
|
|
|
if (command->isNamespace() && reinterpret_cast<GenericCommandNamespace *>(command)->isUsing())
|
|
{
|
|
command = reinterpret_cast<GenericCommandNamespace *>(command)->getCommand(in_command);
|
|
if (command != nullptr) // match found
|
|
return command;
|
|
|
|
--namespaces;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void Jupiter::GenericCommandNamespace::addCommand(Jupiter::GenericCommand &in_command)
|
|
{
|
|
if (in_command.getNamespace() != this)
|
|
in_command.setNamespace(*this);
|
|
else
|
|
{
|
|
Jupiter::GenericCommandNamespace::m_commands.add(&in_command);
|
|
Jupiter::GenericCommandNamespace::m_should_update_help = true;
|
|
}
|
|
}
|
|
|
|
void Jupiter::GenericCommandNamespace::removeCommand(Jupiter::GenericCommand &in_command)
|
|
{
|
|
for (size_t index = 0; index != Jupiter::GenericCommandNamespace::m_commands.size(); ++index)
|
|
if (Jupiter::GenericCommandNamespace::m_commands.get(index) == &in_command)
|
|
{
|
|
Jupiter::GenericCommandNamespace::m_commands.remove(index);
|
|
Jupiter::GenericCommandNamespace::m_should_update_help = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Jupiter::GenericCommandNamespace::removeCommand(const Jupiter::ReadableString &in_command)
|
|
{
|
|
for (size_t index = 0; index != Jupiter::GenericCommandNamespace::m_commands.size(); ++index)
|
|
if (Jupiter::GenericCommandNamespace::m_commands.get(index)->matches(in_command))
|
|
{
|
|
Jupiter::GenericCommandNamespace::m_commands.remove(index);
|
|
Jupiter::GenericCommandNamespace::m_should_update_help = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Jupiter::GenericCommandNamespace::updateHelp()
|
|
{
|
|
Jupiter::GenericCommandNamespace::m_should_update_help = false;
|
|
|
|
Jupiter::ArrayList<Jupiter::GenericCommand> commands = Jupiter::GenericCommandNamespace::getCommands();
|
|
Jupiter::StringL tmp_help(commands.size() * 8);
|
|
|
|
for (size_t index = 0; index != commands.size(); ++index)
|
|
{
|
|
tmp_help += commands.get(index)->getTrigger();
|
|
tmp_help += ' ';
|
|
}
|
|
|
|
Jupiter::GenericCommandNamespace::m_help = tmp_help;
|
|
}
|
|
|