# -*- coding: iso-8859-15 -*-


# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
#     Romain Chantereau <rchantereau@entrouvert.com>
#     Nicolas Clapiès <nclapies@easter-eggs.org>
#     Pierre-Antoine Dejace <padejace@entrouvert.be>
#     Thierry Dulieu <tdulieu@easter-eggs.com>
#     Florent Monnier <monnier@codelutin.com>
#     Cédric Musso <cmusso@easter-eggs.org>
#     Frédéric Péters <fpeters@entrouvert.be>
#     Benjamin Poussin <poussin@codelutin.com>
#     Emmanuel Raviart <eraviart@entrouvert.com>
#     Sébastien Régnier <regnier@codelutin.com>
#     Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
#     Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
#     Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
#     Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
#     Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


__doc__ = """Glasnost Web Kinds"""

__version__ = '$Revision$'[11:-2]


import re
import time
import types

import glasnost.common.context as context
import glasnost.common.faults as faults
import glasnost.common.tools_new as commonTools
from glasnost.common import translation

import glasnost.proxy.kinds as proxyKinds

import things
from tools import *
import WebAPI

## import connectors # Do not remove!
import functions # Do not remove!
import modes # Do not remove!
import properties # Do not remove!
import uploads # Do not remove!
import values # Do not remove!
import widgets # Do not remove!


register = things.register


class KindMixin(things.ThingMixin):
    hasToInitField = 1
    hasToInitField_kind_importExport = 'private'
    hasToInitField_kind_stateInEditMode = 'hidden'
    hasToInitField_kind_stateInViewMode = 'hidden'
    hasToInitField_kindName = 'Boolean'

    hasToMakeFieldFromValue = 1
    hasToMakeFieldFromValue_kind_importExport = 'private'
    hasToMakeFieldFromValue_kind_stateInEditMode = 'hidden'
    hasToMakeFieldFromValue_kind_stateInViewMode = 'hidden'
    hasToMakeFieldFromValue_kindName = 'Boolean'

    hasToRepairField = 1
    hasToRepairField_kind_importExport = 'private'
    hasToRepairField_kind_stateInEditMode = 'hidden'
    hasToRepairField_kind_stateInViewMode = 'hidden'
    hasToRepairField_kindName = 'Boolean'

    hasToSubmitField = 1
    hasToSubmitField_kind_importExport = 'private'
    hasToSubmitField_kind_stateInEditMode = 'hidden'
    hasToSubmitField_kind_stateInViewMode = 'hidden'
    hasToSubmitField_kindName = 'Boolean'

    preference = None
    preference_kind_importExport = 'private'
    preference_kind_stateInEditMode = 'hidden'
    preference_kind_stateInViewMode = 'hidden'
    preference_kindName = 'String'

##     def getHelpAlias(self, slot, fields):
##         return self.helpAlias

    def getModelValueAsString(self, value):
        if type(value) is types.StringType:
            return value
        return self.convertValueToOtherType(value, types.StringType)

    def getModelValueFromFields(self, slot, fields):
        widget = slot.getWidget()
        kind = slot.getKind()
        try:
            value = widget.submit(slot, fields)
            if type(value) != kind.pythonStorageType:
                value = kind.convertValueFromOtherType(value)
        except:
            value = self.defaultValue
        return value

    def getOrderedFieldSlotNames(self, fields, parentSlot = None):
        slotNames = things.ThingMixin.getOrderedFieldSlotNames(
                self, fields, parentSlot = parentSlot)
        # The field widgetName must be set before the field widget.
        slotNames += ['widgetName', 'widget']
        return slotNames

    def newModelWidget(self, slot):
        return commonTools.newThing('widget', self.widgetName)
        

class AbstractSequenceMixin(KindMixin):
    def canAddItem(self, slot, fields):
        return 1

    def getItemsCount(self, slot, fields):
        raise NotImplementedError

    def isLabelImportant(self, slot):
        raise NotImplementedError


class ChoiceMixin(KindMixin):
    def makeModelTitleFromValue(self, slot, fields, value):
        valueAsString = self.getModelValueAsString(value)
        if self.titles and self.titles.has_key(valueAsString):
            return _(self.titles[valueAsString])
        return None


