#! /usr/bin/env python
"""This module implements the IMS LRM 1.2.1 specification defined by IMS GLC
"""

import pyslet.xmlnames20091208 as xmlns

try:
	import vobject
except ImportError:
	vobject=None

import itertools
	
IMSLRM_NAMESPACE="http://www.imsglobal.org/xsd/imsmd_v1p2"
IMSLRM_SCHEMALOCATION="http://www.imsglobal.org/xsd/imsmd_v1p2p4.xsd"

IMSLRM_NAMESPACE_ALIASES={
#	"http://www.imsproject.org/metadata":"1.1",
#	"http://www.imsproject.org/metadata/":"1.1",
	"http://www.imsproject.org/xsd/imsmd_rootv1p2":IMSLRM_NAMESPACE,
	"http://www.imsglobal.org/xsd/imsmd_rootv1p2p1":IMSLRM_NAMESPACE}

LOM_SOURCE="LOMv1.0"
LOM_UNKNOWNSOURCE="None"


class LRMException(Exception): pass

class LRMElement(xmlns.XMLNSElement):
	"""Basic element to represent all CP elements"""
	pass

class LangString(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'langstring')
	
	def __init__(self,parent,value=None):
		LRMElement.__init__(self,parent)
		if value is not None:
			self.SetValue(value)
		
class LangStringList(LRMElement):	
	LangStringClass=LangString
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LangString=[]

	def GetChildren(self):
		return iter(self.LangString)
	
	def GetLangString(self,lang=None):
		if lang is None:
			for s in self.LangString:
				if s.GetLang() is None:
					return s
			return None
		else:
			for s in self.LangString:
				if s.GetLang()==lang:
					return s
			lang=lang.split('-')[0]
			for s in self.LangString:
				sLang=s.GetLang().split('-')[0]
				if sLang==lang:
					return s
		return None

	def AddString(self,lang,value):
		s=self.GetLangString(lang)
		if s is None:
			s=self.ChildElement(self.LangStringClass)
			s.SetValue(value)
			if lang:
				s.SetLang(lang)
		else:
			s.AddData('; '+value)			
		return s

			
class LRMSource(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'source')

	LangStringClass=LangString
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LangString=self.LangStringClass(self)
	
	def GetChildren(self):
		yield self.LangString

		
class LRMValue(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'value')

	LangStringClass=LangString

	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LangString=self.LangStringClass(self)
	
	def GetChildren(self):
		yield self.LangString

	
class LRMSourceValue(LRMElement):
	LRMSourceClass=LRMSource
	LRMValueClass=LRMValue
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LRMSource=self.LRMSourceClass(self)
		self.LRMValue=self.LRMValueClass(self)
	
	def GetChildren(self):
		yield self.LRMSource
		yield self.LRMValue

		
class LOM(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'lom')
	XMLCONTENT=xmlns.ElementContent
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.general=None
		self.lifecycle=None
		self.metametadata=None
		self.technical=None
		self.educational=None
		self.rights=None
		self.relations=[]
		self.annotations=[]
		self.classifications=[]
	
	def GetChildren(self):
		if self.general: yield self.general
		if self.lifecycle: yield self.lifecycle
		if self.metametadata: yield self.metametadata
		if self.technical: yield self.technical
		if self.educational: yield self.educational
		if self.rights: yield self.rights
		for child in itertools.chain(
			self.relations,
			self.annotations,
			self.classifications,
			LRMElement.GetChildren(self)):
			yield child
		
	def LOMGeneral(self):
		if not self.general:
			self.general=LOMGeneral(self)
		return self.general
	
	def LOMLifecycle(self):
		if not self.lifecycle:
			self.lifecycle=LOMLifecycle(self)
		return self.lifecycle
	
	def LOMMetaMetadata(self):
		if not self.metametadata:
			self.metametadata=LOMMetaMetadata(self)
		return self.metametadata
	
	def LOMTechnical(self):
		if not self.technical:
			self.technical=LOMTechnical(self)
		return self.technical
	
	def LOMEducational(self):
		if not self.educational:
			self.educational=LOMEducational(self)
		return self.educational
	
	def LOMRelation(self):
		r=LOMRelation(self)
		self.relations.append(r)
		return r

	def LOMAnnotation(self):
		a=LOMAnnotation(self)
		self.annotations.append(a)
		return a
		
	def LOMClassification(self):
		c=LOMClassification(self)
		self.classifications.append(c)
		return c


class Description(LangStringList):
	XMLNAME=(IMSLRM_NAMESPACE,'description')
	XMLCONTENT=xmlns.ElementContent


