#include "GeneratorBase.h"

#include "GenericSingelton.h"

namespace routing {

const char *GeneratorBase::typeKey = "GeneratorType";
const char *GeneratorBase::nameKey = "Name";

GeneratorBase::GeneratorBase(QObject *parent)
    : GeneratorBase(nullptr, parent) {}

GeneratorBase::GeneratorBase(GeneratorBase::Data d, QObject *parent)
    : QObject(parent), _d(d) {}

GeneratorBase::~GeneratorBase() {}

bool GeneratorBase::save(QJsonObject &obj) const {
  obj[typeKey] = this->type();
  obj[nameKey] = this->name();
  return true;
}

bool GeneratorBase::load(const QJsonObject &obj, QString &errorString) {
  if (obj.contains(nameKey) && obj[nameKey].isString()) {
    setName(obj[nameKey].toString());
    return true;
  } else {
    errorString.append(
        tr("Not able to load generator name. Leaving name unchanged."));
    return false;
  }
}

QString GeneratorBase::name() const { return _name; }

void GeneratorBase::setName(const QString &name) {
  if (_name != name) {
    _name = name;
    emit nameChanged();
  }
}

GeneratorBase::Data GeneratorBase::data() const { return _d; }

void GeneratorBase::setData(Data d) {
  if (d != _d) {
    _d = d;
    emit dataChanged();
  }
}

GeneratorFactory::GeneratorFactory() {}

GeneratorFactory *GeneratorFactory::createInstance() {
  return new GeneratorFactory();
}

GeneratorFactory::~GeneratorFactory() {}

GeneratorFactory *GeneratorFactory::instance() {
  return GenericSingelton<GeneratorFactory>::instance(
      GeneratorFactory::createInstance);
}

bool GeneratorFactory::registerGenerator(const QString &type,
                                         GeneratorFactory::Creator creator) {
  const auto pair = _creatorMap.insert(std::make_pair(type, creator));
  auto success = pair.second;
  Q_ASSERT(success);
  return success;
}

bool GeneratorFactory::registered(const QString &type) {
  return _creatorMap.end() != _creatorMap.find(type);
}

void GeneratorFactory::unregisterGenerator(const QString &type) {
  _creatorMap.erase(type);
}

GeneratorBase *GeneratorFactory::create(const QString &type, QObject *parent) {
  auto it = _creatorMap.find(type);
  if (it != _creatorMap.end()) {
    auto &creator = it->second;
    return creator(parent);
  } else {
    return nullptr;
  }
}

GeneratorBase *GeneratorFactory::create(const QJsonObject &jsonGenerator,
                                        QString &errorMessage,
                                        QObject *parent) {
  if (jsonGenerator.contains(GeneratorBase::typeKey) &&
      jsonGenerator[GeneratorBase::typeKey].isString()) {
    auto gen = create(jsonGenerator[GeneratorBase::typeKey].toString(), parent);
    if (gen != nullptr) {
      QString e;
      if (gen->load(jsonGenerator, e)) {
        return gen;
      } else {
        gen->deleteLater();
        errorMessage.append(e);
        return nullptr;
      }
    } else {
      errorMessage.append(
          QObject::tr("Not able to create generator of type.\n") + " " +
          jsonGenerator[GeneratorBase::typeKey].toString());
      return nullptr;
    }
  } else {
    errorMessage.append(QObject::tr(
        "Not able to load Generator. Impossible to determine type.\n"));
    return nullptr;
  }
}

} // namespace routing
