r"""
Lambda Bracket Algebras

AUTHORS:

- Reimundo Heluani (2019-10-05): Initial implementation.
"""

#******************************************************************************
#       Copyright (C) 2019 Reimundo Heluani <heluani@potuz.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#                  http://www.gnu.org/licenses/
#*****************************************************************************

from .category_types import Category_over_base_ring
from sage.misc.abstract_method import abstract_method
from sage.categories.modules import Modules
from sage.structure.element import coerce_binop
from sage.misc.cachefunc import cached_method
from sage.categories.commutative_rings import CommutativeRings
from sage.misc.lazy_import import LazyImport
_CommutativeRings = CommutativeRings()


class LambdaBracketAlgebras(Category_over_base_ring):
    r"""
    The category of Lambda bracket algebras.

    This is an abstract base category for Lie conformal algebras and
    super Lie conformal algebras.

    """
    @staticmethod
    def __classcall_private__(cls, R, check=True):
        r"""
        INPUT:

        - `R` -- a commutative ring
        - ``check`` -- a boolean (default: ``True``); whether to check
          that `R` is a commutative ring

        EXAMPLES::

            sage: LieConformalAlgebras(QuaternionAlgebra(2))
            Traceback (most recent call last):
            ValueError: base must be a commutative ring got Quaternion Algebra (-1, -1) with base ring Rational Field
            sage: LieConformalAlgebras(ZZ)
            Category of Lie conformal algebras over Integer Ring
        """
        if check:
            if not (R in _CommutativeRings):
                    raise ValueError("base must be a commutative ring got {}".format(R))
        return super(LambdaBracketAlgebras, cls).__classcall__(cls, R)

    @cached_method
    def super_categories(self):
        """
        The list of super categories of this category.

        EXAMPLES::

            sage: from sage.categories.lambda_bracket_algebras import LambdaBracketAlgebras
            sage: LambdaBracketAlgebras(QQ).super_categories()
            [Category of vector spaces over Rational Field]
        """
        return [Modules(self.base_ring())]

    def _repr_object_names(self):
        """
        The name of the objects of this category.

        EXAMPLES::

            sage: from sage.categories.lambda_bracket_algebras import LambdaBracketAlgebras
            sage: LambdaBracketAlgebras(QQ)
            Category of Lambda bracket algebras over Rational Field
        """
        return "Lambda bracket algebras over {}".format(self.base_ring())

    class SubcategoryMethods:

        def FinitelyGeneratedAsLambdaBracketAlgebra(self):
            """
            The category of finitely generated Lambda bracket algebras.

            EXAMPLES::

                sage: LieConformalAlgebras(QQ).FinitelyGenerated()
                Category of finitely generated lie conformal algebras over Rational Field
            """
            return self._with_axiom("FinitelyGeneratedAsLambdaBracketAlgebra")

        def FinitelyGenerated(self):
            """
            The category of finitely generated Lambda bracket algebras.

            EXAMPLES::

                sage: LieConformalAlgebras(QQ).FinitelyGenerated()
                Category of finitely generated lie conformal algebras over Rational Field
            """
            return self._with_axiom("FinitelyGeneratedAsLambdaBracketAlgebra")

    class ParentMethods:

        def ideal(self, *gens, **kwds):
            r"""
            The ideal of this Lambda bracket algebra generated by ``gens``.

            .. TODO::

                Ideals of Lie Conformal Algebras are not implemented yet.

            EXAMPLES::

                sage: Vir = lie_conformal_algebras.Virasoro(QQ)
                sage: Vir.ideal()
                Traceback (most recent call last):
                ...
                NotImplementedError: ideals of Lie Conformal algebras are not implemented yet
            """
            raise NotImplementedError("ideals of Lie Conformal algebras are "
                                      "not implemented yet")
    class ElementMethods:

        @coerce_binop
        def bracket(self, rhs):
            r"""
            The `\lambda`-bracket of these two elements.

            EXAMPLES:

            The brackets of the Virasoro Lie conformal algebra::

                sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0
                sage: L.bracket(L)
                {0: TL, 1: 2*L, 3: 1/2*C}
                sage: L.bracket(L.T())
                {0: 2*T^(2)L, 1: 3*TL, 2: 4*L, 4: 2*C}

            Now with a current algebra::

                sage: V = lie_conformal_algebras.Affine(QQ, 'A1')
                sage: V.gens()
                (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K'])
                sage: E = V.0; H = V.1; F = V.2;
                sage: H.bracket(H)
                {1: 2*B['K']}
                sage: E.bracket(F)
                {0: B[alphacheck[1]], 1: B['K']}
            """
            return self._bracket_(rhs)

        @abstract_method
        def _bracket_(self, rhs):
            r"""
            The `\lambda`-bracket of these two elements.

            .. NOTE::

                It is guaranteed that both are elements of the same
                parent.

            EXAMPLES:

            The brackets of the Virasoro Lie conformal Algebra::

                sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0
                sage: L._bracket_(L)
                {0: TL, 1: 2*L, 3: 1/2*C}
                sage: L._bracket_(L.T())
                {0: 2*T^(2)L, 1: 3*TL, 2: 4*L, 4: 2*C}

            Now with a current algebra::

                sage: V = lie_conformal_algebras.Affine(QQ, 'A1')
                sage: V.gens()
                (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K'])
                sage: E = V.0; H = V.1; F = V.2;
                sage: H._bracket_(H)
                {1: 2*B['K']}
                sage: E._bracket_(F)
                {0: B[alphacheck[1]], 1: B['K']}
            """

        @coerce_binop
        def nproduct(self, rhs, n):
            r"""
            The ``n``-th product of these two elements.

            EXAMPLES::

                sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0
                sage: L.nproduct(L, 3)
                1/2*C
                sage: L.nproduct(L.T(), 0)
                2*T^(2)L
                sage: V = lie_conformal_algebras.Affine(QQ, 'A1')
                sage: E = V.0; H = V.1; F = V.2;
                sage: E.nproduct(H, 0) == - 2*E
                True
                sage: E.nproduct(F, 1)
                B['K']
            """
            return self._nproduct_(rhs,n)

        def _nproduct_(self, rhs, n):
            r"""
            The ``n``-th product of these two elements.

            .. NOTE::

                It is guaranteed that both are elements of the same
                parent.

            EXAMPLES::

                sage: Vir = lie_conformal_algebras.Virasoro(QQ); L = Vir.0
                sage: L._nproduct_(L,3)
                1/2*C
                sage: L._nproduct_(L.T(),0)
                2*T^(2)L
                sage: V = lie_conformal_algebras.Affine(QQ, 'A1')
                sage: E = V.0; H = V.1; F = V.2;
                sage: E._nproduct_(H,0) == - 2*E
                True
                sage: E._nproduct_(F,1)
                B['K']
            """
            if n >= 0:
                return self.bracket(rhs).get(n,self.parent().zero())
            else:
                raise NotImplementedError("vertex algebras are not implemented")

        @abstract_method
        def T(self, n=1):
            r"""
            The ``n``-th derivative of ``self``.

            INPUT:

            - ``n`` -- integer (default:``1``); how many times
              to apply `T` to this element

            OUTPUT:

            `T^n a` where `a` is this element. Notice that we use the
            *divided powers* notation `T^{(j)} = \frac{T^j}{j!}`.

            EXAMPLES::

                sage: Vir = lie_conformal_algebras.Virasoro(QQ)
                sage: Vir.inject_variables()
                Defining L, C
                sage: L.T()
                TL
                sage: L.T(3)
                6*T^(3)L
                sage: C.T()
                0
            """

    WithBasis = LazyImport("sage.categories.lambda_bracket_algebras_with_basis",
                           "LambdaBracketAlgebrasWithBasis", "WithBasis")

    FinitelyGeneratedAsLambdaBracketAlgebra = LazyImport(
        'sage.categories.finitely_generated_lambda_bracket_algebras',
        'FinitelyGeneratedLambdaBracketAlgebras')
