"""
x500.py - X.500 objects
(c) by Michael Stroeder <michael@stroeder.com>

This module is distributed under the terms of the
GPL (GNU GENERAL PUBLIC LICENSE) Version 2
(see http://www.gnu.org/copyleft/gpl.html)
"""

# Python standard lib
import sys, string
# Pisces
from pisces import asn1
# mspki itself
import utctime, asn1helper

string_classes = {
  asn1.PRINTABLE_STRING:'ascii',
  asn1.T61STRING:'iso-8859-1',
  asn1.IA5STRING:'ascii',
  asn1.UTF8STRING:'utf-8',
}

class AttributeTypeAndValue(asn1.Sequence):
  """
  Class for X.500 attributetype / value pairs

  AttributeTypeAndValue ::= SEQUENCE {
    type     AttributeType,
    value    AttributeValue }

  AttributeType ::= OBJECT IDENTIFIER

  AttributeValue ::= ANY DEFINED BY AttributeType
  """
  def __init__(self,val):
    asn1.Sequence.__init__(self,val)

  def __repr__(self):
    return '%s: %s' % (str(self.val[0]),str(self.val[1]))

  def __html__(self):
    return repr(self)

class RelativeDistinguishedName(asn1.Set):
  """
  Class for X.500 relative distinguished names

  RelativeDistinguishedName ::=
    SET OF AttributeTypeAndValue
  """

class Name(asn1.Sequence):
  """
  Class for X.500 distinguished names

  Name ::= CHOICE {
    RDNSequence }

  RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
  """

  def __init__(self,val):
    self.__name__ = map(lambda i: (i[0].val[0],unicode(i[0].val[1],'iso-8859-1')),val)

  def __descr__(self,oids=None,charset='utf-8'):
    """Distinguished Name object with OIDs replaced by descriptions"""
    return map(
      lambda i,d=oids,f=asn1helper.GetOIDDescription,c=charset: (f(i[0],d),i[1]),
      self.__name__
    )

  def __str__(self,oids=None,charset='utf-8'):
    """
    String representation of distinguished name for displaying
    
    This mimics the string output behaviour of OpenSSL.
    If parameter oids is set (dictionary returned by asn1.parseCfg()
    descriptions are used instead of OIDs.
    """
    if oids:
      rdnlist = self.__descr__(oids)
    else:
      rdnlist = self.__name__
    return string.join(
      map(
        lambda i,c=charset: '/%s=%s' % (i[0],i[1].encode(c)),
	rdnlist
      ),
      ''
    )

  def __repr__(self,oids=None):
    """
    See RFC2253: String representation of X.500 DNs
    
    If parameter oids is set (dictionary returned by asn1.parseCfg()
    descriptions are used instead of OIDs.
    """
    if oids:
      rdnlist = self.__descr__(oids)
    else:
      rdnlist = self.__name__
    rdnlist.reverse()
    return string.join(
      map(
        lambda i: '%s=%s' % (i[0],i[1].encode('utf-8')),
	rdnlist
      ),
      ','
    )

  def __html__(self,oids=None,charset='utf-8'):
    """
    HTML-formatted string representation of distinguished name.
    
    If parameter oids is set (dictionary returned by asn1.parseCfg()
    descriptions are used instead of OIDs.
    """
    if oids:
      rdnlist = self.__descr__(oids)
    else:
      rdnlist = self.__name__
    return '<dl>\n%s</dl>\n' % (
      string.join(
        map(
	  lambda i,c=charset: '<dt>%s</dt><dd>%s</dd>' % (
            i[0],
            i[1].encode(c)
          ),
	  rdnlist
	),
	'\n'
      )
    )

