# -*- coding: UTF-8 -*-
#
#       exports.py
#       
#       Copyright 2009-2011 Giuseppe Penone <giuspen@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import os, cgi, base64, shutil, copy
import cons, support


class Export2CTD:
   """The Export to CTD Class"""
   
   def __init__(self, dad):
      """Export to Txt boot"""
      self.dad = dad
   
   def get_single_ctd_filepath(self, proposed_name, filter_pattern):
      """Prepare for the CTD file save"""
      filepath = support.dialog_file_save_as(proposed_name,
                                             filter_pattern=filter_pattern,
                                             filter_name=_("CherryTree Document"),
                                             curr_folder=self.dad.file_dir,
                                             parent=self.dad.window)
      if filepath == None: return None
      if not os.path.isfile(filepath)\
      or support.dialog_question(_("The File %s\nAlready Exists, do you want to Overwrite?") % filepath, self.dad.window):
         return self.dad.filepath_extension_fix(filepath)
      return None
   
   def nodes_all_export_to_ctd(self, filepath):
      """Export All Nodes To CTD"""
      try: xml_string = self.dad.xml_handler.treestore_to_dom()
      except:
         support.dialog_error("%s write failed - all nodes to xml" % filepath, self.dad.window)
         return
      try: self.dad.file_write_low_level(filepath, xml_string)
      except: support.dialog_error("%s write failed - writing to disk" % filepath, self.dad.window)
   
   def node_and_subnodes_export_to_ctd(self, tree_iter, filepath):
      """Export Node and Subnodes To CTD"""
      try: xml_string = self.dad.xml_handler.treestore_sel_node_and_subnodes_to_dom(tree_iter)
      except:
         support.dialog_error("%s write failed - sel node and subnodes to xml" % filepath, self.dad.window)
         return
      try: self.dad.file_write_low_level(filepath, xml_string)
      except: support.dialog_error("%s write failed - writing to disk" % filepath, self.dad.window)
   
   def node_export_to_ctd(self, tree_iter, filepath):
      """Export the Selected Node To CTD"""
      try: xml_string = self.dad.xml_handler.treestore_sel_node_only_to_dom(tree_iter)
      except:
         support.dialog_error("%s write failed - sel node to xml" % filepath, self.dad.window)
         return
      try: self.dad.file_write_low_level(filepath, xml_string)
      except: support.dialog_error("%s write failed - writing to disk" % filepath, self.dad.window)


class ExportPrint:
   """The Export Print Class"""
   
   def __init__(self, dad):
      """Export Print boot"""
      self.dad = dad
      self.pango_handler = Export2Pango(dad)
   
   def nodes_all_export_print(self, top_tree_iter=None):
      """Export Print All Nodes"""
      self.pango_text = []
      self.pixbuf_table_codebox_vector = []
      self.text_font = self.dad.code_font
      if not top_tree_iter: tree_iter = self.dad.treestore.get_iter_first()
      else: tree_iter = top_tree_iter.copy()
      while tree_iter:
         self.nodes_all_export_print_iter(tree_iter)
         if top_tree_iter: break
         tree_iter = self.dad.treestore.iter_next(tree_iter)
      self.run_print()
   
   def nodes_all_export_print_iter(self, tree_iter):
      """Export Print All Nodes - Iter"""
      if self.dad.treestore[tree_iter][4] == cons.CUSTOM_COLORS_ID:
         pango_text, pixbuf_table_codebox_vector = self.pango_handler.pango_get_from_treestore_node(tree_iter)
         self.text_font = self.dad.text_font # text font for all (also eventual code nodes)
      else:
         pango_text = [self.pango_handler.pango_get_from_code_buffer(self.dad.treestore[tree_iter][2])]
         pixbuf_table_codebox_vector = []
      if not self.pango_text: self.pango_text = pango_text
      else:
         self.pango_text[-1] += cons.CHAR_NEWLINE*3 + pango_text[0]
         if len(pango_text) > 1: self.pango_text += pango_text[1:]
      self.pixbuf_table_codebox_vector += pixbuf_table_codebox_vector
      child_tree_iter = self.dad.treestore.iter_children(tree_iter)
      while child_tree_iter:
         self.nodes_all_export_print_iter(child_tree_iter)
         child_tree_iter = self.dad.treestore.iter_next(child_tree_iter)
   
   def node_export_print(self, tree_iter):
      """Export Print the Selected Node"""
      if self.dad.treestore[tree_iter][4] == cons.CUSTOM_COLORS_ID:
         self.pango_text, self.pixbuf_table_codebox_vector = self.pango_handler.pango_get_from_treestore_node(tree_iter)
         self.text_font = self.dad.text_font
      else:
         self.pango_text = [self.pango_handler.pango_get_from_code_buffer(self.dad.treestore[tree_iter][2])]
         self.pixbuf_table_codebox_vector = []
         self.text_font = self.dad.code_font
      self.run_print()
   
   def run_print(self):
      """Finally Run the Print"""
      self.dad.print_handler.print_text(self.dad.window,
                                        self.pango_text,
                                        self.text_font,
                                        self.dad.code_font,
                                        self.pixbuf_table_codebox_vector,
                                        self.dad.get_text_window_width())


