#include "commandsdispatcher.h"

using namespace Schedule;

/**
 * @brief 命令执行相关Exception
 */
class Impl_CmdException : public CmdException
{
public:
    explicit Impl_CmdException(const QString& type, const QString &reason);
    virtual ~Impl_CmdException() = default;

    virtual QString type() const override;
    virtual QString reason() const override;

    // exception interface
public:
    virtual const char *what() const override;

private:
    QString ex_string;
    int title_length;
};

Impl_CmdException::Impl_CmdException(const QString &type, const QString &reason)
{
    title_length = type.length();
    ex_string = QString("%1:%2").arg(type, reason);
}

QString Impl_CmdException::type() const
{
    return ex_string.mid(0, title_length);
}

QString Impl_CmdException::reason() const
{
    return ex_string.mid(title_length+1);
}

const char *Impl_CmdException::what() const
{
    return ex_string.toLocal8Bit();
}

CommandsDispatcher::CommandsDispatcher(const QDir &script_out, bool record)
    : record_execute(record), bout(nullptr), tout(nullptr)
{
    start_time = QDateTime::currentDateTime();
    if(record){
        auto path = script_out.filePath(QString("commands_%1").arg(start_time.toSecsSinceEpoch()));
        bout = new QFile(path);
        if(!bout->open(QIODevice::WriteOnly|QIODevice::Text)){
            delete bout;
            bout = nullptr;
            throw new Impl_CmdException("文件创建失败", "指定宏记录文件创建失败：" + path);
        }
        tout = new QTextStream(bout);
        tout->setCodec("UTF-8");
    }
}

CommandsDispatcher::~CommandsDispatcher()
{
    if(tout){
        tout->flush();
        delete tout;
    }
    if(bout){
        bout->flush();
        bout->close();
        delete bout;
    }
}

void CommandsDispatcher::execute_script(const QString &filepath)
{
    throw new Impl_CmdException("执行过程错误", "未实现函数：execute_script");
}

void CommandsDispatcher::registerMember(AccessibleObject *obj)
{
    if(object_instances.contains(obj->name()))
        throw new Impl_CmdException("参数错误", "重复注册命名对象");

    object_instances[obj->name()] = obj;
}

void CommandsDispatcher::registerCommand(GeCommand *type)
{
    if(command_types.contains(type->name()))
        throw new Impl_CmdException("参数错误", "重复注册该命名命令：" + type->name());

    command_types[type->name()] = type;
}

QList<GeCommand *> CommandsDispatcher::listCommands() const
{
    return command_types.values();
}

void CommandsDispatcher::postCommand(const GeCommand &c)
{
    if(!command_types.contains(c.name()))
        throw new Impl_CmdException("参数错误", "指定的命令类型未注册：" + c.name());

    if(record_execute)
        *tout << QString("[%1]%2#").arg(QDateTime::currentDateTime().msecsTo(start_time)).arg(c.name())
              << c.toText() << endl;

    try{
        c.run(this);
    }catch(...){
        *tout << QString("<<<<<< 该命令执行过程中出现异常 >>>>>>") << endl;
        tout->flush();
        throw;
    }
}

void CommandsDispatcher::postCommandText(const QString &line)
{
    auto split_index = line.indexOf("#");
    auto name = line.mid(0, split_index).trimmed();

    if(!command_types.contains(name))
        throw new Impl_CmdException("参数错误", "指定的命令类型未注册：" + name);

    auto content = line.mid(split_index+1);
    auto ins = command_types[name];
    ins->fromText(content);

    postCommand(*ins);
}






















