#-------------------------------------------------------------------------
#
#  Copyright (c) 2007, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/LICENSE.txt and may be redistributed only
#  under the conditions described in the aforementioned license.  The license
#  is also available online at http://www.enthought.com/licenses/BSD.txt
#
#  Thanks for using Enthought open source!
#
#  Author: David C. Morrill
#  Date:   08/29/2007

#-------------------------------------------------------------------------

""" Defines an ArrayViewEditor for displaying 1-d or 2-d arrays of values.
"""

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

from __future__ import absolute_import

from traits.api import Instance, Property, List, Str, Bool, Font

from ..api import View, Item, TabularEditor, BasicEditorFactory

from ..tabular_adapter import TabularAdapter

from ..toolkit import toolkit_object

from ..ui_editor import UIEditor

#-- Tabular Adapter Definition -------------------------------------------


class ArrayViewAdapter(TabularAdapter):

    # Is the array 1D or 2D?
    is_2d = Bool(True)

    # Should array rows and columns be transposed:
    transpose = Bool(False)

    alignment = 'right'
    index_text = Property

    def _get_index_text(self):
        return str(self.row)

    def _get_content(self):
        if self.is_2d:
            return self.item[self.column_id]

        return self.item

    def get_item(self, object, trait, row):
        """ Returns the value of the *object.trait[row]* item.
        """
        if self.is_2d:
            if self.transpose:
                return getattr(object, trait)[:, row]

            return super(ArrayViewAdapter, self).get_item(object, trait,
                                                          row)

        return getattr(object, trait)[row]

    def len(self, object, trait):
        """ Returns the number of items in the specified *object.trait* list.
        """
        if self.transpose:
            return getattr(object, trait).shape[1]

        return super(ArrayViewAdapter, self).len(object, trait)

# Define the actual abstract Traits UI array view editor (each backend should
# implement its own editor that inherits from this class.


class _ArrayViewEditor(UIEditor):

    # Indicate that the editor is scrollable/resizable:
    scrollable = True

    # Should column titles be displayed:
    show_titles = Bool(False)

    # The tabular adapter being used for the editor view:
    adapter = Instance(ArrayViewAdapter)

    #-- Private Methods ------------------------------------------------------

    def _array_view(self):
        """ Return the view used by the editor.
        """
        return View(
            Item('object.object.' + self.name,
                 id='tabular_editor',
                 show_label=False,
                 editor=TabularEditor(show_titles=self.show_titles,
                                      editable=False,
                                      adapter=self.adapter)
                 ),
            id='array_view_editor',
            resizable=True
        )

    def init_ui(self, parent):
        """ Creates the Traits UI for displaying the array.
        """
        # Make sure that the value is an array of the correct shape:
        shape = self.value.shape
        len_shape = len(shape)
        if (len_shape == 0) or (len_shape > 2):
            raise ValueError("ArrayViewEditor can only display 1D or 2D "
                             "arrays")

        factory = self.factory
        cols = 1
        titles = factory.titles
        n = len(titles)
        self.show_titles = (n > 0)
        is_2d = (len_shape == 2)
        if is_2d:
            index = 1
            if factory.transpose:
                index = 0
            cols = shape[index]
            if self.show_titles:
                if n > cols:
                    titles = titles[:cols]
                elif n < cols:
                    if (cols % n) == 0:
                        titles, old_titles, i = [], titles, 0
                        while len(titles) < cols:
                            titles.extend('%s%d' % (title, i)
                                          for title in old_titles)
                            i += 1
                    else:
                        titles.extend([''] * (cols - n))
            else:
                titles = ['Data %d' % i for i in range(cols)]

        columns = [(title, i) for i, title in enumerate(titles)]

        if factory.show_index:
            columns.insert(0, ('Index', 'index'))

        self.adapter = ArrayViewAdapter(is_2d=is_2d,
                                        columns=columns,
                                        transpose=factory.transpose,
                                        format=factory.format,
                                        font=factory.font)

        return self.edit_traits(view='_array_view',
                                parent=parent,
                                kind='subpanel')

# Define the ArrayViewEditor class used by client code:


class ArrayViewEditor(BasicEditorFactory):

    # The editor implementation class:
    klass = Property

    # Should an index column be displayed:
    show_index = Bool(True)

    # List of (optional) column titles:
    titles = List(Str)

    # Should the array be logically transposed:
    transpose = Bool(False)

    # The format used to display each array element:
    format = Str('%s')

    # The font to use for displaying each array element:
    font = Font('Courier 10')

    def _get_klass(self):
        """ The class used to construct editor objects.
        """
        return toolkit_object('array_view_editor:_ArrayViewEditor')
