/*
 *
 * This file is part of Tulip (https://tulip.labri.fr)
 *
 * Authors: David Auber and the Tulip development Team
 * from LaBRI, University of Bordeaux
 *
 * Tulip is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * Tulip is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 */

#include <cstring>

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#include <tulip/TulipFontAwesome.h>
#include <tulip/TlpTools.h>

#include <utf8.h>

#include <map>

using namespace std;

namespace tlp {

struct cmpCharPtr {
  bool operator()(const char *s1, const char *s2) const {
    return strcmp(s1, s2) < 0;
  }
};
static map<const char *, unsigned int, cmpCharPtr> iconCodePoint;
static vector<std::string> iconsNames;

static string iconFile(const string &iconName) {
  switch (iconName[2]) {
  case 's':
    return "fa-solid-900";
  case 'r':
    return "fa-regular-400";
  case '-': {
    // compatibility with Tulip 5
    std::string name(iconName);
    // fa-...-o => far-..
    if (name.compare(name.size() - 2, 2, "-o") == 0) {
      name.resize(name.size() - 2);
      name.insert(2, 1, 'r');
      if (iconCodePoint.find(name.c_str()) != iconCodePoint.end())
        return "fa-regular-400";
    } else {
      // fa-... => fa[s|r|b]-...
      name.insert(2, 1, 's');
      if (iconCodePoint.find(name.c_str()) != iconCodePoint.end())
        return "fa-solid-900";
      name[2] = 'r';
      if (iconCodePoint.find(name.c_str()) != iconCodePoint.end())
        return "fa-regular-400";
    }
    [[fallthrough]];
  }
  default:
    return "fa-brands-400";
  }
}

static void addIconCodePoint(const char *iconName, unsigned int codePoint) {
  iconCodePoint[iconName] = codePoint;
}

// code generated by generate_fa_init_cpp_code.sh
#include "TulipInitFontAwesome.cpp"

std::string TulipFontAwesome::getTTFLocation(const std::string &iconName) {
  if (iconCodePoint.empty())
    initIconCodePoints();
  return string(tlp::TulipBitmapDir).append(iconFile(iconName)).append(".ttf");
}

std::string TulipFontAwesome::getWOFF2Location(const std::string &iconName) {
  if (iconCodePoint.empty())
    initIconCodePoints();
  return string(tlp::TulipBitmapDir).append(iconFile(iconName.c_str())).append(".woff2");
}

bool TulipFontAwesome::isIconSupported(const std::string &iconName) {
  if (iconCodePoint.empty()) {
    initIconCodePoints();
  }

  return iconCodePoint.find(iconName.c_str()) != iconCodePoint.end();
}

const vector<std::string> &TulipFontAwesome::getSupportedIcons() {
  if (iconCodePoint.empty()) {
    initIconCodePoints();
  }

  return iconsNames;
}

unsigned int TulipFontAwesome::getIconCodePoint(const std::string &iconName) {
  if (iconCodePoint.empty()) {
    initIconCodePoints();
  }

  auto it = iconCodePoint.find(iconName.c_str());

  if (it != iconCodePoint.end())
    return (it->second);
  if (iconName[2] == '-') {
    // ensure compatibility with version before Tulip 5.7
    std::string name(iconName);
    // fa-...-o => far-..
    if (name.compare(name.size() - 2, 2, "-o") == 0) {
      name.resize(name.size() - 2);
      name.insert(2, 1, 'r');
      it = iconCodePoint.find(name.c_str());
    } else {
      // fa-... => fa[s|r|b]-...
      name.insert(2, 1, 's');
      it = iconCodePoint.find(name.c_str());
      if (it == iconCodePoint.end()) {
        name[2] = 'r';
        it = iconCodePoint.find(name.c_str());
        if (it == iconCodePoint.end()) {
          name[2] = 'b';
          it = iconCodePoint.find(name.c_str());
        }
      }
    }
    if (it != iconCodePoint.end()) {
      // output deprecation warning
      tlp::warning() << "Warning: icon name \"" << iconName << "\" is deprecated, use \"" << name
                     << "\" instead." << std::endl;
      return (it->second);
    }
  }

  return 0;
}

std::string TulipFontAwesome::getIconFamily(const std::string &iconName) {
  if (iconCodePoint.empty()) {
    initIconCodePoints();
  }

  return iconFile(iconName.c_str());
}

std::string TulipFontAwesome::getIconStyle(const std::string &iconName) {
  return (iconName[2] == 's') ? "Solid" : "Regular";
}

std::string TulipFontAwesome::getIconUtf8String(const std::string &iconName) {
  if (iconCodePoint.empty()) {
    initIconCodePoints();
  }

  std::string iconString;
  // ensure compatibility with version before Tulip 5.7
  auto cp = getIconCodePoint(iconName);
  if (cp)
    utf8::append(cp, back_inserter(iconString));
  return iconString;
}
} // namespace tlp