class LOMGeneral(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'general')
	XMLCONTENT=xmlns.ElementContent

	DescriptionClass=Description
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.identifier=None
		self.title=None
		self.catalogEntries=[]
		self.languages=[]
		self.Description=[]
		self.keywords=[]
		self.coverage=[]
		self.structure=None
		self.aggregationLevel=None
	
	def GetChildren(self):
		if self.identifier: yield self.identifier
		if self.title: yield self.title
		for child in itertools.chain(
			self.catalogEntries,
			self.languages,
			self.Description,
			self.keywords,
			self.coverage):
			yield child
		if self.structure: yield self.structure
		if self.aggregationLevel: yield self.aggregationLevel
		for child in LRMElement.GetChildren(self): yield child

	def LOMIdentifier(self):
		if not self.identifier:
			self.identifier=LOMIdentifier(self)
		return self.identifier
	
	def LOMTitle(self):
		if not self.title:
			self.title=LOMTitle(self)
		return self.title
	
	def LOMCatalogEntry(self):
		c=LOMCatalogEntry(self)
		self.catalogEntries.append(c)
		return c

	def LOMLanguage(self):
		l=LOMLanguage(self)
		self.languages.append(l)
		return l

	def LOMKeyword(self):
		kw=LOMKeyword(self)
		self.keywords.append(kw)
		return kw
	
	def LOMCoverage(self):
		c=LOMCoverage(self)
		self.coverage.append(c)
		return c

	def LOMStructure(self):
		if not self.structure:
			self.structure=LOMStructure(self)
		return self.structure
	
	def LOMAggregationLevel(self):
		if not self.aggregationLevel:
			self.aggregationLevel=LOMAggregationLevel(self)
		return self.aggregationLevel
	

class LOMIdentifier(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'identifier')
	
class LOMTitle(LangStringList):
	XMLNAME=(IMSLRM_NAMESPACE,'title')

class LOMCatalogEntry(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'catalogentry')

class LOMLanguage(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'language')
	
class LOMKeyword(LangStringList):
	XMLNAME=(IMSLRM_NAMESPACE,'keyword')

class LOMCoverage(LangStringList):
	XMLNAME=(IMSLRM_NAMESPACE,'coverage')

class LOMStructure(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'structure')

class LOMAggregationLevel(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'aggregationlevel')

class LOMLifecycle(LRMElement):
	"""
	<xsd:sequence>
		<xsd:element ref = "version" minOccurs = "0"/>
		<xsd:element ref = "status" minOccurs = "0"/>
		<xsd:element ref = "contribute" minOccurs = "0" maxOccurs = "unbounded"/>
		<xsd:group ref = "grp.any"/>
	</xsd:sequence>
	"""	
	XMLNAME=(IMSLRM_NAMESPACE,'lifecycle')
	XMLCONTENT=xmlns.ElementContent
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LOMVersion=None
		self.LOMStatus=None
		self.LOMContribute=[]
	
	def GetChildren(self):
		if self.LOMVersion: yield self.LOMVersion
		if self.LOMStatus: yield self.LOMStatus
		for child in itertools.chain(
			self.LOMContribute,
			LRMElement.GetChildren(self)):
			yield child

class LOMVersion(LangStringList):
	XMLNAME=(IMSLRM_NAMESPACE,'version')

class LOMStatus(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'status')
	
class LOMContribute(LRMElement):
	"""
	<xsd:sequence>
		<xsd:element ref = "role"/>
		<xsd:element ref = "centity" minOccurs = "0" maxOccurs = "unbounded"/>
		<xsd:element ref = "date" minOccurs = "0"/>
		<xsd:group ref = "grp.any"/>
	</xsd:sequence>
	"""
	XMLNAME=(IMSLRM_NAMESPACE,'contribute')
	XMLCONTENT=xmlns.ElementContent
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LOMRole=LOMRole(self)
		self.LOMCEntity=[]
		self.LOMDate=None
	
	def GetChildren(self):
		yield self.LOMRole
		for child in self.LOMCEntity: yield child
		if self.LOMDate: yield self.LOMDate
		for child in LRMElement.GetChildren(self): yield child

class LOMRole(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'role')

class LOMCEntity(LRMElement):
	"""
	"""
	XMLNAME=(IMSLRM_NAMESPACE,'centity')
	XMLCONTENT=xmlns.ElementContent
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LOMVCard=LOMVCard(self)
	
	def GetChildren(self):
		yield self.LOMVCard
		for child in LRMElement.GetChildren(self): yield child

class LOMVCard(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'vcard')

	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.vcard=None
	
	def GetValue(self):
		return self.vcard
	
	def SetValue(self,vcard):
		self.vcard=vcard
		LRMElement.SetValue(self,vcard.serialize())
	
	def PrettyPrint(self):
		"""Overridden to prevent pretty-printing of the element contents."""
		return False
	
	def GetCanonicalChildren(self):
		"""Overridden to prevent collapsing of whitespace"""
		return self.GetChildren()
		
	def GotChildren(self):
		# called when all children have been parsed
		if vobject is not None:
			src=LRMElement.GetValue(self)
			if src is not None and src.strip():
				self.vcard=vobject.readOne(src)
			else:
				self.vcard=None
				
