import itertools


def is_corpus(obj):
    """Check whether `obj` is a corpus, by peeking at its first element. Works even on streamed generators.
    The peeked element is put back into a object returned by this function, so always use
    that returned object instead of the original `obj`.

    Parameters
    ----------
    obj : object
        An `iterable of iterable` that contains (int, numeric).

    Returns
    -------
    (bool, object)
        Pair of (is `obj` a corpus, `obj` with peeked element restored)

    Examples
    --------
    .. sourcecode:: pycon

        >>> from gensim.utils import is_corpus
        >>> corpus = [[(1, 1.0)], [(2, -0.3), (3, 0.12)]]
        >>> corpus_or_not, corpus = is_corpus(corpus)

    Warnings
    --------
    An "empty" corpus (empty input sequence) is ambiguous, so in this case
    the result is forcefully defined as (False, `obj`).

    """
    try:
        if 'Corpus' in obj.__class__.__name__:  # the most common case, quick hack
            return True, obj
    except Exception:
        pass
    try:
        if hasattr(obj, 'next') or hasattr(obj, '__next__'):
            # the input is an iterator object, meaning once we call next()
            # that element could be gone forever. we must be careful to put
            # whatever we retrieve back again
            doc1 = next(obj)
            obj = itertools.chain([doc1], obj)
        else:
            doc1 = next(iter(obj))  # empty corpus is resolved to False here
        if len(doc1) == 0:  # sparse documents must have a __len__ function (list, tuple...)
            return True, obj  # the first document is empty=>assume this is a corpus

        # if obj is a 1D numpy array(scalars) instead of 2-tuples, it resolves to False here
        id1, val1 = next(iter(doc1))
        id1, val1 = int(id1), float(val1)  # must be a 2-tuple (integer, float)
    except Exception:
        return False, obj
    return True, obj