/* map.h - Map definition
* Copyright (C) 2014 Paulo Pinto
*
* This library 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 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef MAP_H
#define MAP_H

#pragma once

#include <cassert>
#include <string>
#include <memory>
#include <mutex>
#include <utility>
#include <iosfwd>

// forward declarations
class Node;

/**
 * Class to represent the maps used for the A* algorithm.
 */
class Map
{
public:
	static const int MAP_COLS = 126;
	static const int MAP_ROWS = 126;
    enum class CellType {FREE, BLOCKED, VISITED, NODE_PATH, START, END};

    Map();
    Map(const std::string& filename);

    bool load(const std::string& filename);
	bool load(std::wistream& fd);
	
	void clear();

	// Declared as inline member function so that we get the abstraction
	// without speed penalty.
	CellType at (int row, int col) const { 
        assert((col >= 0 && col < MAP_COLS) && (row >= 0 && row < MAP_ROWS));
        std::lock_guard<std::mutex> lock(m_map_mutex);
        return m_map[row][col]; 
    }

    void set_pos (int row, int col, CellType cell) {
        assert((col >= 0 && col < MAP_COLS) && (row >= 0 && row < MAP_ROWS));
        std::lock_guard<std::mutex> lock(m_map_mutex);
        m_map[row][col] = cell;
        if (cell == CellType::START) {
            start = std::make_pair(row, col);
        } else if (cell == CellType::END) {
            end = std::make_pair(row, col);
        }
    }

    void visit(int row, int col) {
        assert((col >= 0 && col < MAP_COLS) && (row >= 0 && row < MAP_ROWS));
        std::lock_guard<std::mutex> lock(m_map_mutex);
        m_map[row][col] = CellType::VISITED;
    }

    void dump_map();
    void add_path(std::shared_ptr<Node> path);

    const std::pair<int, int>& get_start() { return start; }
    const std::pair<int, int>& get_end() { return end; }

private:
	CellType m_map[MAP_ROWS][MAP_COLS];
    mutable std::mutex m_map_mutex;
    std::pair<int, int> start, end;
};

#endif // MAP_H