class Export2Txt:
   """The Export to Txt Class"""
   
   def __init__(self, dad):
      """Export to Txt boot"""
      self.dad = dad
   
   def get_single_txt_filepath(self, proposed_name):
      """Prepare for the txt file save"""
      filepath = support.dialog_file_save_as(proposed_name + ".txt",
                                             filter_pattern="*.txt",
                                             filter_name=_("Plain Text Document"),
                                             curr_folder=self.dad.file_dir,
                                             parent=self.dad.window)
      if filepath == None: return None
      if not os.path.isfile(filepath)\
      or support.dialog_question(_("The File %s\nAlready Exists, do you want to Overwrite?") % filepath, self.dad.window):
         if len(filepath) < 4 or filepath[-4:] != ".txt": filepath += ".txt"
         return filepath
      return None
   
   def prepare_txt_folder(self, new_folder):
      """Prepare the website folder"""
      dir_place = support.dialog_folder_select(curr_folder=self.dad.file_dir, parent=self.dad.window)
      if dir_place == None: return False
      new_folder += "_txt"
      while os.path.exists(os.path.join(dir_place, new_folder)):
         new_folder += "2"
      self.new_path = os.path.join(dir_place, new_folder)
      os.mkdir(self.new_path)
      return True
   
   def nodes_all_export_to_txt(self, top_tree_iter=None):
      """Export All Nodes To Txt"""
      if not top_tree_iter: tree_iter = self.dad.treestore.get_iter_first()
      else: tree_iter = top_tree_iter.copy()
      while tree_iter:
         self.nodes_all_export_to_txt_iter(tree_iter)
         if top_tree_iter: break
         tree_iter = self.dad.treestore.iter_next(tree_iter)
   
   def nodes_all_export_to_txt_iter(self, tree_iter):
      """Export All Nodes To Txt - iter"""
      text_buffer = self.dad.treestore[tree_iter][2]
      filepath = os.path.join(self.new_path,
                              support.get_node_hierarchical_name(self.dad, tree_iter))
      self.node_export_to_txt(text_buffer, filepath)
      child_tree_iter = self.dad.treestore.iter_children(tree_iter)
      while child_tree_iter:
         self.nodes_all_export_to_txt_iter(child_tree_iter)
         child_tree_iter = self.dad.treestore.iter_next(child_tree_iter)
   
   def node_export_to_txt(self, text_buffer, filepath):
      """Export the Selected Node To Txt"""
      plain_text = text_buffer.get_text(*text_buffer.get_bounds())
      file_descriptor = open(filepath, 'w')
      file_descriptor.write(plain_text)
      file_descriptor.close()


