# -*- coding: iso-8859-1 -*-
# GNU Solfege - eartraining for GNOME
# Copyright (C) 2000, 2001  Tom Cato Amundsen
#
# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

if __name__ == '__main__':
    import pygtk
    pygtk.require("2.0")
    import sys
    sys.path.append('src')
    if 'gtkhtml' in sys.argv:
        import gtkhtml2


import sys
import gtk, pango

#gtkhtml2.gtk_html_context_get().set_property('debug-painting', 1)

import htmllib, formatter
import i18n

import string, re, os
import pyscript
import configureoutput
import cfg

class _HtmlWidgetCommon(object):
    def on_key_press_event(self, *argv):
        """
        Will be used to implement scrolling when HTML is available
        """
        pass
    def read_docfile(self, filename, locale=None):
        filefound = None
        if locale:
            languages = [locale]
        else:
            languages = i18n.langs()
        for lang in languages:
            if os.path.isfile(os.path.join('online-docs', lang, filename)):
                os.chdir(os.path.join("online-docs", lang))
                self.source(open(filename, 'r').read())
                filefound = 1
                os.chdir("../..")
                break
        if not filefound:
            for lang in languages:
                fn = os.path.join('online-docs', lang, 'missing-helpfile.html')
                if os.path.isfile(fn):
                    self.source(open(fn, 'r').read())
                    break


class Font:
    def __init__(self, *f):
        if f == None or f[0] == None or f[0][0] == None:
            self.m_size = self.m_italic = self.m_bold = self.m_teletype = None
        else:
            self.m_size, self.m_italic, self.m_bold, self.m_teletype = f[0][0]

