# Copyright (C) 2011 Vaadin Ltd.
# Copyright (C) 2011 Richard Lincoln
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Note: This is a modified file from Vaadin. For further information on
#       Vaadin please visit http://www.vaadin.com.

from datetime import datetime

try:
    from cStringIO import StringIO
except ImportError, e:
    from StringIO import StringIO

from muntjac.data.item import IItem
from muntjac.ui.table_field_factory import ITableFieldFactory
from muntjac.ui.form_field_factory import IFormFieldFactory


class DefaultFieldFactory(IFormFieldFactory, ITableFieldFactory):
    """This class contains a basic implementation for both
    L{IFormFieldFactory} and L{ITableFieldFactory}. The class is
    singleton, use L{get} method to get reference to the instance.

    There are also some static helper methods available for custom built
    field factories.
    """

    INSTANCE = None  # set below

    @classmethod
    def get(cls):
        """Singleton method to get an instance of DefaultFieldFactory.

        @return: an instance of DefaultFieldFactory
        """
        return cls.INSTANCE


    def createField(self, *args):
        nargs = len(args)
        if nargs == 3:
            item, propertyId, _ = args
            typ = item.getItemProperty(propertyId).getType()
            field = self.createFieldByPropertyType(typ)
            field.setCaption(self.createCaptionByPropertyId(propertyId))
            return field
        elif nargs == 4:
            container, itemId, propertyId, _ = args
            containerProperty = \
                    container.getContainerProperty(itemId, propertyId)
            typ = containerProperty.getType()
            field = self.createFieldByPropertyType(typ)
            field.setCaption(self.createCaptionByPropertyId(propertyId))
            return field
        else:
            raise ValueError, 'invalid number of arguments'


    @classmethod
    def createCaptionByPropertyId(cls, propertyId):
        """If name follows method naming conventions, convert the name to
        spaced upper case text. For example, convert "firstName" to
        "First Name"

        @return: the formatted caption string
        """
        name = str(propertyId)

        if len(name) > 0:
            if (name.find(' ') < 0
                    and name[0] == name[0].lower()
                    and name[0] != name[0].upper()):
                out = StringIO()
                out.write(name[0].upper())
                i = 1
                while i < len(name):
                    j = i
                    while j < len(name):
                        c = name[j]
                        if c.lower() != c and c.upper() == c:
                            break
                        j += 1

                    if j == len(name):
                        out.write(name[i:])
                    else:
                        out.write(name[i:j])
                        out.write(' ' + name[j])
                    i = j + 1
                name = out.getvalue()
                out.close()

        return name


    @classmethod
    def createFieldByPropertyType(cls, typ):
        """Creates fields based on the property type.

        The default field type is L{TextField}. Other field types
        generated by this method:

          - B{Boolean}: L{CheckBox}.
          - B{Date}: L{DateField}(resolution: day).
          - B{IItem}: L{Form}.
          - B{default field type}: L{TextField}.

        @param typ:
                   the type of the property
        @return: the most suitable generic L{Field} for given type
        """
        from muntjac.ui.date_field import DateField  # FIXME: circular import
        from muntjac.ui.text_field import TextField
        from muntjac.ui.check_box import CheckBox
        from muntjac.ui.form import Form

        # Null typed properties can not be edited
        if typ is None:
            return None

        # IItem field
        if issubclass(typ, IItem):
            return Form()

        # Date field
        if issubclass(typ, datetime):
            df = DateField()
            df.setResolution(DateField.RESOLUTION_DAY)
            return df

        # Boolean field
        if issubclass(typ, bool):
            return CheckBox()

        return TextField()

DefaultFieldFactory.INSTANCE = DefaultFieldFactory()
