﻿#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Glog, Greut's weblog system
# Library to manage a blog

__author = "Yoan Blanc <yoan@dosimple.ch>"

import os, re, string
from UserDict import UserDict
from xml.dom import minidom

# config variables
metadataextension = ".rdf"
base = "http://localhost/~yoan/blog/"

class Glog:
	"""
	The admin class
	"""
	
	_data = {}
	
	def __init__(self, path_info = None):
		if(path_info != None):
			self._info = path_info
			self._parse()
	
	def _parse(self):
		"""
		Parse the query string
		"""
		
		data = self._info.split('/')
		
		# regex
		main = []
		main.append(('action', re.compile('^[a-z]*$')))
		main.append(('tag', re.compile('^[A-Z][a-zA-Z0-9]*$')))
		
		regex = []
		regex.append(('year', re.compile('^[0-9]{4}$')))
		regex.append(('month', re.compile('^[0-1][0-9]$')))
		regex.append(('day',re.compile('^[0-3][1-9]')))
		regex.append(('title',re.compile('^[a-z][a-zA-Z0-9\-_]*$')))
		
		i = 1
		
		for (name, regelem) in main :
			while(len(data) > i and regelem.match(data[i])):
				if(not self._data.has_key(name)):
					self._data[name] = []
				
				self._data[name].append(data[i])
				i += 1
		
		for (name, regelem) in regex:
			if(len(data) > i and regelem.match(data[i],0) != None):
				self._data[name] = data[i]
			else:
				break
			i += 1
	
	def index(self):
		tpl = Template("../blog/template/index.html")
		
		data = {}
		
		data['page.title'] = 'admin'
		data['page.title.full'] = data['page.title'] + " : index"
		
		tpl.apply(data)
		
		return tpl.write()

class Entry(UserDict):
	"""
	An entry in the blog
	"""
	
	RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
	DC = 'http://purl.org/dc/elements/1.1/'
	localBase = '../blog/'
	xmlBase = 'http://yoan.dosimple.ch/blog/'
	
	dcFields = ['title','description.abstract','language','identifier','format',\
		'format.extent','subject','date.modified','date.issued', 'date.created',\
		'creator']
	dcMultipleFields = ['references', 'isReferencedBy']
	
	def __init__(self):
		"""
		Build the entry
		"""
		UserDict.__init__(self)
		
		self['base'] = self.xmlBase
	
	def load(self, filename):
		
		self['filename'] = filename;
		
		if not os.path.exists(self.localBase + filename):
			raise FileNotFound, "%s doesn't exist" % filename
		else:
			dom = minidom.parse(self.localBase + filename)
			
			element = dom.getElementsByTagNameNS(self.RDF,'Description')
			
			if(len(element) != 1):
				raise RdfTooComplex, "only one rdf:Description is allowed"
			else:
				self.__loadValues(element.item(0))
	
	def __loadValues(self, elem):
		for e in elem.childNodes :
			# lecture des dublin core
			if e.nodeType != e.TEXT_NODE and e.namespaceURI == self.DC :
				# lecture du noeud (littéral ou ressource)
				if e.firstChild != None and e.firstChild.nodeType == e.TEXT_NODE :
					value = e.firstChild.data
				else:
					value = e.getAttributeNS(self.RDF,'resource')
				
				# noeud simple
				if e.localName in self.dcFields:
					self[e.localName] = value
					
				# noeud pouvant être multiple
				elif e.localName in self.dcMultipleFields:
					if not self.has_key(e.localName):
						self[e.localName] = []
					
					self[e.localName].append({e.localName:value})
	
	def export(self):
		tpl = Template("../blog/template/simple.rdf")
		
		if(self.has_key("subject")):
			taxo = Template("../blog/template/simple_taxo.rdf")
			
			topics = []
			
			for topic in self["subject"].split(" "):
				topics.append({"topic":topic})
			
			taxo.loop("topics",topics)
			
			self["topics"] = taxo.write()
		
		tpl.setContext(self)
		tpl.apply(self)
		
		return tpl.write()
		#for k,v in self.items():
		#	print "%s :\t%s" % (k,v)
		#return ''

class Serialize:
	"""
	Serializer RDF-Entry, Entry-RDF
	"""
	
	def __init__(self, root='.'):
		self.root = root
		self.tplroot = "../blog/template/"
	
	def loadEntry(self, filename):
		pass
	
	def saveEntry(self, entry):
		tpl = Template(self.tplroot + "/file.rdf")
		
		tpl.apply(entry)
		
		return tpl.write()