class HTMLWriter(formatter.NullWriter):
    def __init__(self, html, activate_cb, anchor_track_cb):
        formatter.NullWriter.__init__(self)
        self.g_tw = html
        self.activate_cb = activate_cb
        self.anchor_track_cb = anchor_track_cb
        self.m_font = Font(None)
        self.m_margin = (None, 0)
        self.m_link = None
        self.m_label_data = None
        self.m_charset="ascii"
        self.m_link_list = []
        self.m_table = None
        self._para_is_new = 0
        self.m_ignore_flowing_data = 0
        self.setup_fonts()
        self.g_tw.connect('button-release-event', self.on_button_release)
    def on_button_release(self, view, event):
        ypos = event.y + self.g_tw.get_visible_rect().y
        click_pos = self.g_tw.get_iter_at_location(int(event.x), int(ypos)).get_offset()
        for href, a, b in self.m_link_list:
            if a < click_pos < b:
                self.activate_cb(href)
                break
    def register_a_ref_start(self, href):
        self.m_link_list.append([href, self.g_tw.get_buffer().get_end_iter().get_offset()])
    def register_a_ref_end(self):
        self.m_link_list[-1:][0].append(self.g_tw.get_buffer().get_end_iter().get_offset())
    def new_font(self, *f):
        self.m_font = Font(f)
    def new_margin(self, margintype, size):
        self._para_is_new = 1
        self.m_margin = margintype, size
    def send_label_data(self, label_data):
        self.m_label_data = label_data
    def start_table(self):
        #FIXME kan ikke Parser og Writer være i samme klasse, siden det ser
        # ut som mange Parser.function bare peker på Writer.function???
        #self.send_paragraph(1)
        self.send_line_break()
        self.m_table = 1
        self.m_td_string = ""
        buf = self.g_tw.get_buffer()
        it = buf.get_end_iter()
        a = buf.create_child_anchor(it)
        self.g_table_table = gtk.Table()
        self.g_table_table.set_border_width(10)
        self.g_table_table.show()
        self.g_table_table.set_col_spacings(5)
        self.g_tw.add_child_at_anchor(self.g_table_table, a)
        self.m_tableidx = [0, 0]
    def end_td(self):
        l = gtk.Label(self.m_td_string)
        l.set_use_markup(1)
        l.set_alignment(0.0, 0.5)
        l.show()
        self.g_table_table.attach(l, self.m_tableidx[0], self.m_tableidx[0]+1, self.m_tableidx[1], self.m_tableidx[1]+1)
        self.m_td_string = ""
        pass
    def send_flowing_data(self, txt):
        if self.m_ignore_flowing_data:
            return
        buf = self.g_tw.get_buffer()
        if not isinstance(txt, unicode):
           txt = txt.decode(self.m_charset, 'replace')
        txt = txt.strip('\n')
        tags = ['normal', '%s-margin%i' % self.m_margin]
        if self.m_link:
            if not self._para_is_new:
                apply(buf.insert_with_tags_by_name, [buf.get_end_iter(), ' ']+ tags)
                txt = txt.strip()
            tags.append('link')
            self._para_is_new = 0
        if self.m_label_data:
            if self.m_label_data == '*':
                txt = unichr(0x25CF) + " " + txt
            else:
                txt = self.m_label_data + " " + txt
            tags.append('li')
        if self.m_font.m_size in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6'):
            tags.append(self.m_font.m_size)
        if self.m_font.m_italic:
            tags.append('i')
        if self.m_font.m_teletype:
            tags.append('tt')
        if self.m_font.m_bold:
            tags.append('strong')
        if self.m_table:
            for t in tags:
                if t == 'strong':
                    txt = "<b>%s</b>" % txt
                if t == 'i':
                    txt = "<i>%s</i>" % txt
                if t == 'tt':
                    txt = "<tt>%s</tt>" % txt
            self.m_td_string += txt
            return
        apply(buf.insert_with_tags_by_name, [buf.get_end_iter(), txt]+ tags)
        self.m_label_data = None
    def on_anchor_event(self, eventbox, event, addr):
        if event.type == gtk.gdk.ENTER_NOTIFY:
            self.anchor_track_cb(addr)
        elif event.type == gtk.gdk.LEAVE_NOTIFY:
            self.anchor_track_cb('')
        if event.type == gtk.gdk.BUTTON_RELEASE:
            self.anchor_track_cb('')
            self.activate_cb(addr)
    def send_line_break(self):
        buf = self.g_tw.get_buffer()
        #if buf.get_end_iter().get_offset() == 0:
        #    return # FIXME this is a hack
        buf.insert(buf.get_end_iter(), "\n")
    def send_paragraph(self, n):
        self._para_is_new = 1
        self.send_line_break()
    def do_hr(self):
        buf = self.g_tw.get_buffer()
        buf.insert(buf.get_end_iter(), "\n"+"-"*90+"\n")
    def do_img(self, src, alt):
        im = gtk.Image()
        im.set_from_file(src)
        im.show()
        buf = self.g_tw.get_buffer()
        anchor = buf.create_child_anchor(buf.get_end_iter())
        self.g_tw.add_child_at_anchor(im, anchor)
        #self.send_line_break()
    def setup_fonts(self):
        b = self.g_tw.get_buffer()
        t = b.create_tag('normal')

        for n, fontsize in (1, 20), (2, 16), (3, 12), (4, 11), (5, 10), (6, 10):
            t = b.create_tag('h%i' % n)
            t.set_property('font', 'Sans %i' % fontsize)
            t.set_property('weight', pango.WEIGHT_BOLD)

        t = b.create_tag('i')
        t.set_property('style', pango.STYLE_ITALIC)

        t = b.create_tag('tt')
        t.set_property('font', 'Monospace')

        t = b.create_tag('strong')
        t.set_property('weight', pango.WEIGHT_BOLD)

        t = b.create_tag('link')
        t.set_property('foreground', 'blue')
        t.set_property('underline', 'single')

        t = b.create_tag('li')
        t.set_property('indent', -12)

        for n in range(10):#FIXME numeric constant
            t = b.create_tag('dd-margin%i' % n)
            t.set_property('left-margin', n*40+20)

        for n in range(10):#FIXME numeric constant
            t = b.create_tag('None-margin%i' % n)
            t.set_property('left-margin', n*20+10)

        for n in range(10):#FIXME numeric constant
            t = b.create_tag('ul-margin%i' % n)
            t.set_property('left-margin', n*20+10)

        for n in range(10):#FIXME numeric constant
            t = b.create_tag('ol-margin%i' % n)
            t.set_property('left-margin', n*20+10)


