#!/usr/bin/python

# Convert an hnb xml file into a text file formatted for emacs'
# org-mode.
#
# Written by Michael Mandel (mim at ee.columbia.edu)
# (c) copyright 2007

import xml.etree.ElementTree as ET
import sys
import tempfile


def main():
  # Load first arg as file
  hnb_file = file(sys.argv[1], "r")

  # Strip out extra <?pos="##"?> element from first line
  # e.g. <?xml version="1.0" encoding="ISO-8859-1"?><?pos="27"?>
  first_line = hnb_file.next()
  first_line = first_line[:first_line.find("?>")+2] + "\n"

  # Write the file back out to a temporary file
  tmp_file = tempfile.TemporaryFile(mode="w+")
  tmp_file.write(first_line)
  for line in hnb_file:
    tmp_file.write(line)
  tmp_file.flush()
  tmp_file.seek(0,0)

  hnb = ET.parse(tmp_file)
  tmp_file.close()

  for el in hnb.getroot():
    ConvertSubtree(el, 1, HasGrandchildren(hnb.getroot()))


def ConvertSubtree(el, level, is_uncle):
  "Recursively print out subtree rooted at this element"

  kids = list(el)
  has_grandkids = HasGrandchildren(kids)
  todo_string = TodoString(el.attrib)
  is_headline = len(kids) > 1 or is_uncle or todo_string

  if is_headline:
    line = "%s %s%s" % ('*'*level, todo_string, kids[0].text)
  else:
    line = "%s %s%s" % (' '*(level-1), todo_string, kids[0].text)
  print line.encode('utf-8')

  for k in kids[1:]:
    ConvertSubtree(k, level+1, has_grandkids)


def TodoString(atr):
  """
  Determine whether the element with these attributes is a TODO item
  and return the string appropriate to it, e.g. TODO or DONE
  """
  if atr.get("type") == "todo":
    if atr.get("done") == "yes":
      return "DONE "
    else:
      return "TODO "
  else:
    return ""


def HasGrandchildren(kids):
  """
  Determine whether any of the nodes in the list kids have their own
  children.  If kids is a single node, assumes that it is the parent
  in question and determines whether it has any grandchildren.
  """
  if not isinstance(kids, list): kids = list(kids)
  grandkids = [len(k) for k in kids]
  return (max(grandkids) > 1)


if __name__ == '__main__':
  main()


# EXAMPLE
# The following hnb file should be converted to the following org file
################### test.hnb ####################
# <?xml version="1.0" encoding="ISO-8859-1"?><?pos="9"?>
# <!-- generated by hnb 1.9.17 (http://hnb.sourceforge.net) -->
# 
# <!DOCTYPE tree[
# 	<!ELEMENT tree (node*)>
# 	<!ELEMENT data (#PCDATA)> <!-- (max 4096 bytes long) -->
# 	<!ELEMENT node (data?,node*)>
# 	<!ATTLIST node done (yes|no) #IMPLIED
# 	          type CDATA #IMPLIED
# 	>]>
# 
# <tree>
# <node><data>1</data>
# 	<node><data>2</data>
# 		<node><data>3</data></node>
# 	</node>
# 	<node><data>4</data></node>
# 	<node><data>6</data>
# 		<node done="no" type="todo"><data>8</data>
# 			<node done="no" type="todo"><data>11</data></node>
# 			<node done="yes" type="todo"><data>12</data></node>
# 		</node>
# 		<node done="yes" type="todo"><data>9</data></node>
# 		<node done="no" type="todo"><data>10</data></node>
# 	</node>
# 	<node><data>7</data></node>
# </node>
# <node><data>5</data></node>
# </tree>

################### test.org ######################
# * 1
# ** 2
#    3
# ** 4
# ** 6
# *** TODO 8
# **** TODO 11
# **** DONE 12
# *** DONE 9
# *** TODO 10
# ** 7
# * 5

