"""
    main.py
"""

import re
import os
import sys
import cgi
import json

try:
    import pygtk
    pygtk.require("2.0")
except:
    pass

from gi.repository import Gtk, GLib

import ansi
from mainwindow import MainWindow

class Application(object):
    """
        The primary application state object.
    """

    main_window = None
    """
        The main window of the application.
    """

    aliases = None
    """
        Configurable data that should consist of only serializable data.
    """

    alias_states = None
    """
        Runtime relevant state data about each alias.
    """

    url_pattern = re.compile("https?\://([A-z]|\.|[0-9]|-|/)+")
    """
        A regular expression representing any URL. This is used to format URL's in our text output to be
        actual clickable links.
    """

    selected_alias = None
    """
        Thw name of the currently selected alias.
    """

    def main(self):
        """
            Main entry point of the application. This is called to perform initialization of the program
            state and start up the GUI.
        """

        self.config = {"aliases": {}, "triggers": {}, "ansi": {}}
        self.alias_states = {}
        GLib.idle_add(self.update)

        self.main_window = MainWindow(self)

        # Before we finally launch, load the config
        try:
            with open("config.txt", "r") as handle:
                buffer = handle.read()

                config = json.loads(buffer)

                for alias_name in config["aliases"]:
                    self.add_alias(alias_name, config["aliases"][alias_name]["address"], config["aliases"][alias_name]["password"])

                self.config = config
        except OSError:
            print("Failed to load config.")

        Gtk.main()

    def update(self):
        """
            Called to process our ongoing connections, receiving and processing any lines as necessary.
        """

        modified_current_alias = False

        for alias in self.config["aliases"]:
            if alias != "No Aliases." and self.alias_states[alias]["connection"] is not None:
                if self.alias_states[alias]["connection"].is_connected():
                    new_lines = self.alias_states[alias]["connection"].update()

                    # Once we're done updating the buffer, run formatters
                    if new_lines is not None and len(new_lines) != 0:
                        # Write to the logfile if enabled
                        if self.alias_states[alias]["logfile"] is not None:
                            """
                                This is an inefficient logging mechanism but given the nature of MUCK, this performance impact is negligable and allows
                                for log changes to appear in realtime as well as adding safety against crashes.
                            """
                            with open(self.alias_states[alias]["logfile"], "a") as handle:
                                handle.write("\n".join(new_lines))

                        for index, line in enumerate(new_lines):
                            # Escape incoming data so we don't break the markup
                            line = cgi.escape(line)

                            # Perform ANSI formatting
                            ansi_formatter = ansi.Formatter()
                            line = ansi_formatter.process_formatting(line)

                            # TODO: Configurable formatters
                            for trigger_data in self.config["triggers"].values():
                                trigger_text = trigger_data["text"]
                                trigger_color = trigger_data["color"]
                                line = line.replace(trigger_text, "<span foreground=\"%s\">%s</span>" % (trigger_color, trigger_text))

                            # Replace things that look like URL's with the href tags
                            # FIXME: Try things that look like URL's, ie: www.*
                            for match in re.finditer(self.url_pattern, line):
                                match_text = match.group(0)

                                line = line.replace(match_text, "<a href=\"%s\">%s</a>" % (match_text, match_text))

                            new_lines[index] = line
                        # Feed the modified data back to the connection
                        self.alias_states[alias]["connection"].acknowledge_lines(new_lines)

                        if self.selected_alias == alias:
                            modified_current_alias = True
                else:
                    self.alias_states[alias]["icon"].set_from_stock("gtk-dialog-error", 2)

            # If there was new text data to display, attempt to scroll the window down
            if modified_current_alias is True:
                # FIXME: Auto scroll to the bottom
                self.main_window.label_output.set_markup(self.alias_states[self.selected_alias]["connection"].buffer)
                vertical = self.main_window.scroll_window.get_vadjustment()

                vertical.set_value(vertical.get_upper() - vertical.get_page_size())

        return True

    def add_alias(self, name, address, password):
        self.alias_states[name] = {
            "connection": None,
            "icon": self.main_window.add_alias(name),
            "logfile": None,
        }

if __name__ == "__main__":
    Application().main()

@@ -169,16 +169,41 @@
 tk, GLib
+%0Aimport glib%0Aimport pango
 %0A%0Aimport
@@ -3060,24 +3060,66 @@
 ew_lines))%0A%0A
+                        output_lines = %5B%5D%0A
             
@@ -3275,24 +3275,28 @@
             
+old_
 line = cgi.e
@@ -3302,24 +3302,73 @@
 escape(line)
+%0A                            line = str(old_line)
 %0A%0A          
@@ -3553,68 +3553,8 @@
 e)%0A%0A
-                            # TODO: Configurable formatters%0A
     
@@ -3897,32 +3897,418 @@
 trigger_text))%0A%0A
+                            # FIXME: Can we validate with the damn URL's?%0A                            try:%0A                                pango.parse_markup(line)%0A                            except glib.GError as e:%0A                                print(%22An internal error has occurred. Failed to validate markup '%25s': %25s%22 %25 (line, e))%0A                                line = old_line%0A%0A
                 
@@ -4744,31 +4744,33 @@
     
-new_lines%5Bindex%5D = 
+output_lines.append(
 line
+)
 %0A   
@@ -4919,19 +4919,22 @@
 e_lines(
-new
+output
 _lines)%0A

Add some markup validation as an attempt to keep the application running if bad markup is somehow generated.