class MyHTMLParser(htmllib.HTMLParser):
    def __init__(self, formatter, writer):
        htmllib.HTMLParser.__init__(self, formatter)
        self.m_formatter = formatter
        self.m_writer = writer
    def start_style(self, attributes):
        self.m_formatter.writer.m_ignore_flowing_data = 1
    def end_style(self):
        self.m_formatter.writer.m_ignore_flowing_data = 0
    def do_meta(self, attributes):
        http_equiv = None
        content = None
        for n, c in attributes:
            if n == 'http-equiv':
                http_equiv = c
            elif n == 'content':
                content = c
        if not http_equiv:
            return
        if http_equiv.upper() == 'CONTENT-TYPE':
            v = content.split()
            # UGH
            for s in v:
                v2 = s.split('=')
                if len(v2) == 2:
                    if v2[0].upper() == 'CHARSET':
                        self.m_formatter.writer.m_charset = v2[1]
                        break
    def do_hr(self, x):
        self.m_formatter.writer.do_hr()
    def start_a(self, *v):
        if v[0][0][0] == 'href':
            self.m_writer.register_a_ref_start(v[0][0][1])
            self.m_writer.m_link = v[0][0][1]
    def end_a(self):
        if self.m_writer.m_link is not None:
            self.m_writer.m_link = None
            self.m_writer.register_a_ref_end()
    def start_pre(self, *v):
        self.nofill=1
        self.save_bgn()
    def end_pre(self, *v):
        self.m_formatter.push_font(('', 0, 0, 1))
        self.m_formatter.writer.send_line_break()
        self.m_formatter.writer.send_flowing_data(self.save_end())
        self.m_formatter.writer.send_line_break()
        self.m_formatter.pop_font()
        self.nofill=0
    def do_img(self, v):
        alt = ""
        src = ""
        for x in v:
            if x[0] == 'src':
                src = x[1]
            elif x[0] == 'alt':
                alt = x[1]
        self.m_formatter.writer.do_img(src, alt)
    def start_table(self, *v):
        self.m_writer.start_table()
        self.m_writer.m_table = 1
    def end_table(self, *v):
        self.m_writer.m_table = 0
        self.m_writer.send_line_break()
    def start_tr(self, *v):
        """This empty function must exist to make the parser call end_tr."""
        pass
    def end_tr(self, *v):
        self.m_writer.m_tableidx[1] += 1
        self.m_writer.m_tableidx[0] = 0
    def start_td(self, *x):
        """This empty function must exist to make the parser call end_td."""
        pass
    def end_td(self, *v):
        self.m_writer.m_tableidx[0] += 1
        self.m_writer.end_td()

class TextViewHtmlWidget(gtk.ScrolledWindow, _HtmlWidgetCommon):
    def __init__(self, activate_cb, anchor_track_cb):
        gtk.ScrolledWindow.__init__(self)
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.g_tw = gtk.TextView()
        self.writer = HTMLWriter(self.g_tw, activate_cb, anchor_track_cb)
        self.formatter = formatter.AbstractFormatter(self.writer)
        self.parser = MyHTMLParser(self.formatter, self.writer)
        self.g_tw.set_editable(0)
        self.g_tw.set_cursor_visible(0)
        self.g_tw.set_wrap_mode(gtk.WRAP_WORD)
        self.add(self.g_tw)
        self.idx = 0
        self.m_pyscript = pyscript.PyScript()
        self.grab_focus = self.g_tw.grab_focus
    def source(self, txt):
        self.writer.m_link_list = []
        txt = self.m_pyscript.evaluate(txt)
        buf = self.g_tw.get_buffer()
        it_a = buf.get_start_iter()
        it_b = buf.get_end_iter()
        buf.delete(it_a, it_b)
        self.parser.feed(txt)
        buf.place_cursor(buf.get_start_iter())