class Export2Pango:
   """The Export to Pango Class"""
   
   def __init__(self, dad):
      """Export to Pango boot"""
      self.dad = dad
      
   def pango_get_from_code_buffer(self, code_buffer):
      """Get rich text from syntax highlighted code node"""
      curr_iter = code_buffer.get_start_iter()
      code_buffer.ensure_highlight(curr_iter, code_buffer.get_end_iter())
      pango_text = ""
      former_tag_str = cons.COLOR_BLACK
      span_opened = False
      while 1:
         curr_tags = curr_iter.get_tags()
         if len(curr_tags) > 0:
            curr_tag_str = curr_tags[0].get_property("foreground-gdk").to_string()
            font_weight = curr_tags[0].get_property("weight")
            if curr_tag_str == cons.COLOR_BLACK:
               if former_tag_str != curr_tag_str:
                  former_tag_str = curr_tag_str
                  # end of tag
                  pango_text += "</span>"
                  span_opened = False
            else:
               if former_tag_str != curr_tag_str:
                  former_tag_str = curr_tag_str
                  if span_opened: pango_text += "</span>"
                  # start of tag
                  if curr_tag_str == cons.COLOR_WHITE: curr_tag_str = cons.COLOR_BLACK
                  pango_text += '<span foreground="%s" font_weight="%s">' % (curr_tag_str, font_weight)
                  span_opened = True
         elif span_opened:
            span_opened = False
            former_tag_str = cons.COLOR_BLACK
            pango_text += "</span>"
         pango_text += cgi.escape(curr_iter.get_char())
         if not curr_iter.forward_char():
            if span_opened: pango_text += "</span>"
            break
      return pango_text
   
   def pango_get_from_treestore_node(self, node_iter):
      """Given a treestore iter returns the Pango rich text"""
      curr_buffer = self.dad.treestore[node_iter][2]
      pixbuf_table_codebox_vector = self.dad.state_machine.get_embedded_pixbufs_tables_codeboxes(curr_buffer, for_print=1)
      # pixbuf_table_codebox_vector is [ [ "pixbuf"/"table"/"codebox", [offset, pixbuf, alignment] ],... ]
      self.curr_pango_slots = []
      start_offset = 0
      for end_offset_element in pixbuf_table_codebox_vector:
         end_offset = end_offset_element[1][0]
         self.pango_process_slot(start_offset, end_offset, curr_buffer)
         start_offset = end_offset
      self.pango_process_slot(start_offset, -1, curr_buffer)
      #print "curr_pango_slots", self.curr_pango_slots
      #print "pixbuf_table_codebox_vector", pixbuf_table_codebox_vector
      # fix the problem of the latest char not being a new line char
      if len(self.curr_pango_slots) > 0 and\
       ( len(self.curr_pango_slots[-1]) == 0 or self.curr_pango_slots[-1][-1] != cons.CHAR_NEWLINE ):
         self.curr_pango_slots[-1] += cons.CHAR_NEWLINE
      return [self.curr_pango_slots, pixbuf_table_codebox_vector]
      
   def pango_process_slot(self, start_offset, end_offset, curr_buffer):
      """Process a Single Pango Slot"""
      self.curr_pango_text = ""
      start_iter = curr_buffer.get_iter_at_offset(start_offset)
      if end_offset == -1:
         end_offset = curr_buffer.get_end_iter().get_offset()
      #print "process slot (%s->%s)" % (start_offset, end_offset)
      # begin operations
      self.curr_attributes = {}
      for tag_property in cons.TAG_PROPERTIES: self.curr_attributes[tag_property] = ""
      curr_iter = start_iter.copy()
      self.dad.xml_handler.rich_text_attributes_update(curr_iter, self.curr_attributes)
      tag_found = curr_iter.forward_to_tag_toggle(None)
      while tag_found:
         if curr_iter.get_offset() > end_offset:
            curr_iter = curr_buffer.get_iter_at_offset(end_offset)
         self.pango_text_serialize(start_iter, curr_iter)
         offset_old = curr_iter.get_offset()
         if offset_old >= end_offset: break
         else:
            self.dad.xml_handler.rich_text_attributes_update(curr_iter, self.curr_attributes)
            start_iter.set_offset(offset_old)
            tag_found = curr_iter.forward_to_tag_toggle(None)
            if curr_iter.get_offset() == offset_old: break
      else: self.pango_text_serialize(start_iter, curr_iter)
      self.curr_pango_slots.append(self.curr_pango_text)
      
   def pango_text_serialize(self, start_iter, end_iter):
      """Adds a slice to the Pango Text"""
      pango_attrs = ''
      for tag_property in cons.TAG_PROPERTIES:
         if tag_property not in ["justification", "link"] and self.curr_attributes[tag_property] != '':
            property_value = self.curr_attributes[tag_property]
            # tag names fix
            if tag_property == "scale": tag_property = "size"
            # tag properties fix
            if property_value == "small": property_value = 'x-small'
            elif property_value == "h1": property_value = 'xx-large'
            elif property_value == "h2": property_value = 'x-large'
            pango_attrs += ' %s="%s"' % (tag_property, property_value)
      if pango_attrs == '': self.curr_pango_text += cgi.escape(start_iter.get_text(end_iter))
      else: self.curr_pango_text += '<span' + pango_attrs + '>' + cgi.escape(start_iter.get_text(end_iter)) + '</span>'


