import algos
from exceptions import AlgorithmNotImplemented, ParameterNotImplemented, ParameterNotUnderstood, RouteMissingError
class HeaderBase(object):
    def __init__(self, name, value, data):
        self.name = name
        self.value = self.clean(value)
        self.data = data
    def sign(self): return self.value
    def verify(self): return self.value
    def clean(self, value): return value

class GenericString(HeaderBase):
    def clean(self, value):
        return str(value)

class SignNotImplemented(HeaderBase):
    def sign(self):
        raise ParameterNotImplemented("Header Parameter %s not implemented in the context of signing" % self.name)

class VerifyNotImplemented(HeaderBase):
    def verify(self):
        raise ParameterNotImplemented("Header Parameter %s not implemented in the context of verifying" % self.name)

class NotImplemented(HeaderBase):
    def clean(self, *a):
        raise ParameterNotUnderstood("Could not find an action for Header Parameter '%s'" % self.name)

class Algorithm(HeaderBase):
    def clean(self, value):
        try:
            self.methods = algos.route(value)
        except RouteMissingError, e:
            raise AlgorithmNotImplemented('"%s" not implemented.' % value)
    
    def sign(self):
        self.data['signer'] = self.methods['sign']
    def verify(self):
        self.data['verifier'] = self.methods['verify']

KNOWN_HEADERS = {
    # REQUIRED, signing algo, see signing_methods
    'alg': Algorithm,
    # OPTIONAL, type of signed content         
    'typ': GenericString,
    # OPTIONAL, JSON Key URL. See http://self-issued.info/docs/draft-jones-json-web-key.html
    'jku': VerifyNotImplemented,
     # OPTIONAL, key id, hint for which key to use.    
    'kid': VerifyNotImplemented,
    # OPTIONAL, x.509 URL pointing to certificate or certificate chain
    'x5u': VerifyNotImplemented,
    # OPTIONAL, x.509 certificate thumbprint    
    'x5t': VerifyNotImplemented,
}

# data is by reference
def process(data, step):
    for param in data['header']:
        # The JWS Header Input MUST be validated to only include parameters
        # and values whose syntax and semantics are both understood and
        # supported. --- this is why it defaults to NotImplemented, which
        # raises an exception
        cls = KNOWN_HEADERS.get(param, NotImplemented)
        instance = cls(param, data['header'][param], data)
        procedure = getattr(instance, step)
        procedure()
    return data