class IdMixin(KindMixin):
    pass


class SequenceMixin(AbstractSequenceMixin):
##     item_widget = None
##     item_widget_kindName = 'Widget'

    def canAddItem(self, slot, fields):
        maxCount = self.getMaxCount(slot)
        if maxCount is None:
            return 1
        count = self.getItemsCount(slot, fields)
        return count < maxCount
    
    def getItemsCount(self, slot, fields):
        # is this really what we want ?
        minCount = self.getMinCount(slot)
        try:
            count = max(minCount, len(slot.getValue() or []))
        except ValueError:
            pass
        return count

    def isLabelImportant(self, slot):
        return 0

class StringMixin(KindMixin):
    pass

class ThingMixin(ChoiceMixin):
    def getCreatedModelSlotAndValue(self, slot):
        value = None
        if slot.hasValue():
            value = slot.getValue()
        return self.repairModelSlotAndValue(slot, value)
        
    def getModelValueFromFields(self, slot, fields):
        value = ChoiceMixin.getModelValueFromFields(self, slot, fields)
        if value is not None:
            value = value.getThingName()
        return value

    def makeModelTitleFromValue(self, slot, fields, value):
        object = slot.getObject()
        label = _(self.getLabels(slot)[self.getModelValueAsString(value)])
        return object.makeContentTitle(slot, label)

    def newModelWidget(self, slot):
        slot, value = self.getCreatedModelSlotAndValue(slot)
        return value.newWidget(parentSlot = slot)

    def repairModelSlotAndValue(self, slot, value):
        if value is None and self.valueThingName is not None:
            value = commonTools.newThing(
                    self.valueThingCategory, self.valueThingName)
            slot = slot.detach(value)
        return slot, value


class TimeMixin(KindMixin):
    pass

class TokenMixin(KindMixin):
    pass


class UsersSetMixin(SequenceMixin):
    pass


class BaseKind(KindMixin, proxyKinds.BaseKind):
    pass
register(BaseKind)


class AcceptedRoles(SequenceMixin, proxyKinds.AcceptedRoles):
    pass
register(AcceptedRoles)


class Alias(StringMixin, proxyKinds.Alias):
    pass
register(Alias)


class Any(KindMixin, proxyKinds.Any):
    pass
register(Any)


class ApplicationToken(TokenMixin, proxyKinds.ApplicationToken):
    pass
register(ApplicationToken)


## class ArgumentPins(SequenceMixin, proxyKinds.ArgumentPins):
##     pass
## register(ArgumentPins)


class AuthorsSet(UsersSetMixin, proxyKinds.AuthorsSet):
    pass
register(AuthorsSet)


class Boolean(KindMixin, proxyKinds.Boolean):
    def makeModelTitleFromValue(self, slot, fields, value):
        valueAsString = str(value)
        if self.titles and self.titles.has_key(valueAsString):
            return _(self.titles[valueAsString])
        return None
register(Boolean)


class Choice(ChoiceMixin, proxyKinds.Choice):
    def makeModelTitleFromValue(self, slot, fields, value):
        valueAsString = self.getModelValueAsString(value)
        if self.titles and self.titles.has_key(valueAsString):
            return _(self.titles[valueAsString])
        return None
register(Choice)


class Command(KindMixin, proxyKinds.Command):
    def submitField2(self, slot, fields, **keywords):
        error = 0
        errorFields = {}
        value = None
        buttonName = slot.getFieldName()
        if isButtonSelected(buttonName, fields):
            command = context.getVar('command')
            command.action = self.action
            command.nextModeName = self.nextModeName
            command.nextObjectId = self.nextObjectId
        return (error, errorFields, value)
register(Command)


class CreationTime(TimeMixin, proxyKinds.CreationTime):
    pass
register(CreationTime)


class Data(KindMixin, proxyKinds.Data):
    pass
register(Data)


class DispatcherId(KindMixin, proxyKinds.DispatcherId):
    pass
register(DispatcherId)


class Duration(KindMixin, proxyKinds.Duration):
    pass
register(Duration)


class Email(StringMixin, proxyKinds.Email):
    pass
register(Email)


class Fault(ThingMixin, proxyKinds.Fault):
    pass
register(Fault)


