#!/Users/amk/source/p/python/python.exe
# Read copy of the pyfaq infogami site (assumed to be in the pyfaq/
# subdirectory) and write out a pyramid-formatting tree to pyramid-faq/
#
# Warning: erases the existing pyramid-faq/ directory on starting!
#
# $Id$

import os, shutil, glob, cgi
import htmlload

ET = htmlload.ET

DESTDIR = 'pyramid-faq'

# Master collection of categories
categories = {}

def yaml_escape (S):
    "Escape S as a YAML string"
    S = normalize_whitespace(S)
    S = S.replace("\\", "\\\\")
    S = S.replace('"', '\\"')
    S = '"' + S + '"'  
    return S

def normalize_whitespace (S):
    """Replace all whitespace by single spaces.
    >>> normalize_whitespace('a    b\tc\nd')
    'a b c d'
    """
    return ' '.join(S.split())

def get_setting (root, setting_name, default=None):
    """Look for a paragraph containing a setting, like 'CATEGORY: general',
    and returns the result of the setting.
    """
    setting_start = setting_name.upper() + ':'
    for para in root.findall('*/p'):
        if para.text is not None and para.text.startswith(setting_start):
            value = para.text[len(setting_start):]
            value = value.strip()
            return value
    else:
        return default

def write_nav (dir, urls):
    f = open(os.path.join(dir, 'nav.yml'), 'w')
    f.write("""--- !fragment
# Type of template to use
template: nav.html

# Contents of the template
global: 
  nav : !sectionnav |
""")
    for dirname, title in urls:
        title = normalize_whitespace(title)
        f.write(' '*6 + title + ' ' + dirname + '\n')
    f.close()

def convert_question (filename):
    base = os.path.basename(filename).replace('.xml', '')
    # root is the 'html' element
    root = htmlload.load(filename)
    title = root.findtext('head/title') 
    title = normalize_whitespace(title)

    # Find category and name
    category = get_setting(root, 'category')
    if category is None:
        ##print 'Filename without category:', filename
        return
    if category in ('test',):
        return
    if category not in categories:
	categories[category] = None    

    name = get_setting(root, 'name', base)

    qdir = os.path.join(DESTDIR, category, name)
    os.makedirs(qdir)

    # Write body of question
    f = open(os.path.join(qdir, 'question.ht'), 'w')
    f.write('Title: Unused title\n')
    f.write('\n')

    f.write('<h1>%s</h1>\n\n' % cgi.escape(title))
    body = root.find('body')
    for child in body.getchildren():
        s = ET.tostring(child, 'utf-8')
        f.write(s)

    # Add a link to the wiki page for this question
    f.write('''<p><a href="http://pyfaq.infogami.com/%s">[Edit/comment on this page]</a></p>\n''' % base)
    f.close()

    # Write .yml files
    page_title = '%s FAQ: %s' % (category.capitalize(), title)
    f = open(os.path.join(qdir, 'index.yml'), 'w')
    f.write("""--- !fragment
template: index.html
# The data to pass to the template
global:
  metadata: {}
local:
  title: %s
  content: !fragment content.yml
    """ % yaml_escape(page_title))
    f.close()

    f = open(os.path.join(qdir, 'content.yml'), 'w')
    f.write("""--- !fragment
# Type of template to use
template: content.html

# The data to pass to the template
local:
  content:
    breadcrumb: !breadcrumb nav.yml nav
    text: !htfile question.ht\n""")
    f.close()

    
def convert_index (filename):
    root = htmlload.load(filename)
    title = root.findtext('*/title')
    title = normalize_whitespace(title)	
    i = title.find(':')
    category = title[i+1:].strip()
    idir = os.path.join(DESTDIR, category)

    # XXX can there be subsections within a category?
    entries = list(root.findall('*/p/a'))

    # Write body of question
    f = open(os.path.join(idir, 'listing.ht'), 'w')
    f.write('<ul>\n')
    urllist = []
    for a in entries:
        href = a.get("href")
        href = href.lstrip('/')
        a.set("href", href)
        f.write('<li>%s</li>\n' % ET.tostring(a, 'utf-8'))
        urllist.append((href, a.text))

    f.write('</ul>\n')
    f.close()

    write_nav(idir, urllist)	

    # Write .yml files
    f = open(os.path.join(idir, 'index.yml'), 'w')
    f.write("""--- !fragment
template: index.html
# The data to pass to the template
local:
  title: %s
  content: !fragment content.yml
    """ % yaml_escape(title))
    f.close()

    f = open(os.path.join(idir, 'content.yml'), 'w')
    f.write("""--- !fragment
# Type of template to use
template: content.html

# The data to pass to the template
local:
  content:
    breadcrumb: !breadcrumb nav.yml nav
    text: !htfile listing.ht""")
    f.close()
    
def write_master_index (index_files):
    f = open(os.path.join(DESTDIR, 'index.yml'), 'w')
    f.write("""--- !fragment
template: index.html
# The data to pass to the template
local:
  title: FAQs
  content: !fragment content.yml
""")
    f.close()

    f = open(os.path.join(DESTDIR, 'content.yml'), 'w')
    f.write("""--- !fragment
# Type of template to use
template: content.html

# The data to pass to the template
local:
  content:
    text: !htfile listing.ht
    breadcrumb: !breadcrumb nav.yml nav
""")    
    f.close()

    f = open(os.path.join(DESTDIR, 'listing.ht'), 'w')
    f.write('Title: Unused title\n')
    f.write('\n')
    f.write('<ul>\n')
    for cat in sorted(categories.keys()):
        f.write('  <li><a href="%s">%s</a>' % (cat, cat.capitalize()))
    f.write('</ul>\n')
    f.close()

    # Write navigation info
    urllist = []
    for cat in sorted(categories.keys()):
        urllist.append((cat, cat.capitalize()))
    write_nav(DESTDIR, urllist)

    f = open(os.path.join(DESTDIR, 'content.html'), 'w')
    f.write("""<n:invisible n:data="content" n:render="mapping">
<div id="breadcrumb" n:data="breadcrumb" n:render="breadcrumb" />
<n:slot name="text"></n:slot>
</n:invisible>""")
    f.close()

if os.path.exists(DESTDIR):
    shutil.rmtree(DESTDIR)
os.mkdir(DESTDIR)

# List the files to be converted
files = set(glob.glob('pyfaq/*.xml'))

for fn in list(files):
    if fn.startswith('pyfaq/_'):
        files.discard(fn)

index_files = [fn for fn in files if fn.endswith('-index.xml')]
for fn in index_files:
    files.discard(fn)

# Convert questions
for fn in list(files):
    convert_question(fn)

# Convert indexes
for fn in index_files:
    convert_index(fn)

write_master_index(index_files)

