#pragma once
#include <queue>
#include <vector>
/*
 * Решили, что метод canAttackForDistance(int) имеет шаблон, который обозначает тип атаки
 * Melee - без учёта препятствий
 * Range - с учётом препятствий
 * Шаблон - строка. При такой реализации можно добавить новый вид атаки
 * Необходимо в Unit добавить метод bool isCharacter() - является ли данный юнит персонажем
 */
class Unit;
/*
 * Этот класс Игоря ждёт своей реализации
 * (Название неточное)
 * Необходимо добавить методы:
 * OperateOnCell(Cell*)
 * OperateOnUnit(Unit*)
 */
class EffectsForCell;

class Cell {
private:
	/*
	 * Соседние клетки к текущей
	 * nullptr, если ее не существует
	*/
	Cell* leftUp_;
	Cell* left_;
	Cell* leftDown_;
	Cell* rightUp_;
	Cell* right_;
	Cell* rightDown_;
	/*
	 * Ссылка на любую дичь, который находится на клетке
	 * nullptr, клетка пустая
	 */
	Unit* character_;
	/*
	 * Список всех эффектов, применённых к этой клетке
	 * Работа с этим списком в методах ниже
	 * Добавление, удаление, указатель на начало и конец
	 */
	std::vector<EffectsForCell*> effects_list_;
	/*
	 * isMoveAble - Можно ли попасть в данную клетку из точки пересчета
	 * переходя только по клеткам без юнитов
	 * isMeleeAttackAble - Можно ли атаковать данную клетку
	 * isRangeAttackAble_;
	 */
	bool isMoveAble_;
	bool isMeleeAttackAble_;
	bool isRangeAttackAble_;
	/*
	 * Расстояние от точки пересчёта до текущей точки
	 * distance_barrier - расстояние с учетом других препятствий
	 * distance_through - расстояние без учета препятствий
	 * -1, если недостижимо
	 */
	int distance_barrier_;
	int distance_through_;
private:
    /*
     * Локальные методы и переменные
     */
	bool AddedToQuery_;
	void clearTable_();
	void clearCell_();
	void recalcAttackable_();
	void recalcMoveable_();
	/*
	 * BFS Moveable Cells And Find Unmoveable Cells
	 */
	void updateMoveableCells_(std::queue<Cell *> &Q);
	/*
	 * BFS UnMoveable Cells
	 */
	void updateUnMovealeCells_(std::queue<Cell *> &Q);

public:

	explicit Cell(Unit * character);
	/*
	 * Геттеры и сеттеры соседних клеток и персонажа
	 */
	Cell* getleftUp();
	void setleftUp(Cell*);
	Cell* getleft();
	void setleft(Cell*);
	Cell* getleftDown();
	void setleftDown(Cell*);
	Cell* getrightUp();
	void setrightUp(Cell*);
	Cell* getright();
	void setright(Cell*);
	Cell* getrightDown();
	void setrightDown(Cell *);
	Unit* getCharacter();
	void setCharacter(Unit *);
	/*
	 * Ещё геттеры и сеттеры
	 */
    int getdistance_barrier();
    void setdistance_barrier(int);
    int getdistance_through();
    void setdistance_through(int);
    /*
     * Нужно больше геттеров и сеттеров
     */
    bool getisMoveAble();
	void setisMoveAble(bool);
	bool getisMeleeAttackAble();
	void setisMeleeAttackAble(bool);
	bool getisRangeAttackAble();
	void setisRangeAttackAble(bool);
	/*
	 * Содержит ли текущая клетка unit
	 */
	bool isEmpty();
	/*
	 * Методы для работы с эффектами
	 */
	void recalculateAllEffectsList();
	void add(EffectsForCell*);
	void remove(std::vector<EffectsForCell*>::iterator);
	void remove(EffectsForCell*);
	std::vector<EffectsForCell*>::iterator beginIteratorEffectsList();
	std::vector<EffectsForCell*>::iterator endIteratorEffectsList();
	/*
	 * Пересчитывает ВСЁ поле, делая текущую клетку - точкой пересчета
	 */
	void RecalculateTableWithCenterThisPoint();
	/*
	 * Работает корректно только в случае, если текущая - точка пересчета
	 * Возвращает список всех клеток от параметра до точки пересчета
	 * Включает в себя и начало, и конец
	 * При этом список составлен в порядке прохода, начиная с последнего
	 * Если пути нету, то вернется пустой список
	 */
	std::vector <Cell*> actualPath(Cell*);
};