# encoding: utf-8

""" Manage the input and output history of the interpreter and the
frontend.

There are 2 different history objects, one that lives in the interpreter,
and one that lives in the frontend. They are synced with a diff at each
execution of a command, as the interpreter history is a real stack, its
existing entries are not mutable.
"""

__docformat__ = "restructuredtext en"

#-------------------------------------------------------------------------------
#  Copyright (C) 2008  The IPython Development Team
#
#  Distributed under the terms of the BSD License.  The full license is in
#  the file COPYING, distributed as part of this software.
#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------
# Imports
#-------------------------------------------------------------------------------

from copy import copy

# Local imports.
from util import InputList


##############################################################################
class History(object):
    """ An object managing the input and output history.
    """

    def __init__(self, input_cache=None, output_cache=None):

        # Stuff that IPython adds to the namespace.
        self.namespace_additions = dict(
            _ = None,
            __ = None,
            ___ = None,
        )

        # A list to store input commands.
        if input_cache is None:
            input_cache =InputList([])
        self.input_cache = input_cache

        # A dictionary to store trapped output.
        if output_cache is None:
            output_cache = {}
        self.output_cache = output_cache

    def get_history_item(self, index):
        """ Returns the history string at index, where index is the
        distance from the end (positive). 
        """
        if index>=0 and index<len(self.input_cache):
            return self.input_cache[index]


##############################################################################
class InterpreterHistory(History):
    """ An object managing the input and output history at the interpreter
    level.
    """

    def setup_namespace(self, namespace):
        """ Add the input and output caches into the interpreter's namespace
        with IPython-conventional names.

        Parameters
        ----------
        namespace : dict
        """

        namespace['In'] = self.input_cache
        namespace['_ih'] = self.input_cache
        namespace['Out'] = self.output_cache
        namespace['_oh'] = self.output_cache

    def update_history(self, interpreter, python):
        """ Update the history objects that this object maintains and the
        interpreter's namespace.

        Parameters
        ----------
        interpreter : Interpreter
        python : str
            The real Python code that was translated and actually executed.
        """

        number = interpreter.current_cell_number

        new_obj = interpreter.display_trap.obj
        if new_obj is not None:
            self.namespace_additions['___'] = self.namespace_additions['__']
            self.namespace_additions['__'] = self.namespace_additions['_']
            self.namespace_additions['_'] = new_obj
            self.output_cache[number] = new_obj

        interpreter.user_ns.update(self.namespace_additions)
        self.input_cache.add(number, python)


    def get_history_item(self, index):
        """ Returns the history string at index, where index is the
        distance from the end (positive). 
        """
        if index>0 and index<(len(self.input_cache)-1):
            return self.input_cache[-index]

    def get_input_cache(self):
        return copy(self.input_cache)

    def get_input_after(self, index):
        """ Returns the list of the commands entered after index.
        """
        # We need to call directly list.__getslice__, because this object
        # is not a real list.
        return list.__getslice__(self.input_cache, index,
                                                len(self.input_cache))


##############################################################################
class FrontEndHistory(History):
    """ An object managing the input and output history at the frontend.
        It is used as a local cache to reduce network latency problems
        and multiple users editing the same thing.
    """

    def add_items(self, item_list):
        """ Adds the given command list to the stack of executed
            commands.
        """
        self.input_cache.extend(item_list)