#include <metadata_manager.hpp>
#include <layer.hpp>

std::map<std::string, std::vector<ObjectMetadata>> MetadataManager::_metadataMap = {};
std::string MetadataManager::_bottomMetalLayername = "";

bool MetadataManager::load(std::string filename, std::string layername) {
  //read data from file into vertex buffer, element buffer
  std::stringstream buffer;
  try {
    std::ifstream file(filename, std::ios_base::in);
    buffer << file.rdbuf();
    file.close();
  }
  catch (const std::exception e) {
    std::cerr << "An error occurred loading file " << filename << ": " << e.what() << std::endl;
    return false;
  }

  char c;
  int status;
  std::vector<ObjectMetadata> newDataVector;
  int count = 0;
  try {
    while (buffer) {
      c = 'x';
      buffer >> c;
      if (c == 'e') {
        ++count;
        buffer >> status;
        ObjectMetadata data;
        data.status = status;
        newDataVector.push_back(data);
      }
      else if (c == 'x') { //read nothing, probably happens on the last line
        continue;
      }
      else {
        std::cerr << "Encountered unknown directive " << c << " while parsing file " << filename << std::endl;
      }
    }
    //If we load bottom metal, restore the infostrings
    if (_bottomMetalLayername == layername) {
      for (size_t i = 0; i < newDataVector.size(); ++i) {
        newDataVector[i].info = _metadataMap[layername][i].info;
      }
    }
    _metadataMap[layername] = newDataVector;
    std::cout << "Loaded " << newDataVector.size() << " metadata entries for layer " << layername << " from " << filename << "." << std::endl;
    return true;
  }
  catch (const std::exception e) {
    std::cerr << "An error occurred parsing file " << filename << ": " << e.what() << std::endl;
    return false;
  }
}
bool MetadataManager::save(std::string filename, std::string layername) {
  try {
    std::ofstream file(filename, std::ios_base::out);
    std::string writestring = "";
    int count = 0;
    for (auto metadata : _metadataMap[layername]) {
      writestring += "e " + std::to_string(metadata.status) + "\n";
      ++count;
    }
    //if (writestring.length() > 0) {
    //  writestring.pop_back(); //remove trailing endline
    //}
    if (writestring.length() > 0) {
      file << writestring;
      file.close();
      std::cout << "Saved " << count << " metadata entries of layer " << layername << " to " << filename << "." << std::endl;
    }
    else {
      std::cerr << "Empty metadataset for layer " << layername << " cannot be saved." << std::endl;
      return false;
    }
    return true;
  }
  catch (const std::exception e) {
    std::cerr << "An error occurred writing to file " << filename << ": " << e.what() << std::endl;
    return false;
  }
}
bool MetadataManager::addLayer(const Layer& layer) {
  _metadataMap[layer.name()] = std::vector<ObjectMetadata>(layer.numObjects(), { 0 });
  return true;
}
void MetadataManager::markBottomMetal(std::string layername) {
  _bottomMetalLayername = layername;
  std::ifstream file("C:\\Users\\Pascal\\repos\\rbcomb-sample-visualizer\\gui\\resources\\association\\sample-minicircuit-association.txt");

  std::string line;
  while (std::getline(file, line))
  {
    if (line[0] == '#') {
      continue;
    }
    std::istringstream iss(line);
    unsigned index;
    if (!(iss >> index)) {
      continue;
    }
    if (index >= _metadataMap[layername].size()) {
      continue;
    }

    if (line.back() == 'e') { //"None"
      _metadataMap[layername][index].info = "Assignment:\n\tUnconnected";
      continue;
    }
    else {
      std::vector<std::string> split_line;
      std::string tempstr = "";
      for (auto c : line) {
        if (c == ' ') {
          if (tempstr != "") {
            split_line.push_back(tempstr);
          }
          tempstr.clear();
        }
        else {
          tempstr += c;
        }
      }
      split_line.push_back(tempstr); //append last one
      std::string infostr = "";
      infostr += "\tBreakout zif pad " + split_line[3] + " on net " + split_line[1];
      infostr += "\n\tAdapter zif pad " + split_line[4] + " on net " + split_line[5];
      infostr += "\n\tMinicircuit " + split_line[2] + " on channel (" + split_line[6] + ", " + split_line[7] + ")";
      _metadataMap[layername][index].info = infostr;
    }
  }
}
ObjectMetadata& MetadataManager::getData(std::string layername, int objectIndex) {
  return _metadataMap[layername][objectIndex];
}
std::vector<ObjectMetadata> MetadataManager::getLayerData(std::string layername) {
  return _metadataMap[layername];
}