# sage_setup: distribution = sagemath-categories
r"""
Rngs
"""
# ****************************************************************************
#  Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) <Teresa.Gomez-Diaz@univ-mlv.fr>
#                2012 Nicolas M. Thiery <nthiery at users.sf.net>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#                  https://www.gnu.org/licenses/
# *****************************************************************************

from sage.misc.cachefunc import cached_method
from sage.categories.category_with_axiom import CategoryWithAxiom
from sage.misc.lazy_import import LazyImport
from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas


class Rngs(CategoryWithAxiom):
    """
    The category of rngs.

    An *rng* `(S, +, *)` is similar to a ring but not necessarily
    unital. In other words, it is a combination of a commutative
    additive group `(S, +)` and a multiplicative semigroup `(S, *)`,
    where `*` distributes over `+`.

    EXAMPLES::

        sage: C = Rngs(); C
        Category of rngs
        sage: sorted(C.super_categories(), key=str)
        [Category of associative additive commutative additive associative additive unital distributive magmas and additive magmas,
         Category of commutative additive groups]

        sage: sorted(C.axioms())
        ['AdditiveAssociative', 'AdditiveCommutative', 'AdditiveInverse',
         'AdditiveUnital', 'Associative', 'Distributive']

        sage: C is (CommutativeAdditiveGroups() & Semigroups()).Distributive()
        True
        sage: C.Unital()
        Category of rings

    TESTS::

        sage: TestSuite(C).run()
    """

    _base_category_class_and_axiom = (MagmasAndAdditiveMagmas.Distributive.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.Associative, "AdditiveInverse")

    Unital = LazyImport('sage.categories.rings', 'Rings', at_startup=True)

    class ParentMethods:

        @cached_method
        def ideal_monoid(self):
            """
            The monoid of the ideals of this ring.

            .. NOTE::

                The code is copied from the base class of rings.
                This is since there are rings that do not inherit
                from that class, such as matrix algebras.  See
                :issue:`7797`.

            EXAMPLES::

                sage: # needs sage.modules
                sage: MS = MatrixSpace(QQ, 2, 2)
                sage: isinstance(MS, Ring)
                False
                sage: MS in Rings()
                True
                sage: MS.ideal_monoid()
                Monoid of ideals of Full MatrixSpace of 2 by 2 dense matrices
                over Rational Field

            Note that the monoid is cached::

                sage: MS.ideal_monoid() is MS.ideal_monoid()                            # needs sage.modules
                True
            """
            try:
                from sage.rings.ideal_monoid import IdealMonoid
                return IdealMonoid(self)
            except TypeError:
                from sage.rings.noncommutative_ideals import IdealMonoid_nc
                return IdealMonoid_nc(self)

        def _ideal_class_(self, n=0):
            r"""
            Return a callable object that can be used to create ideals in this
            ring.

            The argument `n`, standing for the number of generators
            of the ideal, is ignored.

            EXAMPLES::

                sage: MS = MatrixSpace(QQ, 2, 2)                                        # needs sage.modules
                sage: MS._ideal_class_()                                                # needs sage.modules
                <class 'sage.rings.noncommutative_ideals.Ideal_nc'>

            Since :issue:`7797`, non-commutative rings have ideals as well::

                sage: A = SteenrodAlgebra(2)                                                # needs sage.combinat sage.modules
                sage: A._ideal_class_()                                                     # needs sage.combinat sage.modules
                <class 'sage.rings.noncommutative_ideals.Ideal_nc'>
            """
            from sage.rings.noncommutative_ideals import Ideal_nc
            return Ideal_nc

        def principal_ideal(self, gen, coerce=True):
            """
            Return the principal ideal generated by ``gen``.

            EXAMPLES::

                sage: R.<x,y> = ZZ[]
                sage: R.principal_ideal(x+2*y)
                Ideal (x + 2*y) of Multivariate Polynomial Ring in x, y over Integer Ring
            """
            C = self._ideal_class_(1)
            if coerce:
                gen = self(gen)
            return C(self, [gen])

        @cached_method
        def zero_ideal(self):
            """
            Return the zero ideal of this ring (cached).

            EXAMPLES::

                sage: ZZ.zero_ideal()
                Principal ideal (0) of Integer Ring
                sage: QQ.zero_ideal()
                Principal ideal (0) of Rational Field
                sage: QQ['x'].zero_ideal()
                Principal ideal (0) of Univariate Polynomial Ring in x over Rational Field

            The result is cached::

                sage: ZZ.zero_ideal() is ZZ.zero_ideal()
                True

            TESTS:

            Make sure that :issue:`13644` is fixed::

                sage: # needs sage.rings.padics
                sage: K = Qp(3)
                sage: R.<a> = K[]
                sage: L.<a> = K.extension(a^2-3)
                sage: L.ideal(a)
                Principal ideal (1 + O(a^40)) of 3-adic Eisenstein Extension Field in a defined by a^2 - 3
            """
            return self._ideal_class_(1)(self, [self.zero()])
