// SquareGridMapParser.hpp
//
//     Created on: 17. 03. 2018
//         Author: Jan Uhlik
//    Modified by:
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library

#pragma once

#include <fstream>
#include <stdexcept>
#include <limits>
#include <iostream>
#include <tuple>

namespace graph {
namespace parser {

class SquareGridMapParser {
// ---------------------------------------------------------------------------------------------------------------------
 public:
  template<typename TGrid>
  static
  std::tuple<TGrid, typename TGrid::node_type, typename TGrid::node_type>
  parse(const std::string &filename);

// ---------------------------------------------------------------------------------------------------------------------
};

// =====================================================================================================================

template<typename TGrid>
std::tuple<TGrid, typename TGrid::node_type, typename TGrid::node_type>
SquareGridMapParser::parse(const std::string &filename) {
  using node_type = typename TGrid::node_type;
  std::ifstream file(filename);

  if (!file.is_open()) {
    throw std::runtime_error("Could not open file: '" + filename + "'.");
  }

  // Read header
  unsigned long height, width, i = 0, j = 0;
  file.ignore(std::numeric_limits<std::streamsize>::max(), file.widen('\n')); // skip first line
  file.ignore(std::numeric_limits<std::streamsize>::max(), file.widen(' ')); // skip height
  file >> height;
  file.ignore(std::numeric_limits<std::streamsize>::max(), file.widen(' ')); // skip width
  file >> width;
  file.ignore(std::numeric_limits<std::streamsize>::max(), file.widen('\n')); // skip the endline
  file.ignore(std::numeric_limits<std::streamsize>::max(), file.widen('\n')); // skip 'map'

  // Read grid
  TGrid grid(height, width);
  node_type start(0, 0), goal(0, 0);
  std::string line;
  while (getline(file, line)) {
    j = 0;
    for (const auto &c: line) {
      if (c == 'S') {
        start.first = i;
        start.second = j;
      } else if (c == 'G') {
        goal.first = i;
        goal.second = j;
      } else if (c != '.') {
        grid.addObstacle(i, j);
      }

      ++j; // Increase column
    }
    ++i; // Increase row
  }

  file.close();

  return std::make_tuple(grid, start, goal);

}

// ---------------------------------------------------------------------------------------------------------------------

}
}

