#!/usr/bin/python
# -*- coding: utf-8 -*-

#Canto - ncurses RSS reader
#   Copyright (C) 2008 Jack Miller <jack@codezen.org>
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License version 2 as 
#   published by the Free Software Foundation.

from canto.const import VERSION_TUPLE
from canto.utility import Cycle
import canto.utility as utility

import feeds
import keys
import style
import tags
import links
import hooks
import filters
import triggers
import gui
import sorts
import sources

handlers = [tags, feeds, keys, style,\
        links, hooks, filters, triggers, gui, sorts, sources]

import xml.parsers.expat
import traceback
import chardet
import codecs
import os

class Cfg:
    def __init__(self, conf, log_file, feed_dir, script_dir):
        self.precache = []
        self.locals = {}
        self.wait_for_pid = 0
        self.log_file = log_file
        self.path = conf
        self.feed_dir = feed_dir
        self.script_dir = script_dir
        self.msg_height = 1
        self.msg = None
        self.msg_tick = 0

        self.no_conf = 0

        # If we can't stat self.path, generate a default config
        # and toss a message about making your own.

        try :
            os.stat(self.path)
        except :
            try:
                # Attempt to fall back to just conf
                os.stat(self.path[:-3])
                self.path = self.path[:-3]
            except:
                print "Unable to find config file. Generating and "\
                      "using ~/.canto/conf.py.example"
                print "You will keep getting this until you create your "\
                      "own ~/.canto/conf.py"
                print "\nRemember: it's 'h' for help.\n"

                newpath = os.getenv("HOME") + "/.canto/"
                if not os.path.exists(newpath):
                    os.mkdir(newpath)

                self.path = newpath + "conf.py.example"
                f = codecs.open(self.path, "w", "UTF-8")
                f.write("# Auto-generated by canto because you don't have one.\n"
                        "# Please copy to/create ~/.canto/conf.py\n\n")
                f.write("""add("""\
                        """"http://rss.slashdot.org/slashdot/Slashdot")\n""")
                f.write("""add("""\
                        """"http://reddit.com/.rss")\n""")
                f.write("""add("""\
                        """"http://kerneltrap.org/node/feed")\n""")
                f.write("""add("""\
                        """"http://codezen.org/canto/feeds/latest")\n""")
                f.write("\n")
                f.close()
                self.no_conf = 1

    def message(self, s, time=0):
        if self.msg:
            self.default_renderer.status(self.msg, self.msg_height,\
                    self.width, s)
            if not time:
                self.msg_tick = self.default_msg_tick
            else:
                self.msg_tick = time
            self.msg.refresh()

    # Simple append log.

    def log(self, message, mode="a"):
        self.message(message)
        try:
            f = open(self.log_file, mode)
            f.write(message + "\n")
            f.close()
        except:
            pass

    def read_decode(self, filename, top_encode=0):
        enc = "utf-8"

        f = open(filename, "r")
        try:
            data = f.read()

            try:
                ret = unicode(data, enc)
            except UnicodeDecodeError:
                # If the Python built-in decoders can't figure it
                # out, it might need some help from chardet.
                enc = chardet.detect(data)["encoding"]
                ret = unicode(data, enc)
                self.log("Chardet detected encoding %s for %s" %\
                        (enc,filename))
        except :
            self.log("Failed to open config! (%s)" % sys.exc_info())
        finally:
            f.close()

        if top_encode and not ret.startswith("# -*- coding:"):
            ret = "# -*- coding: " + enc + " -*-\n" + ret

        return ret

    def parse(self, data = None):

        # The entirety of the config is read in first (rather
        # than using execfile) because the config could be in
        # some strange encoding, and execfile would choke attempting
        # to coerce some character into ASCII.

        if not data:
            data = self.read_decode(self.path, 1)

        try :
            exec(data.encode("UTF-8"), {}, self.locals)
        except :
            print "Invalid line in config."
            traceback.print_exc()
            raise

        for h in handlers:
            h.post_parse(self)

    def validate(self):
        for h in handlers:
            h.validate(self)

        for l in [self.all_sorts, self.all_filters]:
            for e in l:
                if not e:
                    continue
                for pc in e.precache:
                    if pc not in self.precache:
                        self.precache.append(pc)
        self.log("Precaching: %s" % self.precache)

def get_cfg(conf, log_file, feed_dir, script_dir):
    c = Cfg(conf, log_file, feed_dir, script_dir)
    for h in handlers:
        h.register(c)
    return c

if __name__ == "__main__":
    c = Cfg("/dev/null","/dev/null","/dev/null", "/dev/null")
    for h in handlers:
        h.register(c)
    for h in handlers:
        h.test(c)
