from copy import copy
import re
from typing import Dict, Set, Optional

from geniusweb.issuevalue.Bid import Bid
from geniusweb.issuevalue.ValueSet import ValueSet


class Domain:
	'''
	A domain description. 
	'''

	def __init__(self,  name:str,  issuesValues :Dict[str, ValueSet]) :
		'''
		@param name a short name for display/toString. This name must
		                 contain simple characters only (a-z, A-Z, 0-9).
	 	@param issuesValues    the issues and values, Map with key: the issue name and value:
	 	                 {@link ValueSet} with the allowed values for the issue.		'''
		if issuesValues == None:
			raise ValueError("issues=null")
		if name == None:
			raise ValueError("shortName=null")
		if not re.match("[a-zA-Z0-9]+", name):
			raise ValueError("domain name can have only simple characters but found "+ name)
		if len(issuesValues)==0:
			raise ValueError("issuesValues is empty set");

		self._name = name;
		self._issuesValues = dict(issuesValues) #'freeze'...
	


	def getName(self) ->str:
		'''
		@return short name for this domain.

		'''
		return self._name

	def getIssues(self) -> Set[str] :
		'''
		@return set of the issues in this domain.
		'''
		#workaround bug, issueValue
		return set(self._issuesValues.keys())
	
	def getIssuesValues(self):
		return copy(self._issuesValues)

	def isFitting(self,  bid:Bid) -> Optional[str]:
		'''
		@param bid the {@link Bid} to be checked
		@return None if bid is fitting, or a string containing a message
		        explaining why not. A bid is fitting if all issues are in the
		        domain and all issue values are known values.
		'''
		for issue in bid.getIssues(): 
			if not issue in self._issuesValues:
				return "bid " + str(bid) + " refers to non-domain issue '" + issue  + "'"
			if not bid.getValue(issue) in self._issuesValues[issue]:
				return "issue '" + issue + "' in bid has illegal value " + str(bid.getValue(issue))
		return None

	def isComplete(self,  bid:Bid) -> Optional[str] :
		'''
		@param bid a Bid
		@return null if this bid is complete, or an error message explaining why
		        the bid is not complete. Complete means that the bid contains a
		        valid value for each issue in the domain and no values for
		        unknown issues.
		'''
		if self._issuesValues.keys() != bid.getIssues(): 
			return "Issues in bid (" + str(bid.getIssues())  \
					+ ") do not match issues in domain ("  \
					+str(self._issuesValues.keys()) + ")"
		return self.isFitting(bid);

	def getValues( self, issue:str) ->ValueSet :
		'''
		@param issue the issue for which allowed values are needed
		@return set of allowed values for given issue, or null if there is no
		        such an issue.

		'''
		return self._issuesValues[issue]

	def __hash__(self):
		return hash((self._name, tuple(self._issuesValues.items())))

	def __eq__(self, other):
		return isinstance(other, self.__class__) \
			 and  self._issuesValues == other._issuesValues and self._name==other._name

	def __repr__(self):
		return "Domain["+self._name+","+repr(self._issuesValues)+"]"
from copy import copy
import re
from typing import Dict, Set, Optional

from geniusweb.issuevalue.Bid import Bid
from geniusweb.issuevalue.ValueSet import ValueSet


class Domain:
	'''
	A domain description. 
	'''

	def __init__(self,  name:str,  issuesValues :Dict[str, ValueSet]) :
		'''
		@param name a short name for display/toString. This name must
		                 contain simple characters only (a-z, A-Z, 0-9).
	 	@param issuesValues    the issues and values, Map with key: the issue name and value:
	 	                 {@link ValueSet} with the allowed values for the issue.		'''
		if issuesValues == None:
			raise ValueError("issues=null")
		if name == None:
			raise ValueError("shortName=null")
		if not re.match("[a-zA-Z0-9]+", name):
			raise ValueError("domain name can have only simple characters but found "+ name)
		if len(issuesValues)==0:
			raise ValueError("issuesValues is empty set");

		self._name = name;
		self._issuesValues = dict(issuesValues) #'freeze'...
	


	def getName(self) ->str:
		'''
		@return short name for this domain.

		'''
		return self._name

	def getIssues(self) -> Set[str] :
		'''
		@return set of the issues in this domain.
		'''
		#workaround bug, issueValue
		return set(self._issuesValues.keys())
	
	def getIssuesValues(self):
		return copy(self._issuesValues)

	def isFitting(self,  bid:Bid) -> Optional[str]:
		'''
		@param bid the {@link Bid} to be checked
		@return None if bid is fitting, or a string containing a message
		        explaining why not. A bid is fitting if all issues are in the
		        domain and all issue values are known values.
		'''
		for issue in bid.getIssues(): 
			if not issue in self._issuesValues:
				return "bid " + str(bid) + " refers to non-domain issue '" + issue  + "'"
			if not bid.getValue(issue) in self._issuesValues[issue]:
				return "issue '" + issue + "' in bid has illegal value " + str(bid.getValue(issue))
		return None

	def isComplete(self,  bid:Bid) -> Optional[str] :
		'''
		@param bid a Bid
		@return null if this bid is complete, or an error message explaining why
		        the bid is not complete. Complete means that the bid contains a
		        valid value for each issue in the domain and no values for
		        unknown issues.
		'''
		if self._issuesValues.keys() != bid.getIssues(): 
			return "Issues in bid (" + str(bid.getIssues())  \
					+ ") do not match issues in domain ("  \
					+str(self._issuesValues.keys()) + ")"
		return self.isFitting(bid);

	def getValues( self, issue:str) ->ValueSet :
		'''
		@param issue the issue for which allowed values are needed
		@return set of allowed values for given issue, or null if there is no
		        such an issue.

		'''
		return self._issuesValues[issue]

	def __hash__(self):
		return hash((self._name, tuple(self._issuesValues.items())))

	def __eq__(self, other):
		return isinstance(other, self.__class__) \
			 and  self._issuesValues == other._issuesValues and self._name==other._name

	def __repr__(self):
		return "Domain["+self._name+","+repr(self._issuesValues)+"]"
A domain description. @param name a short name for display/toString. This name must 		                 contain simple characters only (a-z, A-Z, 0-9). 	 	@param issuesValues    the issues and values, Map with key: the issue name and value: 	 	                 {@link ValueSet} with the allowed values for the issue. #'freeze'... @return short name for this domain. @return set of the issues in this domain. #workaround bug, issueValue @param bid the {@link Bid} to be checked 		@return None if bid is fitting, or a string containing a message 		        explaining why not. A bid is fitting if all issues are in the 		        domain and all issue values are known values. @param bid a Bid 		@return null if this bid is complete, or an error message explaining why 		        the bid is not complete. Complete means that the bid contains a 		        valid value for each issue in the domain and no values for 		        unknown issues. @param issue the issue for which allowed values are needed 		@return set of allowed values for given issue, or null if there is no 		        such an issue.