class Fields(KindMixin, proxyKinds.Fields):
    pass
register(Fields)


class FilePath(StringMixin, proxyKinds.FilePath):
    pass
register(FilePath)


class Fingerprint(StringMixin, proxyKinds.Fingerprint):
    pass
register(Fingerprint)


class Float(KindMixin, proxyKinds.Float):
    pass
register(Float)


class Id(IdMixin, proxyKinds.Id):
    def makeModelTitleFromValue(self, slot, fields, value):
        return X.objectHypertextLabel(value)
register(Id)


## class InputConnector(ThingMixin, proxyKinds.InputConnector):
##     pass
## register(InputConnector)


class Integer(KindMixin, proxyKinds.Integer):
    pass
register(Integer)


class IntegerChoice(ChoiceMixin, proxyKinds.IntegerChoice):
    pass
register(IntegerChoice)


class Kind(ThingMixin, proxyKinds.Kind):
    pass
register(Kind)


class KindName(ChoiceMixin, proxyKinds.KindName):
    kindSlotName = None
    kindSlotName_kind_isRequired = 1
    kindSlotName_kindName = 'SlotName'

    def __init__(self, **attributes):
        proxyKinds.KindName.__init__(self, **attributes)
        self.labels = {}
        for kindClass in commonTools.getAllThingClasses().values():
            if kindClass.thingCategory != 'kind':
                continue
            value = kindClass.getThingName.im_func(kindClass)
            self.labels[value] = kindClass.getThingPublicName.im_func(
                    kindClass)

    def makeModelTitleFromValue(self, slot, fields, value):
        object = slot.getObject()
        label = _(self.getLabels(slot)[self.getModelValueAsString(value)])
        return object.makeContentTitle(slot, label)
register(KindName)


class LanguageChoice(ChoiceMixin, proxyKinds.LanguageChoice):
    pass
register(LanguageChoice)


class Link(KindMixin, proxyKinds.Link):
    pass
register(Link)


class Mapping(KindMixin, proxyKinds.Mapping):
    fieldsCountMin = 1 # FIXME: To rename?
    fieldsCountMin_kindName = 'Integer'

    keyDefaultValues = None
    keyDefaultValues_kind_importExport = 'private'
    keyDefaultValues_kind_stateInEditMode = 'hidden'
    keyDefaultValues_kind_stateInViewMode = 'hidden'
    keyDefaultValues_kind_itemKind_value_kindName = 'String'
    keyDefaultValues_kind_label = N_('Default Values')
    keyDefaultValues_kindName = 'Sequence'

##     key_widget = None
##     key_widget_kindName = 'Widget'

##     value_widget = None
##     value_widget_kindName = 'Widget'

    def getItemsCount(self, slot, fields):
        count = self.fieldsCountMin
        try:
            count = max(count, int(slot.getFieldOption(
                fields, 'count', default = '0')))
        except ValueError:
            pass
        return count

    def canAddItem(self, slot, fields):
        return not self.keyKind.isExportable()
register(Mapping)


class Marks(KindMixin, proxyKinds.Marks):
    idsGetterName = None
    idsGetterName_kindName = 'String'
register(Marks)


class ApprovalMarks(Marks):
    defaultValue_kindName = 'ApprovalMarks'
register(ApprovalMarks)


class DistributionMarks(Marks):
    defaultValue_kindName = 'DistributionMarks'
register(DistributionMarks)


class RankingMarks(Marks):
    defaultValue_kindName = 'RankingMarks'
register(RankingMarks)


class RatingMarks(Marks):
    defaultValue_kindName = 'RatingMarks'
register(RatingMarks)


class Memory(KindMixin, proxyKinds.Memory):
    pass
register(Memory)


class Mode(ThingMixin, proxyKinds.Mode):
    pass
register(Mode)


class ModificationTime(TimeMixin, proxyKinds.ModificationTime):
    pass
register(ModificationTime)


## class OutputConnector(ThingMixin, proxyKinds.OutputConnector):
##     pass
## register(OutputConnector)


class PairwiseMatrix(KindMixin, proxyKinds.PairwiseMatrix):
    pass
register(PairwiseMatrix)


class Password(StringMixin, proxyKinds.Password):
    pass
