1# Copyright (c) 2004 Divmod.
2# See LICENSE for details.
3
4from __future__ import generators
5
6from zope.interface import implements
7
8from twisted.python import components
9
10from nevow import inevow
11from nevow import tags
12
13from formless import iformless
14
15
16try:
17    enumerate = enumerate
18except:
19    def enumerate(collection):
20        i = 0
21        it = iter(collection)
22        while 1:
23            yield (i, it.next())
24            i += 1
25
26
27class PrefixerDict(dict):
28    def __init__(self, prefix, errors):
29        if prefix is None: prefix = ''
30        self.prefix = prefix
31        self.errors = errors
32        dict.__init__(self)
33
34    def __setitem__(self, key, value):
35        if key is None:
36            key = ''
37        if key == '':
38            pfxkey = self.prefix
39        else:
40            pfxkey = '.'.join((self.prefix, key))
41        self.errors[pfxkey] = value
42
43    def __getitem__(self, key):
44        if key == '':
45            pfxkey = self.prefix
46        else:
47            pfxkey = '.'.join((self.prefix, key))
48        return self.errors[pfxkey]
49
50    def update(self, other):
51        for key, value in other.items():
52            self[key] = value
53
54
55class FormDefaults(components.Adapter):
56    def __init__(self):
57        self.defaults = {}
58
59    def setDefault(self, key, value, context=None):
60        self.defaults[key] = value
61
62    def getDefault(self, key, context=None):
63        #print "getting default for key", key, self.defaults
64        # 1) Check on the request
65        current = self.defaults.get(key, None)
66        if current is None:
67            # 2) Check on the session
68            if context is not None:
69                sessionDefaults = context.locate(iformless.IFormDefaults)
70                if sessionDefaults is not self:
71                    current = sessionDefaults.getDefault(key)
72                    if current is not None:
73                        return current
74                # 3) Ask the Binding instance for the default values
75                try:
76                    configurable = context.locate(iformless.IConfigurable)
77                except KeyError:
78                    return ''
79                return configurable.getDefault(context.locate(inevow.IData))
80        return current
81
82    def getAllDefaults(self, key):
83        return PrefixerDict(key, self.defaults)
84
85    def clearAll(self):
86        self.defaults = {}
87
88
89class FormErrors(components.Adapter):
90    """An object which keeps track of which forms have which errors
91    """
92    implements(iformless.IFormErrors)
93    def __init__(self):
94        self.errors = {}
95
96    def setError(self, errorKey, error):
97        self.errors[errorKey] = error
98
99    def getError(self, errorKey):
100        #print "get error", errorKey, self.__dict__
101        return self.errors.get(errorKey)
102
103    def getAllErrors(self, formName):
104        return PrefixerDict(formName, self.errors)
105
106    def updateErrors(self, formName, errors):
107        PrefixerDict(formName, self.errors).update(errors)
108
109    def clearErrors(self, formName):
110        for key in self.errors.keys():
111            if key.startswith(formName):
112                del self.errors[key]
113
114    def clearAll(self):
115        self.errors = {}
116
117def calculatePostURL(context, data):
118    postLocation = inevow.ICurrentSegments(context)[-1]
119    if postLocation == '':
120        postLocation = '.'
121    try:
122        configurableKey = context.locate(iformless.IConfigurableKey)
123    except KeyError:
124        #print "IConfigurableKey was not remembered when calculating full binding name for %s in node %s" % (configurable, context.key)
125        configurableKey = ''
126    bindingName = context.key
127    return "%s/freeform_post!%s!%s" % (postLocation, configurableKey, bindingName)
128
129
130def keyToXMLID(key):
131    """Convert a key into an XML-styleinevow.ID """
132    if not key:
133        #print 'keyToXMLID: no key, but why?'
134        return '***Error: Unset***'
135    return '-'.join(key.split('.'))
136
137
138def getError(context):
139    errors = context.locate(iformless.IFormErrors)
140    err = errors.getError(context.key)
141    if err is not None:
142        return err
143    return tags.comment["\nNo error for error key: %s\n" % context.key]
144