/*
	Copyright 2016, 2017 Michele "King_DuckZ" Santullo

	This file is part of MyCurry.

	MyCurry is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	MyCurry 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.

	You should have received a copy of the GNU General Public License
	along with MyCurry.  If not, see <http://www.gnu.org/licenses/>.
*/

#define BOOST_SPIRIT_USE_PHOENIX_V3 1

#include "csvloader.hpp"
#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi_lit.hpp>
#include <boost/spirit/include/qi_eoi.hpp>
#include <boost/spirit/include/qi_eol.hpp>
#include <boost/spirit/include/qi_kleene.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/phoenix/core/reference.hpp>
#include <boost/phoenix/operator/arithmetic.hpp>
#include <sstream>
#include <fstream>
#include <ciso646>
#include <utility>
#include <algorithm>

namespace qi = boost::spirit::qi;

namespace curry {
	CSVJointData load_csv(const std::vector<std::string>& parCsvPath) {
		typedef boost::spirit::istream_iterator iter_type;
		using boost::phoenix::ref;

		qi::int_parser<TileIndex> idx;
		//auto csv_parser = *((qi::int_ % ',') >> -qi::eol) >> qi::eoi;
		CSVJointData out_csv;
		std::size_t row_count = 0;
		TileIndex largest_tile_idx = 0;

		for (auto& csv_path : parCsvPath) {
			std::ifstream f_map(csv_path);
			f_map.unsetf(std::ios::skipws);

			std::vector<TileIndex> curr_data;
			row_count = 0;
			const bool parse_fail = qi::parse(
				iter_type(f_map),
				iter_type(),
				idx % (',' | qi::eol[ref(row_count) += 1]) >> qi::eoi,
				curr_data
			);

			if (parse_fail) {
				std::ostringstream oss;
				oss << "Error parsing csv \"" << csv_path << "\"";
				throw std::runtime_error(oss.str());
			}
			if (not curr_data.empty()) {
				largest_tile_idx = std::max(*std::max_element(curr_data.begin(), curr_data.end()), largest_tile_idx);
			}
			out_csv.tables.emplace_back(std::move(curr_data));
		}

		if (not out_csv.tables.empty()) {
			out_csv.height = static_cast<uint16_t>(row_count);
			out_csv.width = static_cast<uint16_t>(out_csv.tables.front().size() / row_count);
		}
		else {
			out_csv.height = out_csv.width = 0;
		}

		out_csv.tile_properties.resize(static_cast<size_t>(largest_tile_idx) + 1);

#if !defined(NDEBUG)
		for (const auto& table : out_csv.tables) {
			for (const auto& val : table) {
				const auto casted_val = static_cast<size_t>(val);
				assert(val < 0 or casted_val < out_csv.tile_properties.size());
			}
		}
#endif
		return out_csv;
	}
} //namespace curry
