// GridFunction.hpp
//
//     Created on: 04. 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

#ifndef ALIB2_GRIDFUNCTION_HPP
#define ALIB2_GRIDFUNCTION_HPP

#include <alib/pair>
#include <alib/set>
#include <grid/common/GridDirection.hpp>

namespace grid {

class GridFunction {
// ---------------------------------------------------------------------------------------------------------------------
 public:

  template<typename TCoordinate>
  static
  grid::SquareGridDirections
  squareGridDirection(const ext::pair<TCoordinate, TCoordinate> &a,
                      const ext::pair<TCoordinate, TCoordinate> &b);

// ---------------------------------------------------------------------------------------------------------------------
  template<typename TCoordinate>
  static
  ext::pair<TCoordinate, TCoordinate>
  squareGridDirectionVector(grid::SquareGridDirections direction);

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

  static
  ext::set<grid::SquareGridDirections>
  squareGridDirectionDecompose(grid::SquareGridDirections direction);

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

  static
  bool
  sqaureGridDirectionIsDiagonal(grid::SquareGridDirections direction);

  static
  bool
  sqaureGridDirectionIsCardinal(grid::SquareGridDirections direction);

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

};

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

template<typename TCoordinate>
grid::SquareGridDirections
GridFunction::squareGridDirection(const ext::pair<TCoordinate, TCoordinate> &a,
                                  const ext::pair<TCoordinate, TCoordinate> &b) {
  using direction_type = grid::SquareGridDirections;

  TCoordinate x = b.first - a.first;
  TCoordinate y = b.second - a.second;

  if (x < 0 && y == 0) return direction_type::north;
  else if (x > 0 && y == 0) return direction_type::south;
  else if (x == 0 && y < 0) return direction_type::west;
  else if (x == 0 && y > 0) return direction_type::east;
  else if (x < 0 && y < 0) return direction_type::north_west;
  else if (x > 0 && y < 0) return direction_type::south_west;
  else if (x < 0 && y > 0) return direction_type::north_east;
  else if (x > 0 && y > 0) return direction_type::south_east;
  else return direction_type::none;
}

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

template<typename TCoordinate>
ext::pair<TCoordinate, TCoordinate>
GridFunction::squareGridDirectionVector(grid::SquareGridDirections direction) {
  using direction_type = grid::SquareGridDirections;
  using node_type = ext::pair<TCoordinate, TCoordinate>;

  switch (direction) {
    case direction_type::north: return node_type(-1, 0);
    case direction_type::south: return node_type(1, 0);
    case direction_type::west: return node_type(0, -1);
    case direction_type::east: return node_type(0, 1);
    case direction_type::north_west: return node_type(-1, -1);
    case direction_type::south_west: return node_type(1, -1);
    case direction_type::north_east: return node_type(-1, 1);
    case direction_type::south_east: return node_type(1, 1);
    default: return node_type(0, 0);
  }
}

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

} // namespace grid

#endif //ALIB2_GRIDFUNCTION_HPP
