from sympy.core import Dict, Tuple
from sympy.sets import Set
from .cartan_type import Standard_Cartan
from sympy.matrices import eye

class TypeD(Standard_Cartan):

    def __new__(cls, n):
        if n < 3:
            raise ValueError("n cannot be less than 3")
        return Standard_Cartan.__new__(cls, "D", n)


    def dimension(self):
        """
        Return the dimension of the vector space
        V underlying the Lie algebra
        Example
        ========
        >>> from sympy.liealgebras.cartan_type import CartanType
        >>> c = CartanType("D4")
        >>> c.dimension()
        4
        """

        return self.n

    def basic_root(self, i, j):
        """
        This is a method just to generate roots
        with a 1 iin the ith position and a -1
        in the jth postion.

        """

        n = self.n
        root = [0]*n
        root[i] = 1
        root[j] = -1
        return root

    def simple_root(self, i):
        """
        Every lie algebra has a unique root system.
        Given a root system Q, there is a subset of the
        roots such that an element of Q is called a
        simple root if it cannot be written as the sum
        of two elements in Q.  If we let D denote the
        set of simple roots, then it is clear that every
        element of Q can be written as a linear combination
        of elements of D with all coefficients non-negative.

        In D_n, the first n-1 simple roots are the same as
        the roots in A_(n-1) (a 1 in the ith position, a -1
        in the (i+1)th position, and zeroes elsewhere).
        The nth simple root is the root in which there 1s in
        the nth and (n-1)th positions, and zeroes elsewhere.

        This method returns the ith simple root for the D series.

        Example
        ========
        >>> from sympy.liealgebras.cartan_type import CartanType
        >>> c = CartanType("D4")
        >>> c.simple_root(2)
        [0, 1, -1, 0]

        """

        n = self.n
        if i < n:
            return self.basic_root(i-1, i)
        else:
            root = [0]*n
            root[n-2] = 1
            root[n-1] = 1
            return root


    def positive_roots(self):
        """
        This method generates all the positive roots of
        A_n.  This is half of all of the roots of D_n
        by multiplying all the positive roots by -1 we
        get the negative roots.

        Example
        ======
        >>> from sympy.liealgebras.cartan_type import CartanType
        >>> c = CartanType("A3")
        >>> c.positive_roots()
        {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0],
                5: [0, 1, 0, -1], 6: [0, 0, 1, -1]}
        """

        n = self.n
        posroots = {}
        k = 0
        for i in range(0, n-1):
            for j in range(i+1, n):
               k += 1
               posroots[k] = self.basic_root(i, j)
               k += 1
               root = self.basic_root(i, j)
               root[j] = 1
               posroots[k] = root
        return posroots

    def roots(self):
        """
        Returns the total number of roots for D_n"
        """

        n = self.n
        return 2*n*(n-1)

    def cartan_matrix(self):
        """
        Returns the Cartan matrix for D_n.
        The Cartan matrix matrix for a Lie algebra is
        generated by assigning an ordering to the simple
        roots, (alpha[1], ...., alpha[l]).  Then the ijth
        entry of the Cartan matrix is (<alpha[i],alpha[j]>).

        Example
        =======
        >>> from sympy.liealgebras.cartan_type import CartanType
        >>> c = CartanType('D4')
        >>> c.cartan_matrix()
            Matrix([
            [ 2, -1,  0,  0],
            [-1,  2, -1, -1],
            [ 0, -1,  2,  0],
            [ 0, -1,  0,  2]])

        """

        n = self.n
        m = 2*eye(n)
        i = 1
        while i < n-2:
           m[i,i+1] = -1
           m[i,i-1] = -1
           i += 1
        m[n-2, n-3] = -1
        m[n-3, n-1] = -1
        m[n-1, n-3] = -1
        m[0, 1] = -1
        return m

    def basis(self):
        """
        Returns the number of independent generators of D_n
        """
        n = self.n
        return n*(n-1)/2

    def lie_algebra(self):
        """
        Returns the Lie algebra associated with D_n"
        """

        n = self.n
        return "so(" + str(2*n) + ")"

    def dynkin_diagram(self):
        n = self.n
        diag = " "*4*(n-3) + str(n-1) + "\n"
        diag += " "*4*(n-3) + "0\n"
        diag += " "*4*(n-3) +"|\n"
        diag += " "*4*(n-3) + "|\n"
        diag += "---".join("0" for i in range(1,n)) + "\n"
        diag += "   ".join(str(i) for i in range(1, n-1)) + "   "+str(n)
        return diag
