from math import fabs

"""Kept these functions outside the class, since they are static
   for the search and movement functions for board. The downside is it creates
   an object for search purposes, which seems relatively heavy. I'll
   optimize later if necessary
"""


def shift_up(pos):
    """returns new position that has shifted up"""
    return Position(pos.x, pos.y + 1)


def shift_down(pos):
    """returns new position that has shifted down"""
    return Position(pos.x, pos.y - 1)


def shift_right(pos):
    """returns new position that has shifted right"""
    return Position(pos.x + 1, pos.y)


def shift_left(pos):
    """returns new position that has shifted left"""
    return Position(pos.x - 1, pos.y)


def shift_up_left(pos):
    """returns new position that has shifted up"""
    return Position(pos.x + 1, pos.y - 1)


def shift_down_left(pos):
    """returns new position that has shifted down"""
    return Position(pos.x - 1, pos.y - 1)


def shift_up_right(pos):
    """returns new position that has shifted right"""
    return Position(pos.x + 1, pos.y + 1)


def shift_down_right(pos):
    """returns new position that has shifted left"""
    return Position(pos.x - 1, pos.y + 1)


class Position(object):

    def __init__(self, x, y):
        self._x, self._y = x, y

    # TODO: test the speed of this implementation
    # def __cmp__(self, other):
    #     if (self.width != other.width):
    #     return cmp(self.width, other.width)
    # return cmp(self.height, other.height)

    def __eq__(self, pos):
        return self._x == pos.x and self._y == pos.y

    def __ne__(self, pos):
        return self._x != pos.x or self._y != pos.y

    def __hash__(self):
        return hash(('x', self._x, 'y', self._y))

    def __repr__(self):
        return '({0},{1})'.format(self._x, self._y)

    def __str__(self):
        return '({0},{1})'.format(self._x, self._y)


    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    # ############################### Discovery ###############################

    def is_diagonal(self, pos):
        """Verify if points are diagonal"""
        return fabs(self.x - pos.x) == fabs(self.y - pos.y)

    def is_parallel(self, pos):
        """Verify if points are parallel"""
        return self.x == pos.x or self.y == pos.y

    def is_adj(self, pos):
        """Verify if points are adjacent.
        checks parallel on x plane if y +/- 1 is adj
        checks parallel on y plane if x +/- 1 is adj
        check if diagonal and if only 1 square away on the x plane
        check if diagonal and if only 1 square away on the y plane
        """
        return ((self.x == pos.x and fabs(self.y - pos.y)) == 1) \
            or ((self.y == pos.y and fabs(self.x - pos.x)) == 1) \
            or ((self.is_diagonal(pos) and fabs(self.y - pos.y)) == 1) \
            or ((self.is_diagonal(pos) and fabs(self.x - pos.x)) == 1)

    def to_json(self):
        return {'x': self.x, 'y': self.y}
    # ##################### Accessors/Modifiers ###############################