import re, copy
import dt_FilePath
from cStringIO import StringIO

class StructuredDoc:
    def __init__(self, from_file=None, from_string=None):
	self.pieces=[]
	self.fields={}
	self.filename=None
	self.template_filename=None
	self.unused=[]
	if from_file:
	    self.parse_file(from_file)
	if from_string:
	    self.parse_string(from_string)
    def parse_string(self, contents): # class method
	match=begintemplate.search(contents)
	if match:
	    self.template_filename=match.group(1)
	    contents=contents[match.end():]
	    match=endtemplate.search(contents)
	    contents=contents[:match.start()]
	while 1:
	    match=begineditable.search(contents)
	    if not match: break
	    self.add_string(contents[:match.start()])
	    name=match.group(1)
	    contents=contents[match.end():]
	    match=endeditable.search(contents)
	    if not match: raise BadTemplate
	    default=contents[:match.start()]
	    contents=contents[match.end():]
	    self.add_editable(name, default)
	self.add_string(contents)
	return self
    def parse_file(self, filename): # class method
	f=open(filename)
	self.parse_string(f.read())
	f.close()
	self.filename=filename
	return self

    def add_string(self, string):
	self.pieces.append(string)
    def add_editable(self, name, default):
	self.pieces.append([name, default])
	self.fields[name]=default

    def __str__(self):
	result=StringIO()
	if self.template_filename:
	    result.write("<!-- #BeginTemplate \"%s\" -->\n" % 
			 self.template_filename)
	for x in self.pieces:
	    if type(x) is type(""):
		result.write(x)
	    else:
		result.write("<!-- #BeginEditable \"%s\" -->\n" % x[0])
		result.write(x[1])
		result.write("<!-- #EndEditable -->\n")
	for x in self.unused:
	    result.write("<!-- #BeginEditable \"%s\" --" % x[0])
	    result.write("%s!-- #EndEditable -->" % x[1])
	if self.template_filename:
	    result.write("<!-- #EndTemplate -->\n")
	s=result.getvalue()
	result.close()
	return s
    def insert(self, contents): # I'm a template, insert contents
	inserted=copy.deepcopy(self)
	usedfields={}
	for key in contents.fields.keys():
	    usedfields[key]=0
	for x in inserted.pieces:
	    if type(x) is type([]) and contents.fields.has_key(x[0]):
		x[1]=contents.fields[x[0]]
		inserted.fields[x[0]]=contents.fields[x[0]]
		usedfields[x[0]]=1
	for key, value in contents.fields.items():
	    if not usedfields[key]:
		inserted.unused.append([key, value])
	if self.filename:
	    inserted.template_filename=self.filename
	return inserted
    def strip_template(self):
	new_pieces=[]
	for x in self.pieces:
	    if type(x) is type([]):
		new_pieces.append(x)
	self.pieces=new_pieces
	return self
	
    def redirect_links(self, redirect_from, redirect_to):
	for i in range(0, len(self.pieces)):
	    if type(self.pieces[i]) is type(""):
		self.pieces[i]=redirect_links(self.pieces[i], redirect_from,
					      redirect_to)

begineditable=re.compile(r"<!--\s*#BeginEditable\s*\"(\w*)\"\s*-->?", re.I)
endeditable=re.compile(r"<?!--\s*#EndEditable\s*-->", re.I)
begintemplate=re.compile(r"<!--\s*#BeginTemplate\s*\"(.*)\"\s*-->", re.I)
endtemplate=re.compile(r"<!--\s*#EndTemplate\s*-->", re.I)
linkmatch=re.compile(r"(<[^>]*(?:href|src)\s*=\s*\")([^\"]*)(\"[^>]*>)", re.I)

def redirect_links(contents, relative_from, relative_to):
    def link_redirect(match, relative_to=relative_to,
		      relative_from=relative_from):
	path=match.group(2)
	if dt_FilePath.is_local(path):
	    path=dt_FilePath.construct_path(path, relative_from)
	    dir=dt_FilePath.strip_filename(path)
	    filename=dt_FilePath.get_filename(path)
	    path=dt_FilePath.add_filename(
		dt_FilePath.relative_to(dir, relative_to),
		filename)
	return '%s%s%s"' % (match.group(1), path, match.group(3))
    return re.sub(linkmatch, link_redirect, contents)