class Export2Html:
   """The Export to HTML Class"""
   
   def __init__(self, dad):
      """Export to HTML boot"""
      self.dad = dad
      self.tree_links_text = ""
   
   def prepare_html_folder(self, new_folder):
      """Prepare the website folder"""
      dir_place = support.dialog_folder_select(curr_folder=self.dad.file_dir, parent=self.dad.window)
      if dir_place == None: return False
      new_folder += "_html"
      while os.path.exists(os.path.join(dir_place, new_folder)):
         new_folder += "2"
      self.new_path = os.path.join(dir_place, new_folder)
      self.images_dir = os.path.join(self.new_path, "images")
      os.mkdir(self.new_path)
      os.mkdir(self.images_dir)
      return True
   
   def nodes_all_export_to_html(self, top_tree_iter=None):
      """Export All Nodes To HTML"""
      # create tree links text
      self.tree_links_nums = ["1"]
      for image_stock_id in cons.NODES_STOCKS:
         shutil.copy(cons.GLADE_PATH + cons.STOCKS_N_FILES[image_stock_id], self.images_dir)
      self.tree_links_text = '<table style="text-align:left">'
      if not top_tree_iter: tree_iter = self.dad.treestore.get_iter_first()
      else: tree_iter = top_tree_iter.copy()
      while tree_iter:
         self.tree_links_text_iter(tree_iter)
         self.tree_links_nums[-1] = str( int(self.tree_links_nums[-1]) + 1 )
         if top_tree_iter: break
         tree_iter = self.dad.treestore.iter_next(tree_iter)
      self.tree_links_text += '</table>'
      # create index html page
      self.create_tree_index_page()
      # create html pages
      if not top_tree_iter: tree_iter = self.dad.treestore.get_iter_first()
      else: tree_iter = top_tree_iter.copy()
      while tree_iter:
         self.nodes_all_export_to_html_iter(tree_iter)
         if top_tree_iter: break
         tree_iter = self.dad.treestore.iter_next(tree_iter)
      self.tree_links_text = ""
   
   def nodes_all_export_to_html_iter(self, tree_iter):
      """Export All Nodes To HTML - iter"""
      self.node_export_to_html(tree_iter)
      child_tree_iter = self.dad.treestore.iter_children(tree_iter)
      while child_tree_iter:
         self.nodes_all_export_to_html_iter(child_tree_iter)
         child_tree_iter = self.dad.treestore.iter_next(child_tree_iter)
   
   def tree_links_text_iter(self, tree_iter):
      """Creating the Tree Links Text - iter"""
      href = self.get_html_filename(tree_iter)
      self.tree_links_text += "<tr><td>"
      self.tree_links_text += "&nbsp;&nbsp;&nbsp;" * len(self.tree_links_nums)
      icon_rel_path = os.path.join(self.images_dir, cons.STOCKS_N_FILES[self.dad.treestore[tree_iter][0]])
      self.tree_links_text += '<img src="%s" alt="%s" height="22" width="22"/>' % (icon_rel_path, icon_rel_path)
      self.tree_links_text += '<a href="' + href + '">' + ".".join(self.tree_links_nums) + " " + self.dad.treestore[tree_iter][1] + "</a></td></tr>"
      child_tree_iter = self.dad.treestore.iter_children(tree_iter)
      self.tree_links_nums.append("1")
      while child_tree_iter:
         self.tree_links_text_iter(child_tree_iter)
         self.tree_links_nums[-1] = str( int(self.tree_links_nums[-1]) + 1 )
         child_tree_iter = self.dad.treestore.iter_next(child_tree_iter)
      self.tree_links_nums.pop()
   
   def create_tree_index_page(self):
      """Write the index html file for the tree"""
      html_text = cons.HTML_HEADER % self.dad.file_name
      html_text += self.tree_links_text
      html_text += cons.HTML_FOOTER
      file_descriptor = open(os.path.join(self.new_path, "index.html"), 'w')
      file_descriptor.write(html_text)
      file_descriptor.close()
   
   def node_export_to_html(self, tree_iter):
      """Export the Selected Node To HTML"""
      html_text = cons.HTML_HEADER % self.dad.treestore[tree_iter][1]
      if self.tree_links_text:
         html_text += r'<table width="100%"><tr>'
         td_tree = r'<td valign="top" align="left" width=30%>'
         td_page = r'<td valign="top" align="left" width=70%>'
         html_text += td_tree + self.tree_links_text + td_page
      if self.dad.treestore[tree_iter][4] == cons.CUSTOM_COLORS_ID:
         text_n_objects = self.html_get_from_treestore_node(tree_iter)
         self.images_count = 0
         for i, html_slot in enumerate(text_n_objects[0]):
            html_text += html_slot
            if i < len(text_n_objects[1]):
               curr_object = text_n_objects[1][i]
               if curr_object[0] == "pixbuf": html_text += self.get_image_html(curr_object[1], tree_iter)
               elif curr_object[0] == "table": html_text += self.get_table_html(curr_object[1])
               elif curr_object[0] == "codebox": html_text += self.get_codebox_html(curr_object[1])
      else: html_text += self.html_get_from_code_buffer(self.dad.treestore[tree_iter][2])
      if self.tree_links_text:
         html_text += '</td></tr></table>'
      html_text += cons.HTML_FOOTER
      file_descriptor = open(os.path.join(self.new_path, self.get_html_filename(tree_iter)), 'w')
      file_descriptor.write(html_text)
      file_descriptor.close()
   
   def selection_export_to_html(self, text_buffer, start_iter, end_iter, syntax_highlighting):
      """Returns the HTML given the text buffer and iter bounds"""
      html_text = cons.HTML_HEADER % ""
      if syntax_highlighting == cons.CUSTOM_COLORS_ID:
         text_n_objects = self.html_get_from_rich_text_selection(text_buffer, start_iter, end_iter)
         self.images_count = 0
         for i, html_slot in enumerate(text_n_objects[0]):
            html_text += html_slot
            if i < len(text_n_objects[1]):
               curr_object = text_n_objects[1][i]
               if curr_object[0] == "pixbuf":
                  self.images_dir = cons.TMP_FOLDER
                  html_text += self.get_image_html(curr_object[1], None)
               elif curr_object[0] == "table": html_text += self.get_table_html(curr_object[1])
               elif curr_object[0] == "codebox": html_text += self.get_codebox_html(curr_object[1])
      else: html_text += self.html_get_from_code_buffer(text_buffer, sel_range=(start_iter.get_offset(), end_iter.get_offset()))
      html_text += cons.HTML_FOOTER
      return html_text
   
   def table_export_to_html(self, table_dict):
      """Returns the HTML given the table dict"""
      html_text = cons.HTML_HEADER % ""
      html_text += self.get_table_html([0, table_dict, "left"])
      html_text += cons.HTML_FOOTER
      return html_text
   
   def codebox_export_to_html(self, codebox_dict):
      """Returns the HTML given the table dict"""
      html_text = cons.HTML_HEADER % ""
      html_text += self.get_codebox_html([0, codebox_dict, "left"])
      html_text += cons.HTML_FOOTER
      return html_text
   
   def get_image_html(self, image, tree_iter):
      """Returns the HTML Image"""
      # image is: [offset, pixbuf, justification]
      if "anchor" in dir(image[1]):
         return '<a name="%s"></a>' % image[1].anchor
      image_align_text = self.get_object_alignment_string(image[2])
      self.images_count += 1
      if tree_iter:
         image_name = "%s-%s.png" % (self.dad.treestore[tree_iter][3], self.images_count)
         image_rel_path = os.path.join(self.images_dir, image_name)
      else:
         image_name = "%s.png" % self.images_count
         image_rel_path = "file://" + os.path.join(self.images_dir, image_name)
      image_html = '<table style="%s"><tr><td><img src="%s" alt="%s" /></td></tr></table>' % (image_align_text, image_rel_path, image_rel_path)
      image[1].save(os.path.join(self.images_dir, image_name), "png")
      return image_html
   
   def get_codebox_html(self, codebox):
      """Returns the HTML CodeBox"""
      # codebox is: [offset, dict, justification]
      codebox_align_text = self.get_object_alignment_string(codebox[2])
      codebox_html = '<table border="1" style="%s"><tr><td>' % codebox_align_text
      codebox_html += codebox[1]['fill_text']
      codebox_html += "</td></tr></table>"
      return codebox_html
   
   def get_table_html(self, table_orig):
      """Returns the HTML Table"""
      # table is: [offset, dict, justification]
      table = copy.deepcopy(table_orig)
      table_align_text = self.get_object_alignment_string(table[2])
      table_html = '<table border="1" style="%s;text-align:center">' % table_align_text
      table[1]['matrix'].insert(0, table[1]['matrix'].pop())
      for col in table[1]['matrix'][0]:
         table_html += '<col width="%s" />' % table[1]['col_max']
      for j, row in enumerate(table[1]['matrix']):
         table_html += "<tr>"
         for cell in row:
            if j == 0: table_html += "<th>" + cell + "</th>"
            else: table_html += "<td>" + cell + "</td>"
         table_html += "</tr>"
      table_html += "</table>"
      return table_html
   
   def get_object_alignment_string(self, alignment):
      """Returns the style attribute(s) according to the alignment"""
      if alignment == "center": return "margin-left:auto;margin-right:auto"
      elif alignment == "right": return "margin-left:auto"
      else: return "display:inline-table"
   
   def get_html_filename(self, tree_iter):
      """Get the HTML page filename given the tree iter"""
      file_name = self.dad.treestore[tree_iter][1]
      father_iter = self.dad.treestore.iter_parent(tree_iter)
      while father_iter:
         file_name = self.dad.treestore[father_iter][1] + "--" + file_name
         father_iter = self.dad.treestore.iter_parent(father_iter)
      file_name += ".html"
      return file_name.replace("/", "-")
   
   def html_get_from_code_buffer(self, code_buffer, sel_range=None):
      """Get rich text from syntax highlighted code node"""
      if sel_range: curr_iter = code_buffer.get_iter_at_offset(sel_range[0])
      else: curr_iter = code_buffer.get_start_iter()
      code_buffer.ensure_highlight(curr_iter, code_buffer.get_end_iter())
      html_text = ""
      former_tag_str = cons.COLOR_BLACK
      span_opened = False
      while 1:
         curr_tags = curr_iter.get_tags()
         if len(curr_tags) > 0:
            curr_tag_str = curr_tags[0].get_property("foreground-gdk").to_string()
            font_weight = curr_tags[0].get_property("weight")
            if curr_tag_str == cons.COLOR_BLACK:
               if former_tag_str != curr_tag_str:
                  former_tag_str = curr_tag_str
                  # end of tag
                  html_text += "</span>"
                  span_opened = False
            else:
               if former_tag_str != curr_tag_str:
                  former_tag_str = curr_tag_str
                  if span_opened: html_text += "</span>"
                  # start of tag
                  if curr_tag_str == cons.COLOR_WHITE: curr_tag_str = cons.COLOR_BLACK
                  html_text += '<span style="color:#%s;font-weight:%s">' % (self.rgb_to_24(curr_tag_str[1:]), font_weight)
                  span_opened = True
         elif span_opened:
            span_opened = False
            former_tag_str = cons.COLOR_BLACK
            html_text += "</span>"
         html_text += cgi.escape(curr_iter.get_char()).replace(" ", "&nbsp;")
         if not curr_iter.forward_char() or (sel_range and curr_iter.get_offset() > sel_range[1]):
            if span_opened: html_text += "</span>"
            break
      html_text = html_text.replace(cons.CHAR_NEWLINE, "<br>")
      return html_text
   
   def html_get_from_treestore_node(self, node_iter):
      """Given a treestore iter returns the HTML rich text"""
      curr_buffer = self.dad.treestore[node_iter][2]
      pixbuf_table_codebox_vector = self.dad.state_machine.get_embedded_pixbufs_tables_codeboxes(curr_buffer, for_print=2)
      # pixbuf_table_codebox_vector is [ [ "pixbuf"/"table"/"codebox", [offset, pixbuf, alignment] ],... ]
      self.curr_html_slots = []
      start_offset = 0
      for end_offset_element in pixbuf_table_codebox_vector:
         end_offset = end_offset_element[1][0]
         self.html_process_slot(start_offset, end_offset, curr_buffer)
         start_offset = end_offset
      self.html_process_slot(start_offset, -1, curr_buffer)
      #print "curr_html_slots", self.curr_html_slots
      #print "pixbuf_table_codebox_vector", pixbuf_table_codebox_vector
      return [self.curr_html_slots, pixbuf_table_codebox_vector]
      
   def html_get_from_rich_text_selection(self, text_buffer, start_iter, end_iter):
      """Given a text buffer and iter bounds returns the HTML rich text"""
      pixbuf_table_codebox_vector = self.dad.state_machine.get_embedded_pixbufs_tables_codeboxes(text_buffer,
                                                                                                 for_print=2,
                                                                                                 sel_range=(start_iter.get_offset(), end_iter.get_offset()))
      # pixbuf_table_codebox_vector is [ [ "pixbuf"/"table"/"codebox", [offset, pixbuf, alignment] ],... ]
      self.curr_html_slots = []
      start_offset = start_iter.get_offset()
      for end_offset_element in pixbuf_table_codebox_vector:
         end_offset = end_offset_element[1][0]
         self.html_process_slot(start_offset, end_offset, text_buffer)
         start_offset = end_offset
      self.html_process_slot(start_offset, end_iter.get_offset(), text_buffer)
      #print "curr_html_slots", self.curr_html_slots
      #print "pixbuf_table_codebox_vector", pixbuf_table_codebox_vector
      return [self.curr_html_slots, pixbuf_table_codebox_vector]
      
   def html_process_slot(self, start_offset, end_offset, curr_buffer):
      """Process a Single HTML Slot"""
      self.curr_html_text = ""
      start_iter = curr_buffer.get_iter_at_offset(start_offset)
      if end_offset == -1:
         end_offset = curr_buffer.get_end_iter().get_offset()
      #print "process slot (%s->%s)" % (start_offset, end_offset)
      # begin operations
      self.curr_attributes = {}
      for tag_property in cons.TAG_PROPERTIES: self.curr_attributes[tag_property] = ""
      curr_iter = start_iter.copy()
      self.dad.xml_handler.rich_text_attributes_update(curr_iter, self.curr_attributes)
      tag_found = curr_iter.forward_to_tag_toggle(None)
      while tag_found:
         if curr_iter.get_offset() > end_offset: curr_iter = curr_buffer.get_iter_at_offset(end_offset)
         self.html_text_serialize(start_iter, curr_iter)
         offset_old = curr_iter.get_offset()
         if offset_old >= end_offset: break
         else:
            self.dad.xml_handler.rich_text_attributes_update(curr_iter, self.curr_attributes)
            start_iter.set_offset(offset_old)
            tag_found = curr_iter.forward_to_tag_toggle(None)
            if curr_iter.get_offset() == offset_old: break
      else:
         if curr_iter.get_offset() > end_offset: curr_iter = curr_buffer.get_iter_at_offset(end_offset)
         self.html_text_serialize(start_iter, curr_iter)
      self.curr_html_text = self.curr_html_text.replace("<br/><p ", "<p ")
      self.curr_html_text = self.curr_html_text.replace("</p><br/>", "</p>")
      self.curr_html_slots.append(self.curr_html_text)
      
   def html_text_serialize(self, start_iter, end_iter):
      """Adds a slice to the HTML Text"""
      inner_text = cgi.escape(start_iter.get_text(end_iter))
      if inner_text == "": return
      inner_text = inner_text.replace(cons.CHAR_NEWLINE, "<br>")
      html_attrs = ""
      for tag_property in cons.TAG_PROPERTIES:
         if self.curr_attributes[tag_property] != '':
            property_value = self.curr_attributes[tag_property]
            #print property_value
            if tag_property == "weight":
               # font-weight:bolder
               tag_property = "font-weight"
               property_value = "bolder"
            elif tag_property == "foreground":
               # color:#FFFF00
               tag_property = "color"
               property_value = "#" + self.rgb_to_24(property_value[1:])
            elif tag_property == "background":
               # background-color:#FFFF00
               tag_property = "background-color"
               property_value = "#" + self.rgb_to_24(property_value[1:])
            elif tag_property == "style":
               # font-style:italic
               tag_property = "font-style"
               property_value = "italic"
            elif tag_property == "underline":
               # text-decoration:underline
               tag_property = "text-decoration"
               property_value = "underline"
            elif tag_property == "strikethrough":
               # text-decoration:line-through
               tag_property = "text-decoration"
               property_value = "line-through"
            elif tag_property == "scale":
               # font-size:xx-large/x-large/x-small
               tag_property = "font-size"
               if property_value == "small": property_value = "x-small"
               elif property_value == "h1": property_value = "xx-large"
               elif property_value == "h2": property_value = "x-large"
            elif tag_property == "justification":
               # text-align:center/left/right
               #tag_property = "text-align"
               continue
            elif tag_property == "link":
               # <a href="http://www.example.com/">link-text goes here</a>
               vector = property_value.split()
               if vector[0] == "webs": href = vector[1]
               elif vector[0] == "file": href = "file://" + base64.b64decode(vector[1])
               elif vector[0] == "node":
                  dest_tree_iter = self.dad.get_tree_iter_from_node_id(long(vector[1]))
                  if not dest_tree_iter: continue
                  href = self.get_html_filename(dest_tree_iter)
                  if len(vector) >= 3:
                     if len(vector) == 3: anchor_name = vector[2]
                     else: anchor_name = property_value[len(vector[0]) + len(vector[1]) + 2:]
                     href += "#" + anchor_name
               else: continue
               self.curr_html_text += '<a href="' + href + '">' + inner_text + "</a>"
               return
            html_attrs += "%s:%s;" % (tag_property, property_value)
      if html_attrs == "" or inner_text == "<br/>": self.curr_html_text += inner_text
      else:
         if "xx-large" in html_attrs:
            html_attrs = html_attrs.replace("font-size:xx-large;", "")
            self.curr_html_text += '<h1 style="' + html_attrs + '">' + inner_text + "</h1>"
         elif "x-large" in html_attrs:
            html_attrs = html_attrs.replace("font-size:x-large;", "")
            self.curr_html_text += '<h2 style="' + html_attrs + '">' + inner_text + "</h2>"
         #elif "text-align" in html_attrs: self.curr_html_text += '<p style="' + html_attrs + '">' + inner_text + "</p>"
         else: self.curr_html_text += '<span style="' + html_attrs + '">' + inner_text + "</span>"
      #print "###############"
      #print self.curr_html_text
      #print "###############"
   
   def rgb_to_24(self, rgb_in):
      """Convert RRRRGGGGBBBB to RRGGBB if needed"""
      if len(rgb_in) == 6: return rgb_in
      # I expect len(rgb_in) == 12
      r = int(rgb_in[:4], 16)
      g = int(rgb_in[4:8], 16)
      b = int(rgb_in[8:], 16)
      r >>= 8
      g >>= 8
      b >>= 8
      return "%.2x%.2x%.2x" % (r, g, b)
