1 | from copy import copy
|
---|
2 | import re
|
---|
3 | from typing import Dict, Set, Optional
|
---|
4 |
|
---|
5 | from geniusweb.issuevalue.Bid import Bid
|
---|
6 | from geniusweb.issuevalue.ValueSet import ValueSet
|
---|
7 |
|
---|
8 |
|
---|
9 | class Domain:
|
---|
10 | '''
|
---|
11 | A domain description.
|
---|
12 | '''
|
---|
13 |
|
---|
14 | def __init__(self, name:str, issuesValues :Dict[str, ValueSet]) :
|
---|
15 | '''
|
---|
16 | @param name a short name for display/toString. This name must
|
---|
17 | contain simple characters only (a-z, A-Z, 0-9).
|
---|
18 | @param issuesValues the issues and values, Map with key: the issue name and value:
|
---|
19 | {@link ValueSet} with the allowed values for the issue. '''
|
---|
20 | if issuesValues == None:
|
---|
21 | raise ValueError("issues=null")
|
---|
22 | if name == None:
|
---|
23 | raise ValueError("shortName=null")
|
---|
24 | if not re.match("[a-zA-Z0-9]+", name):
|
---|
25 | raise ValueError("domain name can have only simple characters but found "+ name)
|
---|
26 | if len(issuesValues)==0:
|
---|
27 | raise ValueError("issuesValues is empty set");
|
---|
28 |
|
---|
29 | self._name = name;
|
---|
30 | self._issuesValues = dict(issuesValues) #'freeze'...
|
---|
31 |
|
---|
32 |
|
---|
33 |
|
---|
34 | def getName(self) ->str:
|
---|
35 | '''
|
---|
36 | @return short name for this domain.
|
---|
37 |
|
---|
38 | '''
|
---|
39 | return self._name
|
---|
40 |
|
---|
41 | def getIssues(self) -> Set[str] :
|
---|
42 | '''
|
---|
43 | @return set of the issues in this domain.
|
---|
44 | '''
|
---|
45 | #workaround bug, issueValue
|
---|
46 | return set(self._issuesValues.keys())
|
---|
47 |
|
---|
48 | def getIssuesValues(self):
|
---|
49 | return copy(self._issuesValues)
|
---|
50 |
|
---|
51 | def isFitting(self, bid:Bid) -> Optional[str]:
|
---|
52 | '''
|
---|
53 | @param bid the {@link Bid} to be checked
|
---|
54 | @return None if bid is fitting, or a string containing a message
|
---|
55 | explaining why not. A bid is fitting if all issues are in the
|
---|
56 | domain and all issue values are known values.
|
---|
57 | '''
|
---|
58 | for issue in bid.getIssues():
|
---|
59 | if not issue in self._issuesValues:
|
---|
60 | return "bid " + str(bid) + " refers to non-domain issue '" + issue + "'"
|
---|
61 | if not bid.getValue(issue) in self._issuesValues[issue]:
|
---|
62 | return "issue '" + issue + "' in bid has illegal value " + str(bid.getValue(issue))
|
---|
63 | return None
|
---|
64 |
|
---|
65 | def isComplete(self, bid:Bid) -> Optional[str] :
|
---|
66 | '''
|
---|
67 | @param bid a Bid
|
---|
68 | @return null if this bid is complete, or an error message explaining why
|
---|
69 | the bid is not complete. Complete means that the bid contains a
|
---|
70 | valid value for each issue in the domain and no values for
|
---|
71 | unknown issues.
|
---|
72 | '''
|
---|
73 | if self._issuesValues.keys() != bid.getIssues():
|
---|
74 | return "Issues in bid (" + str(bid.getIssues()) \
|
---|
75 | + ") do not match issues in domain (" \
|
---|
76 | +str(self._issuesValues.keys()) + ")"
|
---|
77 | return self.isFitting(bid);
|
---|
78 |
|
---|
79 | def getValues( self, issue:str) ->ValueSet :
|
---|
80 | '''
|
---|
81 | @param issue the issue for which allowed values are needed
|
---|
82 | @return set of allowed values for given issue, or null if there is no
|
---|
83 | such an issue.
|
---|
84 |
|
---|
85 | '''
|
---|
86 | return self._issuesValues[issue]
|
---|
87 |
|
---|
88 | def __hash__(self):
|
---|
89 | return hash((self._name, tuple(self._issuesValues.items())))
|
---|
90 |
|
---|
91 | def __eq__(self, other):
|
---|
92 | return isinstance(other, self.__class__) \
|
---|
93 | and self._issuesValues == other._issuesValues and self._name==other._name
|
---|
94 |
|
---|
95 | def __repr__(self):
|
---|
96 | return "Domain["+self._name+","+repr(self._issuesValues)+"]" |
---|