class GtkHtml2Widget(gtk.ScrolledWindow, _HtmlWidgetCommon):
    def __init__(self, activate_cb, anchor_track_cb):
        gtk.ScrolledWindow.__init__(self)
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.activate_cb = activate_cb
        self.anchor_track_cb = anchor_track_cb
        self.g_document = gtkhtml2.Document()
        self.g_view = gtkhtml2.View()
        self.set_hadjustment(self.g_view.get_hadjustment())
        self.set_vadjustment(self.g_view.get_vadjustment())
        self.add(self.g_view)
        self.g_view.set_document(self.g_document)
        self.g_document.connect('link_clicked',
                 lambda widget, url: self.activate_cb(url))
        self.g_document.connect('request_url', self.on_request_url)
        if self.anchor_track_cb:
            self.g_view.connect('on-url', lambda f, url: self.anchor_track_cb(url))
        self.grab_focus = self.g_view.grab_focus
    def on_request_url(self, document, url, stream):
        #if url == "style.css":
        #    stream.set_mime_type("text/css")
        #    print stream.get_mime_type()
        s = open(url, 'r').read()
        stream.write(s)
    def source(self, html):
        self.g_document.clear()
        self.g_document.open_stream("text/html")
        self.g_document.write_stream(html)
        self.g_document.close_stream()