class Template:
	"""
	A Class to parse template
	"""
	
	opener = "<!--%"
	closer = "%-->"
	hardcloser = "(?:[^%][^\-]{2}[^>])"
	
	# loop
	loopopen = "loop:"
	loopclose = "endloop"
	
	# if
	ifopen = "if:"
	ifelif = "elseif:"
	ifelse = "else"
	ifclose = "endif"
	
	# recursion
	recopen = "recursion:"
	recloop = recopen + "loop"
	recbody = recopen + "body"
	recendloop = recopen + "endloop"
	recclose = "endrecursion"
	
	def __init__(self, filename):
		tpl = open(filename)
		self.data = tpl.read()
		self._context = {}
	
	def apply(self, values):
		"""
		Apply values to template
		"""
		for k,v in values.items():
			if type(v) is str or type(v) is unicode :
				self.replace(k, v)
			elif type(v) is int or type (v) is float :
				self.replace(k, str(v))
			elif type(v) is list:
				self.loop(k, v)
			else:
				print k + " unknow "
				print type(v)
	
	def setContext(self, dict):
		"""
		Add new elements to context
		"""
		self._context.update(dict)
	
	def __parseif(self, text):
		"""
		Apply if statement
		"""
		
		ifregex = "(" + self.opener + self.ifopen + "(.*?)" + self.closer + "(.*?)" + self.opener + self.ifclose + self.closer + ")"
		elifregex = self.ifelif + "(.*?)" + self.closer + "(.*?)" + self.opener
		thenregex = "(.*?)" + self.opener + "(" + self.ifelif + "|" + self.ifelse + "|" + self.ifclose + ")"
		elseregex = self.opener + self.ifelse + self.closer + "(.*)"
		
		p = re.compile(ifregex, re.DOTALL | re.MULTILINE)
		
		ifs = p.findall(text)
		
		result = ""
		
		def evalformat(txt):
			has_key = re.compile("\[(.*?)\]")
			
			text = has_key.sub (r"self._context.has_key(\1) and self._context[\1]", txt)
			
			return text
		
		for ifstat in ifs:
			if(eval(evalformat(ifstat[1]))):
				np = re.compile(thenregex, re.DOTALL | re.M)
				npr = np.search(ifstat[2])
				
				if(npr is not None):
					result = npr.group(1)
				else:

					result = ifstat[2]
				
			else:
				eip = re.compile(elifregex, re.DOTALL | re.M)
				elifs = eip.findall(ifstat[2])
				
				find = 0
				
				for elifstat in elifs:
					if(eval(evalformat(elifstat[0]))):
						result = elifstat[1]
						find = 1
						break
				
				if not find:
					e = re.compile(elseregex, re.DOTALL | re.M)
					
					ev = e.search(ifstat[2])
					if ev is not None:
						result = ev.group(1)
					else:
						result = ''
			
			text = text.replace(ifstat[0],result)		
		
		return text
	
	def recursive(self, name, value):
		"""
		Apply recursive template
		"""
		
		recursionloop = "(.*?)" + self.opener + self.recloop + self.closer + "(.*?)" + self.opener + self.recendloop + self.closer + "(.*?)"
		recursion = "(" + self.opener + self.recopen + name + self.closer + recursionloop + self.opener + self.recclose + self.closer + ")"
		
		rec = re.compile(recursion, re.DOTALL | re.M)
		
		r = rec.findall(self.data)
		
		oldcontext = self._context
		
		def recurs (data, triple):
			result = triple[0]
			
			for line in data:
				body = triple[1]
				rec = ""
				
				self._context = line[0]
				body = self.__parseif(body)
				
				if(len(line) > 1):
					rec = recurs(line[1], triple)
					
				line[0][self.recbody] = rec
				
				for k,v in line[0].items():
					body = body.replace(self.opener + k + self.closer, str(v))
				
				result += body
			
			result += triple[2]
			
			return result
		
		self._context = oldcontext
		
		for rfind in r:
			
			text = recurs(value, rfind[1:])
			
			self.data = self.data.replace(rfind[0], text)
			
	
	def replace(self, name, value):
		"""
		replace the key(s) with the given value
		"""
		
		self.data = self.data.replace(self.opener + name + self.closer, value)
	
	def loop(self, name, values):
		"""
		Apply the values to that loop !
		"""
		
		loop = self.__getloop(name)
		
		oldcontext = self._context
		
		for l in loop:
			data = ""
			for line in values:
				self._context = line
				linedata = self.__parseif(l)
				for k,v in line.items():
					linedata = linedata.replace(self.opener + k + self.closer, v)
				data += linedata
			
			regex = self.opener + self.loopopen + name + ".*?" + self.loopclose + self.closer
			
			p = re.compile(regex, re.DOTALL | re.M)
			
			self.data = p.sub(data, self.data)
		
		self._context = oldcontext
	
	def __getloop(self, name):
		"""
		Init the loops
		"""
		regex = self.opener + self.loopopen + "(" + name + ")" + self.closer + "(.*?)" + self.opener + self.loopclose + self.closer
			
		loop = re.compile(regex, re.DOTALL | re.MULTILINE)
			
		listloop = loop.findall(self.data)
		
		loops = []
			
		for n in listloop:
			loops.append(n[1])
		
		return loops
		
	
	def write(self):
		"""
		Return the string output
		"""
		
		text = self.__parseif(self.data)
		
		emptytags = re.compile(self.opener + ".*?" + self.closer, re.DOTALL)

		text = emptytags.sub("", text)

		return text