"""
====
grid
====
"""

import numpy as np


class Grid:
    """Grid class to allow the Q-space grid to be defined in different
    ways. The grid can be defined be either specifying the corners of
    the volume or by the axis vectors.

    The grid is defined by three vectors **v1**, **v2** and **v3**;
    the range of these vectors **r1**, **r2** and **r3**; and the
    number of bin in each of these directions.

    :examples:

    Setting grid by defining corners

    >>> grid = Grid()
    >>> grid.set_corners(ll=[-2,-2,-3], lr=[2,2,-3], ul=[-2,-2,3])
    >>> grid.bins = 5, 3
    >>> grid.v1
    array([ 1.,  1.,  0.])
    >>> grid.v2
    array([ 0.,  0.,  1.])
    >>> grid.v3
    array([ 1., -1.,  0.])
    >>> grid.r1
    array([-2., -1.,  0.,  1.,  2.])
    >>> grid.r2
    array([-3.,  0.,  3.])
    >>> grid.r3
    array([ 0.])
    >>> print(grid)
    lower left  corner :     [-2. -2. -3.]
    lower right corner :     [ 2.  2. -3.]
    upper left  corner :     [-2. -2.  3.]
    top   left  corner :     [-2. -2. -3.]
    <BLANKLINE>
    hor. increment     :     [ 1.  1.  0.]
    vert. increment    :     [ 0.  0.  3.]
    top   increment    :     [ 1. -1.  0.]
    <BLANKLINE>
    # of points        :     5 x 3 x 1

    Setting grid by vectors and ranges

    >>> grid = Grid()
    >>> grid.v1 = [1, 1, 1]
    >>> grid.v2 = [2, -1, -1]
    >>> grid.v3 = [0, 1, -1]
    >>> grid.r1 = [-1, 1]
    >>> grid.r2 = [0, 2]
    >>> grid.r3 = [0, 2]
    >>> grid.bins = 3, 3, 3
    >>> print(grid)
    lower left  corner :     [-1 -1 -1]
    lower right corner :     [1 1 1]
    upper left  corner :     [ 3 -3 -3]
    top   left  corner :     [-1  1 -3]
    <BLANKLINE>
    hor. increment     :     [ 1.  1.  1.]
    vert. increment    :     [ 2. -1. -1.]
    top   increment    :     [ 0.  1. -1.]
    <BLANKLINE>
    # of points        :     3 x 3 x 3

    """
    def __init__(self):
        # vectors of grid
        self._v1 = np.array([1., 0., 0.])
        self._v2 = np.array([0., 1., 0.])
        self._v3 = np.array([0., 0., 1.])

        # min max of each vector
        self._r1 = np.array([0., 1.])
        self._r2 = np.array([0., 1.])
        self._r3 = np.array([0., 1.])

        # number of bins in each direction
        self.bins = (101, 101, 1)

        self.units = 'r.l.u'

    def __str__(self):
        return """lower left  corner :     {}
lower right corner :     {}
upper left  corner :     {}
top   left  corner :     {}

hor. increment     :     {}
vert. increment    :     {}
top   increment    :     {}

# of points        :     {} x {} x {}""".format(self.ll, self.lr, self.ul, self.tl,
                                                self.v1_delta, self.v2_delta, self.v3_delta,
                                                *self.bins)

    def set_corners(self,
                    ll=(0, 0, 0),
                    lr=None,
                    ul=None,