def _test():
    import gettext
    gettext.install('solfege', 'share/locale', unicode=1)
    sys.path.insert(0, ".")
    import gtk
    w = gtk.Window()
    w.set_size_request(300, 400)
    def activate_cb(*v):
        print "ACTIVATE_CB", v
    def anchor_track_cb(*v):
        print "ANCHOR_TRACK_CB", v
    if 'textview' in sys.argv:
        h = TextViewHtmlWidget(activate_cb, anchor_track_cb)
    elif 'gtkhtml' in sys.argv:
        h = GtkHtml2Widget(activate_cb, anchor_track_cb)
    else:
        h = HtmlWidget(activate_cb, anchor_track_cb)
    s = """
<html>
<head>
<style type="text/css">
h1 { font-weight: bold; font-size: 2em;    margin: 0.67em 0 0;}
h2 { font-weight: bold; font-size: 1.5em;  margin: 0.83em 0 0;}
h3 { font-weight: bold; font-size: 1.17em; margin: 1em 0 0;}
h4 { font-weight: bold;                    margin: 1.33em 0 0;}
tt { font-family: courier; }
.programlisting { background: #ccc; }
p + div > dl {
 margin-top: 0;
 }
dd { margin-left: 50px; }
</head>
<body>
<h1>Heading 1 <i>italic</i> <tt>teletype</tt></h1>
<h2>Heading 2 <i>italic</i> <tt>teletype</tt></h2>
<h3>Heading 3 <i>italic</i> <tt>teletype</tt></h3>
<h4>Heading 4 <i>italic</i> <tt>teletype</tt></h4>
<h5>Heading 5 <i>italic</i> <tt>teletype</tt></h5>
        <div class="itemizedlist">
          <ul type="disc">
            <li>
              <p>
                Nytt intervall:
                <b class="keycap">Alt</b>-<b class="keycap">n</b>
              </p>
            </li>
            <li>
              <p>
                Repeter:
                <b class="keycap">Alt</b>-<b class="keycap">r</b>
              </p>
            </li>
            <li>
              <p>
                Repeter melodisk:
                <b class="keycap">Alt</b>-<b class="keycap">m</b>
              </p>
            </li>
            <li>
              <p>
                Gi opp:
                <b class="keycap">Alt</b>-<b class="keycap">g</b>
              </p>
            </li>
          </ul>
        </div>
        <div class="table">
          <a name="id2879544" id="id2879544"></a>
          <p class="title_c2">
            Tabell 2.1. Taster brukt til &Atilde;&yen; identifisere
            intervaller
          </p>

          <table summary="Taster brukt til &Atilde;&yen; identifisere intervaller"
                 border="1">
            <colgroup>
              <col />
              <col />
            </colgroup>
            <tbody>
              <tr>
                <td align="left">
                  Liten sekund: <b class="keycap">1</b>
                </td>
                <td align="left">
                  Ren kvart: <b class="keycap">2</b>
                </td>
                <td align="left">
                  Stor sekst: <b class="keycap">3</b>
                </td>
                <td align="left">
                  Liten none: <b class="keycap">4</b>
                </td>
              </tr>
              <tr>
                <td align="left">
                  Stor sekund: <b class="keycap">q</b>
                </td>
                <td align="left">
                  Forminsket kvint: <b class="keycap">w</b>
                </td>
                <td align="left">
                  Liten septim: <b class="keycap">e</b>
                </td>
                <td align="left">
                  Stor none: <b class="keycap">r</b>
                </td>
              </tr>
              <tr>
                <td align="left">
                  Liten ters: <b class="keycap">a</b>
                </td>
                <td align="left">
                  Ren kvint: <b class="keycap">s</b>
                </td>
                <td align="left">
                  Stor septim: <b class="keycap">d</b>
                </td>
                <td align="left">
                  Liten desim: <b class="keycap">f</b>
                </td>
              </tr>
              <tr>
                <td align="left">
                  Stor ters: <b class="keycap">z</b>
                </td>
                <td align="left">
                  Liten sekst: <b class="keycap">x</b>
                </td>
                <td align="left">
                  Ren oktav: <b class="keycap">c</b>
                </td>
                <td align="left">
                  Stor desim: <b class="keycap">v</b>
                </td>
              </tr>
            </tbody>
          </table>
</div>

<h6>Heading 6 <i>italic</i> <tt>teletype</tt></h6>

Some words in <i>italic</i> and <tt>teletype</tt>.
<table summary="blabla">
<colgroup>
  <col />
  <col />
</colgroup>
<tbody>
<td>non-bold <b>BOLD</b>
</td><td>BBB</td>
<td>CCC</td></tr>
<tr><td>AAA</td><td>BBB</td><td>CCC</td></tr>
</tbody>
</table>

En <a href=" "> link </a> her
  This is a paragraph with a <a href="addr1">link</a> in the middle
  of a sentence.

<p>Definition list:</p>
<div class="val">
<dl>
  <dt>Term 1</dt>
  <dd>Definition data 1</dd>
  <dt>Term 2</dt>
  <dd>Definition data 2</dd>
  <dt>Term 3</dt>
  <dd>Definition data 3</dd>
</dl>
</div>
<p>paragraph</p>

<dl>
    <dt>Definition term 1</dt>

    <dd>Definition description 1</dd>
    <dt>Definition term 2</dt>
    <dd>
        <dl>
            <dt>Definition term 1 - 2</dt>
            <dd>Definition description 1 - 2</dd>
            <dt>Definition term 2 - 2</dt>
            <dd>Definition description 2 - 2</dd>
            <dt>Definition term 3 - 2</dt>
            <dd>Definition description 3 - 2</dd>
        </dl>
    </dd>
    <dt>Definition term 3</dt>
    <dd>Definition description 3</dd>
</dl> 

<p>This is a paragraph</p>  

<p>Simple bullet list:</p>
<ul><li>en alkdsj alksj dflkajsd lja dlkl kdalkdj alskd laksdj falksd flaksd 
 askldj falksjd flaksj laksj lkajd lfkald kfajldf
<li>to
<li>tre
</ul>

<p>Simple bullet list:</p>
<ul>
<li>ben</li>
<li>bto
    bla bla bla bla bla bla bla bla bla bla bla bla
    bla bla bla bla bla bla bla bla bla bla bla bla
</li>
<li>
    <ul>
        <li>bhei-1</li>
        <li>bhei-2
            bla bla bla bla bla bla bla bla bla bla bla bla
            bla bla bla bla bla bla bla bla bla bla bla bla
        <li>
            <ul>
                <li>btre-1</li>
                <li>btre-2 
                    bla bla bla bla bla bla bla bla bla bla bla bla
                    bla bla bla bla bla bla bla bla bla bla bla bla
                </li>
                <li>tre-3</li>
            </ul>
        </li>
    </ul>
<li>tre
</ul>

<p>Font styles: <i>italics</i>, <tt>tt (fixed)</tt>
</p>
<p>Another paragraph with another ABC<a href="addr2">link</a>DEF.</p>
</body></html>

"""
    if sys.argv[-1:][0].endswith('.html'):
        s = file(sys.argv[-1:][0]).read()
    h.source(s)
    w.add(h)
    w.show_all()
    w.connect('destroy', gtk.mainquit)
    gtk.mainloop()

if configureoutput.WITH_GTKHTML:
    import gtkhtml2
    HtmlWidget = GtkHtml2Widget
else:
    HtmlWidget = TextViewHtmlWidget

if __name__ == '__main__':
    _test()


