// SquareGrid4.hpp
//
//     Created on: 31. 01. 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 <alib/pair>
#include <alib/tuple>

#include "SquareGrid.hpp"

namespace grid {

template<typename TCoordinate, typename TEdge>
class SquareGrid4 final : public SquareGrid<TCoordinate, TEdge> {
// ---------------------------------------------------------------------------------------------------------------------

 public:
  using coordinate_type = TCoordinate;
  using edge_type = TEdge;
  using node_type = ext::pair<TCoordinate, TCoordinate>;
  using direction_type = SquareGridDirections;

// =====================================================================================================================
// Constructor, Destructor, Operators
 public:
  explicit SquareGrid4(TCoordinate height, TCoordinate width);

// =====================================================================================================================
// GridBase interface
 public:
	auto operator <=> (const SquareGrid4 &other) const {
		return ext::tie(this->m_obstacles, this->m_height, this->m_width) <=> ext::tie(other.getObstacleList(), other.getHeight(), other.getWidth());
	}

	bool operator == (const SquareGrid4 &other) const {
		return ext::tie(this->m_obstacles, this->m_height, this->m_width) == ext::tie(other.getObstacleList(), other.getHeight(), other.getWidth());
	}

// =====================================================================================================================
// GridInterface interface

 public:

  bool isValidDirection(direction_type direction) const override;

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

 protected:
  TEdge createEdge(const node_type &a, const node_type &b) const override;

// ---------------------------------------------------------------------------------------------------------------------
// =====================================================================================================================
// GraphInterface interface

 public:

  std::string name() const override;

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

};

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

template<typename TCoordinate, typename TEdge>
SquareGrid4<TCoordinate, TEdge>::SquareGrid4(TCoordinate height, TCoordinate width)
    : SquareGrid<TCoordinate, TEdge>(height, width) {
}

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

template<typename TCoordinate, typename TEdge>
bool SquareGrid4<TCoordinate, TEdge>::isValidDirection(SquareGrid4::direction_type direction) const {
  switch (direction) {
    case SquareGridDirections::north : return true;
    case SquareGridDirections::south : return true;
    case SquareGridDirections::east : return true;
    case SquareGridDirections::west : return true;
    default: return false;
  }
}

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

template<typename TCoordinate, typename TEdge>
TEdge SquareGrid4<TCoordinate, TEdge>::createEdge(const SquareGrid4::node_type &a,
                                                  const SquareGrid4::node_type &b) const {
  return TEdge(a, b);
}

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

template<typename TCoordinate, typename TEdge>
std::string SquareGrid4<TCoordinate, TEdge>::name() const {
  return "SquareGrid4";
}

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

} // namespace grid

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

namespace core {

/**
 * Helper for normalisation of types specified by templates used as internal datatypes of symbols and states.
 *
 * \returns new instance of the graph with default template parameters or unmodified instance if the template parameters were already the default ones
 */

template<typename TCoordinate, typename TEdge>
struct normalize < grid::SquareGrid4 < TCoordinate, TEdge > > {
  static grid::SquareGrid4<> eval(grid::SquareGrid4<TCoordinate, TEdge> &&value) {
    grid::SquareGrid4<> grid(value.getHeight(), value.getWidth());

    // Copy obstacles
    for (auto &&i: ext::make_mover(std::move(value).getObstacleList())) {
      DefaultSquareGridNodeType
          obstacle = graph::GraphNormalize::normalizeObstacle(std::move(i));

      grid.addObstacle(std::move(obstacle));
    }

    return grid;
  }
};

} // namespace grid

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