class LOMMetaMetadata(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'metametadata')
	
class LOMTechnical(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'technical')
	
class LOMEducational(LRMElement):
	"""
    <xsd:complexType name="educationalType" mixed="true">
      <xsd:sequence>
         <xsd:element ref="interactivitytype" minOccurs="0"/>
         <xsd:element ref="learningresourcetype" minOccurs="0" maxOccurs="unbounded"/>
         <xsd:element ref="interactivitylevel" minOccurs="0"/>
         <xsd:element ref="semanticdensity" minOccurs="0"/>
         <xsd:element ref="intendedenduserrole" minOccurs="0" maxOccurs="unbounded"/>
         <xsd:element ref="context" minOccurs="0" maxOccurs="unbounded"/>
         <xsd:element ref="typicalagerange" minOccurs="0" maxOccurs="unbounded"/>
         <xsd:element ref="difficulty" minOccurs="0"/>
         <xsd:element ref="typicallearningtime" minOccurs="0"/>
         <xsd:element ref="description" minOccurs="0"/>
         <xsd:element ref="language" minOccurs="0" maxOccurs="unbounded"/>
         <xsd:group ref="grp.any"/>
      </xsd:sequence>
    </xsd:complexType>
	"""	
	XMLNAME=(IMSLRM_NAMESPACE,'educational')
	XMLCONTENT=xmlns.ElementContent
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LOMInteractivityType=None
		self.LOMLearningResourceType=[]
		self.LOMInteractivityLevel=None
		self.LOMSemanticDensity=None
		self.LOMIntendedEndUserRole=[]
		self.LOMContext=[]
		self.LOMTypicalAgeRange=[]
		self.LOMDifficulty=None
		self.LOMTypicalLearningTime=None
		self.Description=None
		self.LOMLanguage=[]

	def GetChildren(self):
		if self.LOMInteractivityType: yield self.LOMInteractivityType
		for child in self.LOMLearningResourceType: yield child
		if self.LOMInteractivityLevel: yield self.LOMInteractivityLevel
		if self.LOMSemanticDensity: yield self.LOMSemanticDensity
		for child in itertools.chain(
			self.LOMIntendedEndUserRole,
			self.LOMContext,
			self.LOMTypicalAgeRange):
			yield child
		if self.LOMDifficulty: yield self.LOMDifficulty
		if self.LOMTypicalLearningTime: yield self.LOMTypicalLearningTime
		if self.Description: yield self.Description
		for child in itertools.chain(
			self.LOMLanguage,
			LRMElement.GetChildren(self)):
			yield child

		
class LOMInteractivityType(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'interactivitytype')
	
class LOMLearningResourceType(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'learningresourcetype')

class LOMInteractivityLevel(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'interactivitylevel')

class LOMSemanticDensity(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'semanticdensity')

class LOMIntendedEndUserRole(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'intendedenduserrole')

class LOMContext(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'context')

class LOMTypicalAgeRange(LangStringList):
	XMLNAME=(IMSLRM_NAMESPACE,'typicalagerange')

class LOMDifficulty(LRMSourceValue):
	XMLNAME=(IMSLRM_NAMESPACE,'difficulty')

class LOMTypicalLearningTime(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'typicallearningimte')


class LOMRelation(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'relation')
	
class LOMAnnotation(LRMElement):
	""" 
	<xsd:complexType name="annotationType" mixed="true">
      <xsd:sequence>
         <xsd:element ref="person" minOccurs="0"/>
         <xsd:element ref="date" minOccurs="0"/>
         <xsd:element ref="description" minOccurs="0"/>
         <xsd:group ref="grp.any"/>
      </xsd:sequence>
	</xsd:complexType>
	"""
	XMLNAME=(IMSLRM_NAMESPACE,'annotation')
	XMLCONTENT=xmlns.ElementContent
	
	def __init__(self,parent):
		LRMElement.__init__(self,parent)
		self.LOMPerson=None
		self.LOMDate=None
		self.Description=None
	
	def GetChildren(self):
		if self.LOMPerson: yield self.LOMPerson
		if self.LOMDate: yield self.LOMDate
		if self.Description: yield self.Description
		for child in LRMElement.GetChildren(self): yield child

	
class LOMClassification(LRMElement):
	XMLNAME=(IMSLRM_NAMESPACE,'classification')
	
	
classMap={
	(IMSLRM_NAMESPACE,None):LRMElement
	}

xmlns.MapClassElements(classMap,globals())

def GetElementClass(name):
	ns,xmlname=name
	if ns in IMSLRM_NAMESPACE_ALIASES:
		ns=IMSLRM_NAMESPACE_ALIASES[ns]
	return classMap.get((ns,xmlname),classMap.get((ns,None),xmlns.XMLNSElement))
