# Copyright (C) 2012 Vaadin Ltd. 
# Copyright (C) 2012 Richard Lincoln
# 
# Licensed under the Apache License, Version 2.0 (the "License"); 
# you may not use this file except in compliance with the License. 
# You may obtain a copy of the License at 
# 
#     http://www.apache.org/licenses/LICENSE-2.0 
# 
# Unless required by applicable law or agreed to in writing, software 
# distributed under the License is distributed on an "AS IS" BASIS, 
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
# See the License for the specific language governing permissions and 
# limitations under the License.

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()