register(Password)


class Path(StringMixin, proxyKinds.Path):
    pass
register(Path)


class Properties(SequenceMixin, proxyKinds.Properties):
    pass
register(Properties)


class PythonIdentifier(StringMixin, proxyKinds.PythonIdentifier):
    pass
register(PythonIdentifier)


class Rating(KindMixin, proxyKinds.Rating):
    pass
register(Rating)


class ReadersSet(UsersSetMixin, proxyKinds.ReadersSet):
    pass
register(ReadersSet)


## class ResultPins(SequenceMixin, proxyKinds.ResultPins):
##     pass
## register(ResultPins)


class Script(StringMixin, proxyKinds.Script):
    pass
register(Script)


class ScriptSourceCode(StringMixin, proxyKinds.ScriptSourceCode):
    pass
register(ScriptSourceCode)


class Sequence(SequenceMixin, proxyKinds.Sequence):
    pass
register(Sequence)


class ServerId(IdMixin, proxyKinds.ServerId):
    pass
register(ServerId)


class ServerRole(ChoiceMixin, proxyKinds.ServerRole):
    pass
register(ServerRole)


class SlotName(ChoiceMixin, proxyKinds.SlotName):
    pass
register(SlotName)


class String(StringMixin, proxyKinds.String):
    pass
register(String)


class Structure(AbstractSequenceMixin, proxyKinds.Structure):
    def canAddItem(self, slot, fields):
        return 0

    def getItemsCount(self, slot, fields):
        if self.parameters is None:
            return 0
        else:
            return len(self.parameters)

    def isLabelImportant(self, slot):
        return 1
register(Structure)


class Thing(ThingMixin, proxyKinds.Thing):
    pass
register(Thing)


class Time(TimeMixin, proxyKinds.Time):
    pass
register(Time)


class Token(TokenMixin, proxyKinds.Token):
    pass
register(Token)


class TranslationToAdd(KindMixin, proxyKinds.TranslationToAdd):
    # TODO: could this class be moved in web/TranslationsWeb.py ?
    pass
register(TranslationToAdd)


class TranslatorsSets(KindMixin, proxyKinds.TranslatorsSets):
    pass
register(TranslatorsSets)


class Union(KindMixin, proxyKinds.Union):
    pass
register(Union)


class Upload(ThingMixin, proxyKinds.Upload):
    pass
register(Upload)


class UploadFile(Data):
    defaultValue_kindName = 'UploadFile'
    thingPublicCategory = None # N_('Compound')
register(UploadFile)


class UsersSet(UsersSetMixin, proxyKinds.UsersSet):
    pass
register(UsersSet)


class UserToken(TokenMixin, proxyKinds.UserToken):
    pass
register(UserToken)


class ValueHolder(ThingMixin, proxyKinds.ValueHolder):
    pass
register(ValueHolder)


class Widget(ThingMixin, proxyKinds.Widget):
    pass
register(Widget)


class WidgetName(ChoiceMixin, proxyKinds.WidgetName):
    def __init__(self, **attributes):
        proxyKinds.WidgetName.__init__(self, **attributes)
        self.labels = {}
        for widgetClass in commonTools.getAllThingClasses().values():
            if widgetClass.thingCategory != 'widget':
                continue
            value = widgetClass.getThingName.im_func(widgetClass)
            self.labels[value] = widgetClass.getThingPublicName.im_func(
                    widgetClass)

    def makeModelTitleFromValue(self, slot, fields, value):
        object = slot.getObject()
        label = _(self.getLabels(slot)[self.getModelValueAsString(value)])
        return object.makeContentTitle(slot, label)
register(WidgetName)


class WritersSet(UsersSetMixin, proxyKinds.WritersSet):
    pass
register(WritersSet)


class XChoice(ChoiceMixin, proxyKinds.XChoice):
    otherFieldLabel = None
##     otherFieldLabel_kind_label = N_('Input Text Label')
    otherFieldLabel_kindName = 'String'

    def makeModelTitleFromValue(self, slot, fields, value):
        valueAsString = self.getModelValueAsString(value)
        if self.titles and self.titles.has_key(valueAsString):
            return _(self.titles[valueAsString])
        return valueAsString
register(XChoice)


