# -*- coding: utf-8 -*-
# Copyright 2018 Joshua Bronson. All Rights Reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


#==============================================================================
#                    * Welcome to the bidict source code *
#==============================================================================

# Doing a code review? You'll find a "Code review nav" comment like the one
# below at the top and bottom of the most important source files. This provides
# a suggested initial path through the source when reviewing.
#
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
# viewing an outdated version of the code. Please head to GitHub to review the
# latest version, which contains important improvements over older versions.
#
# Thank you for reading and for any feedback you provide.

#                             * Code review nav *
#==============================================================================
#← Prev: _orderedbase.py  Current: _frozenordered.py  Next: _orderedbidict.py →
#==============================================================================

"""Provides :class:`FrozenOrderedBidict`, an immutable, hashable, ordered bidict."""

from ._base import BidictBase
from ._frozenbidict import frozenbidict
from ._orderedbase import OrderedBidictBase
from .compat import DICTS_ORDERED, ItemsView, PY2, izip


# FrozenOrderedBidict intentionally does not subclass frozenbidict because it only complicates the
# inheritance hierarchy without providing any actual code reuse: The only thing from frozenbidict
# that FrozenOrderedBidict uses is frozenbidict.__hash__(), but Python specifically prevents
# __hash__ from being inherited; it must instead always be defined explicitly as below. Users who
# need an `is_frozenbidict(..)` test that succeeds for both frozenbidicts and FrozenOrderedBidicts
# should therefore not use isinstance(foo, frozenbidict), but should instead use the appropriate
# ABCs, e.g. `isinstance(foo, BidirectionalMapping) and not isinstance(foo, MutableMapping)`.
class FrozenOrderedBidict(OrderedBidictBase):
    """Hashable, immutable, ordered bidict type."""

    __slots__ = ()

    # frozenbidict.__hash__ can be resued for FrozenOrderedBidict:
    # FrozenOrderedBidict inherits BidictBase.__eq__ which is order-insensitive,
    # and frozenbidict.__hash__ is consistent with BidictBase.__eq__.
    __hash__ = frozenbidict.__hash__  # Must define __hash__ explicitly, Python prevents inheriting
    if PY2:
        # Must grab the __func__ attribute off the method in Python 2, or else get "TypeError:
        # unbound method __hash__() must be called with frozenbidict instance as first argument"
        __hash__ = __hash__.__func__


if DICTS_ORDERED:
    # If the Python implementation's dict type is ordered (e.g. PyPy or CPython >= 3.6), then
    # `FrozenOrderedBidict` can set `__delegate__` to `_fwdm`, allowing the more efficient
    # implementations of `keys` and `values`, rather than the less efficient implementations
    # inherited from `Mapping.keys` and `OrderedBidictBase.values`.
    # Both the `_fwdm` and `_invm` backing dicts will always be initialized with the provided
    # items in the correct order, and since `FrozenOrderedBidict` is immutable, their respective
    # orders can't get out of sync after a mutation, like they can with a mutable `OrderedBidict`.
    FrozenOrderedBidict.__delegate__ = property(lambda self: self._fwdm)  # noqa: E501; pylint: disable=protected-access

    # (`FrozenOrderedBidict` can't use the more efficient `_fwdm.items` and `_fwdm.viewitems`
    # implementations because the values in `_fwdm` are nodes.
    FrozenOrderedBidict.items = super(BidictBase, FrozenOrderedBidict).items
    FrozenOrderedBidict.viewitems = lambda s: ItemsView(s)  # pylint: disable=unnecessary-lambda

    if PY2:
        # We can do better than the `iteritems` implementation inherited from `Mapping`;
        # zipping together the keys from `_fwdm` and `_invm` runs faster (e.g. C speed on CPython).
        def iteritems(self):
            """An iterator over the contained items."""
            return izip(self._fwdm, self._invm)  # pylint: disable=protected-access

        FrozenOrderedBidict.iteritems = iteritems


#                             * Code review nav *
#==============================================================================
#← Prev: _orderedbase.py  Current: _frozenordered.py  Next: _orderedbidict.py →
#==============================================================================
