def gtk_treeview_search_cb_stristr(model, column, key, iter, data=None):
    value = model.get_value(iter, column)
    if value.lower().find(key.lower()) > -1:
        return False
    else:
        return True

class plugin_FlexRSS_Config:
    constants = {
        'Generic'         : 0,
        'TV Show'         : 1,
        'TV Show (dated)' : 2 }
    feeds_counter = 0
    filters_counter = 0
    feeds = None
    filters = None
    version = 0
    show_toolbar_button = False
    threaded_retrieval = False

    def getFilter(self, id):
        if not self.filters:
            return None

        for filter in self.filters:
            if filter['id'] == id:
                return filter

        return None

    def setFilter(self, id, key, value):
        filter = self.getFilter(id)

        if not filter:
            return False
        else:
            filter[key] = value
            return True

    def addFilter(self, name, type, patterns, feeds):
        id = self.feeds_counter + 1
        self.feeds_counter = id

        if not self.filters:
            self.filters = []

        filter = { "id"       : id,
                   "name"     : name,
                   "type"     : type,
                   "patterns" : patterns,
                   "feeds"    : feeds,
                   "history"  : {},
                   "path"     : None,
                   "enabled"  : True,
                   "queue_top": False,
                   "pause"    : False,
                   "delete"   : False}

        self.filters.append(filter)

        return id

    def deleteFilter(self, id):
        if not self.filters:
            return False

        i = 0
        while i < len(self.filters):
            if self.filters[i]['id'] == id:
                del self.filters[i]
                return True
            i = i + 1

    def checkHistory(self, id, type, data):
        filter = self.getFilter(id)

        if not filter:
            return False

        try:
            if type == self.constants['TV Show']:
                filter['history'][type][data['series']].index(data['episode'])
                return True
            elif type == self.constants['TV Show (dated)']:
                filter['history'][type][data['year']][data['month']].index(data['day'])
                return True
            else:
                filter['history'][type].index(data['url'])
                return True
        except:
            return False

    def checkRange(self, id, type, data):
        filter = self.getFilter(id)

        if not filter:
            return False

        if type == self.constants['TV Show']:
            if filter['history'][type].has_key('from'):
                if data['series'] < filter['history'][type]['from']['season']:
                    return False
                elif data['series'] == filter['history'][type]['from']['season']:
                    if data['episode'] < filter['history'][type]['from']['episode']:
                        return False

            if filter['history'][type].has_key('thru'):
                if data['series'] > filter['history'][type]['thru']['season']:
                    return False
                elif data['series'] == filter['history'][type]['thru']['season']:
                    if data['episode'] > filter['history'][type]['thru']['episode']:
                        return False

            return True

        elif type == self.constants['TV Show (dated)']:
            if filter['history'][type].has_key('from'):
                if data['year'] < filter['history'][type]['from']['year']:
                    return False
                elif data['year'] == filter['history'][type]['from']['year']:
                    if data['month'] < filter['history'][type]['from']['month']:
                        return False
                    elif data['month'] == filter['history'][type]['from']['month']:
                        if data['day'] < filter['history'][type]['from']['day']:
                            return False

            if filter['history'][type].has_key('thru'):
                if data['year'] > filter['history'][type]['thru']['year']:
                    return False
                elif data['year'] == filter['history'][type]['thru']['year']:
                    if data['month'] > filter['history'][type]['thru']['month']:
                        return False
                    elif data['month'] == filter['history'][type]['thru']['month']:
                        if data['day'] > filter['history'][type]['thru']['day']:
                            return False

            return True

        else:
            return True

    def addHistory(self, id, type, data):
        filter = self.getFilter(id)

        if not filter:
            return False

        if type == self.constants['TV Show']:
            if not filter['history'].has_key(type):
                filter['history'][type] = {}
            if not filter['history'][type].has_key(data['series']):
                filter['history'][type][data['series']] = []
            filter['history'][type][data['series']].append(data['episode'])
        elif type == self.constants['TV Show (dated)']:
            if not filter['history'].has_key(type):
                filter['history'][type] = {}
            if not filter['history'][type].has_key(data['year']):
                filter['history'][type][data['year']] = {}
            if not filter['history'][type][data['year']].has_key(data['month']):
                filter['history'][type][data['year']][data['month']] = []
            filter['history'][type][data['year']][data['month']].append(data['day'])
        else:
            if not filter['history'].has_key(type):
                filter['history'][type] = []
            try:
                filter['history'][type].append(data['url'])
            except AttributeError, e:
                filter['history'][type] = [data['url']]

    def getFeed(self, id):
        if not self.feeds:
            return None

        for feed in self.feeds:
            if feed['id'] == id:
                return feed

        return None

    def setFeed(self, id, key, value):
        feed = self.getFeed(id)

        if not feed:
            return False
        else:
            feed[key] = value
            return True

    def addFeed(self, name, url, interval):
        # Uhhh... no ++? WTF is the increment operator?
        id = self.feeds_counter + 1
        self.feeds_counter = id

        if not self.feeds:
            self.feeds = []

        self.feeds.append({ "id"       : id,
                            "name"     : name,
                            "url"      : url,
                            "interval" : interval,
                            "enabled"  : True })

        return id

    def deleteFeed(self, id):
        if not self.feeds:
            return False

        i = 0
        while i < len(self.feeds):
            if self.feeds[i]['id'] == id:
                del self.feeds[i]
                return True
            i = i + 1

class plugin_FlexRSS:
    config = None
    glade = None
    feeds = None
    toolbar_button = None
    history_calendarbuttons = None

    def update_config(self):
        if self.config.version >= 5:
            return

        if self.config.version < 1:
            print 'Updating config to v1'
            i = 0
            while i < len(self.config.filters):
                self.config.filters[i]['enabled'] = True
                i = i + 1

        if self.config.version < 2:
            print 'Updating config to v2'
            i = 0
            while i < len(self.config.feeds):
                self.config.feeds[i]['enabled'] = True
                i = i + 1

        if self.config.version < 3:
            print 'Updating config to v3'
            i = 0
            while i < len(self.config.filters):
                type_s = self.config.filters[i]['type']
                type_i = self.config.constants[type_s]
                if self.config.filters[i]['history'].has_key(type_s):
                    history = { type_i: self.config.filters[i]['history'][type_s] }
                    self.config.filters[i]['history'] = history
                self.config.filters[i]['type'] = self.config.constants[self.config.filters[i]['type']];
                i = i + 1

        if self.config.version < 4:
            print 'Updating config to v4'
            i = 0
            while i < len(self.config.filters):
                self.config.filters[i]['queue_top'] = False
                self.config.filters[i]['pause'] = False
                i = i + 1

        if self.config.version < 5:
            print 'Updating config to v5'
            i = 0
            while i < len(self.config.filters):
                self.config.filters[i]['delete'] = False
                i = i + 1

        self.config.version = 5
        self.write_config()

    def load_config(self):
        import deluge.common, os, cookielib

        file = deluge.common.CONFIG_DIR + "/flexrss.dat"
        if os.path.isfile(file):
            import pickle

            fd = open(file, 'r')
            self.config = pickle.load(fd)
            fd.close()
        else:
            self.config = plugin_FlexRSS_Config()
            self.config.version = 5

        self.update_config()

        cookie_file = deluge.common.CONFIG_DIR + "/flexrss-cookies.txt"
        self.cookies = cookielib.MozillaCookieJar()
        if os.path.isfile(cookie_file):
            self.cookies.load(cookie_file)

    def write_config(self, write_cookies=False):
        import deluge.common, os, pickle

        file = deluge.common.CONFIG_DIR + "/flexrss.dat"
        fd = open(file, 'w')
        pickle.dump(self.config, fd)
        fd.close()

        if write_cookies:
            print "Saving cookies."
            self.cookies.save(deluge.common.CONFIG_DIR + "/flexrss-cookies.txt")

    def configure_cb_closed(self, args):
        self.glade = None
        self.history_calendarbuttons = None

    def configure_cb_feed_new(self, args):
        feed = { "name"     : 'Untitled',
                 "url"      : 'http://',
                 "interval" : 900,
                 "id"       : 0 }

        feed["id"] = self.config.addFeed(feed["name"], feed["url"], feed["interval"])

        view = self.glade.get_widget("FlexRSS_Feeds")
        model = view.get_model()
        view.get_selection().select_iter(model.append(None, (feed["id"], feed["name"], feed["url"])))

    def configure_cb_feed_selected(self, selection):
        model, iter = selection.get_selected()

        if not iter:
            return

        parent = model.iter_parent(iter)
        if parent: # Selected a filter
            self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(model.get_value(iter, 1))
            self.configure_cb_test_filter(None)

            iter = parent

        # We want to edit a feed.
        feed = self.config.getFeed(model.get_value(iter, 0))
        if not feed:
            print 'Error: could not find feed #' + str(model.get_value(iter, 0))
            return

        self.glade.get_widget("FlexRSS_EditFeed_Name").set_text(feed["name"])
        self.glade.get_widget("FlexRSS_EditFeed_URL").set_text(feed["url"])
        self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text(str(feed["interval"]))
        if feed["enabled"] == True:
            self.glade.get_widget("FlexRSS_EditFeed_Status_Enabled").set_active(True)
        else:
            self.glade.get_widget("FlexRSS_EditFeed_Status_Disabled").set_active(True)
        self.glade.get_widget('FlexRSS_Feeds_Editor').show()

    def configure_cb_feed_delete(self, arg, id=None):
        if not id:
            # Which feed is selected?
            selection = self.glade.get_widget("FlexRSS_Feeds").get_selection()
            model, iter = selection.get_selected()

            if not iter:
                return

            id = model.get_value(iter, 0)
            if id == 0:
                id = model.get_value(model.iter_parent(iter), 0)
        else:
            model = self.glade.get_widget("FlexRSS_Feeds").get_model()
            iter = model.get_iter_first()
            while iter:
                if model.get_value(iter, 0) == id:
                    break
                iter = model.iter_next(iter)

        if not iter:
            print 'Couldn\'t find feed.'
            return

        # Remove from config
        if not self.config.deleteFeed(id):
            print 'Unable to delete feed #' + str(id)
            return

        # Remove from UI
        model.remove(iter)

        self.write_config()

        # We are no longer editing a feed, so hide the editing widgets.
        self.glade.get_widget('FlexRSS_Feeds_Editor').hide()

    def configure_cb_feed_save(self, arg, id=None):
        if not id:
            # Which feed is selected?
            selection = self.glade.get_widget("FlexRSS_Feeds").get_selection()
            model, iter = selection.get_selected()

            if not iter:
                return

            id = model.get_value(iter, 0)
            if id == 0:
                iter = model.iter_parent(iter)
                id = model.get_value(iter, 0)
        else:
            model = self.glade.get_widget("FlexRSS_Feeds").get_model()
            iter = model.iter_first()
            while iter:
                if model.get_value(iter, 0) == id:
                    break
                iter = iter.iter_next(iter)

        if not iter:
            print 'Couldn\'t find feed.'
            return

        # Update configuration
        self.config.setFeed(id, "name", self.glade.get_widget("FlexRSS_EditFeed_Name").get_text())
        self.config.setFeed(id, "url", self.glade.get_widget("FlexRSS_EditFeed_URL").get_text())
        interval = self.configure_ui_get_text_as_int("FlexRSS_EditFeed_Interval", 900)
        if interval < 300:
            # It's just not polite to hit a server that often.
            self.glade.get_widget("FlexRSS_EditFeed_Interval").set_text('300')
            interval = 300
        self.config.setFeed(id, "interval", interval)
        self.config.setFeed(id, "enabled", self.glade.get_widget("FlexRSS_EditFeed_Status_Enabled").get_active())
        self.write_config()

        # Update UI
        feed = self.config.getFeed(id)
        model.set_value(iter, 0, feed["id"])
        model.set_value(iter, 1, feed["name"])
        model.set_value(iter, 2, feed["url"])

        if not self.feeds.has_key(id):
            self.feeds[id] = { 'cfg'     : feed,
                               'updated' : 0,
                               'data'    : [] }

    def escape_regex_special_chars(self, pattern):
        escape_chars = '[]()^$\\.?*+|'
        out = []
        for c in pattern:
            try:
                escape_chars.index(c)
                out.append('\\' + c)
            except:
                out.append(c)
        return ''.join(out)

    def configure_cb_filter_new(self, arg, test_pattern=None):
        filter = { "name"     : "Untitled",
                   "type"     : "Generic",
                   "patterns" : [('', 'Title')],
                   "feeds"    : [0],
                   "id"       : 0 }

        if test_pattern:
            # Try to guess a good pattern
            import re, string

            trans_table = string.maketrans(' ', '.')

            # TV Show
            exp = re.compile(r'(.*?)S([0-9]+)E([0-9]+)', re.IGNORECASE)
            match = exp.match(test_pattern)
            if match:
                pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + 's%se%e'
                filter['patterns'][0] = (pattern, 'Title')
                filter['name'] = match.group(1)
                filter['type'] = self.config.constants['TV Show']

            if not match:
                exp = re.compile(r'(.*?)([0-9]{4}).([0-9]{1,2}).([0-9]{1,2})', re.IGNORECASE)
                match = exp.match(test_pattern)
                if match:
                    pattern = None
                    if ((int(match.group(3)) <= 12) and (int(match.group(4)) <= 31)):
                        pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%Y.%m.%d'
                    elif ((int(match.group(3)) <= 31) and (int(match.group(4)) <= 12)):
                        pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%Y.%d.%m'

                    if pattern:
                        filter['patterns'][0] = (pattern, 'Title')
                        filter['name'] = match.group(1)
                        filter['type'] = self.config.constants['TV Show (dated)']
                    else:
                        match = None

            if not match:
                exp = re.compile(r'(.*?)([0-9]{2}).([0-9]{2}).([0-9]{2})', re.IGNORECASE)
                match = exp.match(test_pattern)
                if match:
                    pattern = None
                    if ((int(match.group(2)) <= 12) and (int(match.group(3)) <= 31)):
                        pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%m.%d.%y'
                    elif ((int(match.group(3)) <= 31) and (int(match.group(2)) <= 12)):
                        pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%d.%m.%y'

                    if pattern:
                        filter['patterns'][0] = (pattern, 'Title')
                        filter['name'] = match.group(1)
                        filter['type'] = self.config.constants['TV Show (dated)']
                    else:
                        match = None

            if not match:
                exp = re.compile(r'(.*?)([0-9]+)([x\.\-_]{1})([0-9]+)', re.IGNORECASE)
                match = exp.match(test_pattern)
                if match:
                    pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%s' + self.escape_regex_special_chars(match.group(3)) + '%e'
                    filter['patterns'][0] = (pattern, 'Title')
                    filter['name'] = match.group(1)
                    filter['type'] = self.config.constants['TV Show']

            if not match:
                exp = re.compile(r'(.*?)([0-9]+)$', re.IGNORECASE)
                match = exp.match(test_pattern)
                if match:
                    pattern = self.escape_regex_special_chars(match.group(1)).lower().translate(trans_table) + '%e'
                    filter['patterns'][0] = (pattern, 'Title')
                    filter['name'] = match.group(1)
                    filter['type'] = self.config.constants['TV Show']

        # Add to config
        filter['id'] = self.config.addFilter(filter['name'], filter['type'], filter['patterns'], [0])

        # Add to UI
        self.configure_ui_add_filter(self.config.getFilter(filter['id']), test_pattern)

    def configure_cb_filter_selected(self, selection):
        model, iter = selection.get_selected()

        if not iter:
            return

        # We want to edit a filter.
        filter = self.config.getFilter(model.get_value(iter, 0))
        if not filter:
            print 'Error: could not find filter #' + str(model.get_value(iter, 0))
            return

        self.configure_ui_reset_filter()

        self.glade.get_widget('FlexRSS_Filters_Name').set_text(filter['name'])

        if filter['type'] == self.config.constants['TV Show']:
            type_i = 1
        elif filter['type'] == self.config.constants['TV Show (dated)']:
            type_i = 2
        else:
            type_i = 0

        self.glade.get_widget('FlexRSS_Filters_Type').set_active(type_i)

        selection = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection()
        selection.unselect_all()
        feed_model = self.glade.get_widget('FlexRSS_Filters_Feed').get_model()
        for i in filter['feeds']:
            if i == 0:
                selection.select_all()
            else:
                iter = feed_model.get_iter_first()
                while iter:
                    if feed_model.get_value(iter, 0) == i:
                        selection.select_iter(iter)
                    iter = feed_model.iter_next(iter)

        for pattern in filter['patterns']:
            self.configure_ui_add_pattern(pattern)

        if filter['type'] == self.config.constants['TV Show']:
            if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('from'):
                self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').set_active(True)
                self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(True)
                self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(True)
                self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_text(str(filter['history'][filter['type']]['from']['season']))
                self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_text(str(filter['history'][filter['type']]['from']['episode']))
            else:
                self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').set_active(False)
                self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(False)
                self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(False)
                self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_text('0')
                self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_text('0')

            if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('thru'):
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').set_active(True)
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(True)
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(True)
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_text(str(filter['history'][filter['type']]['thru']['season']))
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_text(str(filter['history'][filter['type']]['thru']['episode']))
            else:
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').set_active(False)
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(False)
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(False)
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_text('0')
                self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_text('0')

            self.glade.get_widget("FlexRSS_History_TVShow_Dated").hide()
            self.glade.get_widget("FlexRSS_History_TVShow").show()
            self.glade.get_widget("FlexRSS_Filter_History_Range").show()
        elif filter['type'] == self.config.constants['TV Show (dated)']:
            import time

            cal_from, cal_thru = self.history_calendarbuttons
            today = time.localtime()

            if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('from'):
                self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').set_active(True)
                cal_from.set_sensitive(True)
                cal_from.set_date(filter['history'][filter['type']]['from']['year'],
                                  filter['history'][filter['type']]['from']['month'],
                                  filter['history'][filter['type']]['from']['day'])
            else:
                self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').set_active(False)
                cal_from.set_sensitive(False)
                cal_from.set_date(today[0], today[1], today[2])

            if filter['history'].has_key(filter['type']) and filter['history'][filter['type']].has_key('thru'):
                self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').set_active(True)
                cal_thru.set_sensitive(True)
                cal_thru.set_date(filter['history'][filter['type']]['thru']['year'],
                                  filter['history'][filter['type']]['thru']['month'],
                                  filter['history'][filter['type']]['thru']['day'])
            else:
                self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').set_active(False)
                cal_thru.set_sensitive(False)
                cal_thru.set_date(today[0], today[1], today[2])

            self.glade.get_widget("FlexRSS_History_TVShow").hide()
            self.glade.get_widget("FlexRSS_History_TVShow_Dated").show()
            self.glade.get_widget("FlexRSS_Filter_History_Range").show()
        else:
            self.glade.get_widget("FlexRSS_History_TVShow").hide()
            self.glade.get_widget("FlexRSS_History_TVShow_Dated").hide()
            self.glade.get_widget("FlexRSS_Filter_History_Range").hide()

        self.glade.get_widget('FlexRSS_Filter_Download_QueueTop').set_active(filter.get('queue_top', False))
        self.glade.get_widget('FlexRSS_Filter_Download_Pause').set_active(filter.get('pause', False))
        self.glade.get_widget('FlexRSS_Filter_Download_Delete').set_active(filter.get('delete', False))

        self.configure_cb_test_filter(None)

        if filter['path'] != None:
            self.glade.get_widget('FlexRSS_Filter_Output_Location').set_current_folder(filter['path'])
            self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').set_active(True)
        else:
            self.glade.get_widget('FlexRSS_Filter_Output_Type_Default').set_active(True)

        replace = filter.get('replace', {'pattern': '', 'with': ''})
        self.glade.get_widget('FlexRSS_Filter_Rewrite_Pattern').set_text(replace['pattern'])
        self.glade.get_widget('FlexRSS_Filter_Rewrite_Replacement').set_text(replace['with'])

    def configure_cb_filter_history_toggle(self, box):
        name = box.get_name()
        active = box.get_active()

        if name == 'FlexRSS_History_TVShow_From_Enabled':
            self.glade.get_widget('FlexRSS_History_TVShow_From_Season').set_sensitive(active)
            self.glade.get_widget('FlexRSS_History_TVShow_From_Episode').set_sensitive(active)
        elif name == 'FlexRSS_History_TVShow_Thru_Enabled':
            self.glade.get_widget('FlexRSS_History_TVShow_Thru_Season').set_sensitive(active)
            self.glade.get_widget('FlexRSS_History_TVShow_Thru_Episode').set_sensitive(active)
        elif name == 'FlexRSS_History_TVShow_Dated_From_Enabled':
            self.history_calendarbuttons[0].set_sensitive(active)
        elif name == 'FlexRSS_History_TVShow_Dated_Thru_Enabled':
            self.history_calendarbuttons[1].set_sensitive(active)

        self.configure_cb_test_filter(None)

    def configure_ui_get_text_as_int(self, widget_name, default=0):
        try:
            return int(self.glade.get_widget(widget_name).get_text())
        except:
            return default

    def configure_ui_get_history_restriction(self):
        h_from = None
        h_thru = None

        type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()
        if type == 1:
            type_s = self.config.constants['TV Show']
        elif type == 2:
            type_s = self.config.constants['TV Show (dated)']
        else:
            type_s = self.config.constants['Generic']

        if type_s == self.config.constants['TV Show']:
            if self.glade.get_widget('FlexRSS_History_TVShow_From_Enabled').get_active():
                from_season = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_From_Season')
                from_episode = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_From_Episode')
                h_from = {'season': from_season, 'episode': from_episode}
        elif type_s == self.config.constants['TV Show (dated)']:
            if self.glade.get_widget('FlexRSS_History_TVShow_Dated_From_Enabled').get_active():
                from_y, from_m, from_d = self.history_calendarbuttons[0].get_date()
                h_from = {'year': from_y, 'month': from_m, 'day': from_d}

        if type_s == self.config.constants['TV Show']:
            if self.glade.get_widget('FlexRSS_History_TVShow_Thru_Enabled').get_active():
                thru_season = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_Thru_Season')
                thru_episode = self.configure_ui_get_text_as_int('FlexRSS_History_TVShow_Thru_Episode')
                h_thru = {'season': thru_season, 'episode': thru_episode}
        elif type_s == self.config.constants['TV Show (dated)']:
            if self.glade.get_widget('FlexRSS_History_TVShow_Dated_Thru_Enabled').get_active():
                thru_y, thru_m, thru_d = self.history_calendarbuttons[1].get_date()
                h_thru = {'year': thru_y, 'month': thru_m, 'day': thru_d}

        return (h_from, h_thru)

    def configure_cb_filter_save(self, arg):
        # Which feed is selected?
        selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection()
        model, iter = selection.get_selected()

        if not iter:
            return

        id = model.get_value(iter, 0)
        name = self.glade.get_widget('FlexRSS_Filters_Name').get_text()
        self.config.setFilter(id, 'name', name)
        iter = model.get_iter_first()
        while iter:
            if model.get_value(iter, 0) == id:
                model.set_value(iter, 1, name)
            iter = model.iter_next(iter)

        type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()
        if type == 1:
            type_s = self.config.constants['TV Show']
        elif type == 2:
            type_s = self.config.constants['TV Show (dated)']
        else:
            type_s = self.config.constants['Generic']
        self.config.setFilter(id, 'type', type_s)

        model, paths = self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().get_selected_rows()
        feeds = []
        for path in paths:
            feeds.append(model.get_value(model.get_iter(path), 0))
        if len(feeds) == 0:
            feeds.append(0)
        self.config.setFilter(id, 'feeds', feeds)

        patterns = []
        filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')
        for i in filter_patterns.get_children():
            data = i.get_children()
            pattern = data[0].get_text()
            if data[2].get_active() == 1:
                type = 'Link'
            else:
                type = 'Title'
            patterns.append((pattern, type))
        self.config.setFilter(id, 'patterns', patterns)

        if self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').get_active():
            path = self.glade.get_widget('FlexRSS_Filter_Output_Location').get_current_folder()
        else:
            path = None

        self.config.setFilter(id, 'path', path)

        self.config.setFilter(id, 'queue_top', self.glade.get_widget('FlexRSS_Filter_Download_QueueTop').get_active())
        self.config.setFilter(id, 'pause', self.glade.get_widget('FlexRSS_Filter_Download_Pause').get_active())
        self.config.setFilter(id, 'delete', self.glade.get_widget('FlexRSS_Filter_Download_Delete').get_active())

        filter = self.config.getFilter(id)

        h_from, h_thru = self.configure_ui_get_history_restriction()
        if filter['type'] != self.config.constants['Generic']:
            if not filter['history'].has_key(filter['type']):
                filter['history'][filter['type']] = {}

            if h_from != None:
                filter['history'][filter['type']]['from'] = h_from
            else:
                if filter['history'][filter['type']].has_key('from'):
                    del filter['history'][filter['type']]['from']

                if h_thru != None:
                    filter['history'][filter['type']]['thru'] = h_thru
                else:
                    if filter['history'][filter['type']].has_key('thru'):
                        del filter['history'][filter['type']]['thru']

        filter['replace'] = { 'pattern': self.glade.get_widget('FlexRSS_Filter_Rewrite_Pattern').get_text(),
                              'with'   : self.glade.get_widget('FlexRSS_Filter_Rewrite_Replacement').get_text() }

        self.write_config()

    def configure_cb_remove_pattern(self, arg):
        arg.get_parent().destroy()

    def configure_ui_add_pattern(self, pattern):
        import gtk, gobject

        filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')

        hbox = gtk.HBox()
        filter_patterns.pack_start(hbox)

        input = gtk.Entry()
        input.set_text(pattern[0])
        input.connect("changed", self.configure_cb_test_filter)

        on = gtk.Label()
        on.set_text('On')
        on.show()

        combo = gtk.combo_box_new_text()
        combo.append_text('Title')
        combo.append_text('Link')
        if pattern[1] == 'Link':
            combo.set_active(1)
        else:
            combo.set_active(0)

        remove = gtk.Button(stock=gtk.STOCK_REMOVE)
        remove.connect("pressed", self.configure_cb_remove_pattern)

        hbox.pack_start(input)
        hbox.pack_start(on, expand=False)
        hbox.pack_start(combo, expand=False)
        hbox.pack_start(remove, expand=False)

        hbox.show_all()

    def configure_cb_add_pattern(self, args):
        self.configure_ui_add_pattern(('', 'Title'))

    def configure_ui_add_filter(self, filter, test_pattern=None):
        if not filter:
            print 'No filter to add'
            return None

        self.configure_ui_reset_filter()

        model = self.glade.get_widget("FlexRSS_Filters_List").get_model()
        iter = model.append((filter['id'], filter['name'], filter['enabled']))

        if not iter:
            return

        view = self.glade.get_widget("FlexRSS_Filters_List")
        model = view.get_model()
        view.get_selection().select_iter(iter)

        if test_pattern:
            self.glade.get_widget('FlexRSS_Filters_Test_Pattern').set_text(test_pattern)
            self.configure_cb_test_filter(None)

        self.glade.get_widget('FlexRSS_MainNotebook').set_current_page(1)

    def configure_ui_test_result(self, result, h_match=False):
        if result and h_match:
            self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Match')
        else:
            self.glade.get_widget('FlexRSS_Filters_Test_Result').set_text('Doesn\'t match')

        type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()

        if type == 0: # Generic
            self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide()
            self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide()
            self.glade.get_widget('FlexRSS_History_TVShow').hide()
            self.glade.get_widget('FlexRSS_History_TVShow_Dated').hide()
        elif type == 1: # TV Show
            self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').show()
            self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide()
            self.glade.get_widget('FlexRSS_History_TVShow').show()
            self.glade.get_widget('FlexRSS_History_TVShow_Dated').hide()
            if result:
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text(str(result['series']))
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text(str(result['episode']))
            else:
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Series').set_text('0')
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Episode').set_text('0')
        else: # TV Show (dated)
            self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide()
            self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').show()
            self.glade.get_widget('FlexRSS_History_TVShow').hide()
            self.glade.get_widget('FlexRSS_History_TVShow_Dated').show()
            if result:
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text(str(result['year']))
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text(str(result['month']))
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text(str(result['day']))
            else:
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Year').set_text('0')
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Month').set_text('0')
                self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated_Day').set_text('0')

    def configure_cb_test_filter(self, source=None, date=None):
        subject = self.glade.get_widget('FlexRSS_Filters_Test_Pattern').get_text()

        type = self.glade.get_widget('FlexRSS_Filters_Type').get_active()
        if type == 1:
            type_s = self.config.constants['TV Show']
        elif type == 2:
            type_s = self.config.constants['TV Show (dated)']
        else:
            type_s = self.config.constants['Generic']

        filter_patterns = self.glade.get_widget('FlexRSS_Filter_Patterns_List')
        for i in filter_patterns.get_children():
            data = i.get_children()
            pattern = data[0].get_text()
            result = self.test_pattern(type_s, subject, pattern)
            if result:
                # Pattern matched, let's try history restriction.
                h_from, h_thru = self.configure_ui_get_history_restriction()
                h_match = self.test_range(type_s, result, h_from, h_thru)
                self.configure_ui_test_result(result, h_match)
                return

        self.configure_ui_test_result(False)        

    def configure_cb_delete_filter(self, arg):
        # Which filter is selected?
        selection = self.glade.get_widget("FlexRSS_Filters_List").get_selection()
        model, iter = selection.get_selected()

        if not iter:
            return

        id = model.get_value(iter, 0)

        # Remove from config
        if not self.config.deleteFilter(id):
            print 'Unable to delete filter #' + str(id)
            return
        self.write_config()

        # Remove from UI
        model.remove(iter)

        self.configure_ui_reset_filter()

    def configure_cb_feed_refresh(self, caller, id=None):
        if not id:
            selection = self.glade.get_widget("FlexRSS_Feeds").get_selection()
            model, iter = selection.get_selected()

            if not iter:
                return

            id = model.get_value(iter, 0)

        if id:
            if ( self.config.threaded_retrieval ):
                import threading
                threading.Thread(target=self.parse_feed, args=(id,)).start()
            else:
                self.parse_feed(id)

    def configure_cb_download_torrent(self, caller, url):
        self.download_torrent(url)

    def configure_cb_feed_popup(self, view, event):
        if event.button != 3:
            return

        model = view.get_model()
        coords = event.get_coords()
        path = view.get_path_at_pos(int(coords[0]), int(coords[1]))
        if path:
            iter = model.get_iter(path[0])
        else:
            iter = None

        import gtk

        popup = gtk.Menu()

        if iter:
            id = model.get_value(iter, 0)
            if id: # Feed
                item_refresh = gtk.MenuItem(_("Refresh feed"))
                item_refresh.connect("activate", self.configure_cb_feed_refresh, id)
                popup.append(item_refresh)

                item_delete = gtk.MenuItem(_("Delete feed"))
                item_delete.connect("activate", self.configure_cb_feed_delete, id)
                popup.append(item_delete)

            else: # Filter
                item_filter = gtk.MenuItem(_("Create filter"))
                item_filter.connect("activate", self.configure_cb_filter_new, model.get_value(iter, 1))
                popup.append(item_filter)

                item_download = gtk.MenuItem(_("Download torrent"))
                item_download.connect("activate", self.configure_cb_download_torrent, model.get_value(iter, 2))
                popup.append(item_download)

        else: # Neither
            item_new = gtk.MenuItem("New feed")
            item_new.connect("activate", self.configure_cb_feed_new)
            popup.append(item_new)

        popup.popup(None, None, None, event.button, event.time)
        popup.show_all()

    def configure_cb_output_set(self, chooser):
        self.glade.get_widget('FlexRSS_Filter_Output_Type_Custom').set_active(True)

    def configure_ui_reset_filter(self):
        # Just resets the crap in the filter tab to defaults.
        self.glade.get_widget('FlexRSS_Filters_Name').set_text('')
        self.glade.get_widget('FlexRSS_Filters_Type').set_active(0)
        self.glade.get_widget('FlexRSS_Filters_Feed').get_selection().unselect_all()
        for filter in self.glade.get_widget('FlexRSS_Filter_Patterns_List').get_children():
            filter.destroy()
        self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow').hide()
        self.glade.get_widget('FlexRSS_Filters_Test_Results_TVShow_Dated').hide()
        file_chooser = self.glade.get_widget('FlexRSS_Filter_Output_Location')
        file_chooser.set_current_folder(self.interface.config.get('default_download_path'))
        self.glade.get_widget('FlexRSS_Filter_Output_Type_Default').set_active(True)

    def strcasecmp(self, s1, s2):
        try:
            t1 = s1.lower()
            t2 = s2.lower()

            if s1 < s2:
                return -1
            elif s1 > s2:
                return 1
        except:
            pass

        return 0

    def configure_ui_sort_cmp(self, model, iter1, iter2, user_data=None):
        if (model.get_value(iter1, 0) == 0) or (model.get_value(iter2, 0) == 0):
            return 0

        return self.strcasecmp(model.get_value(iter1, 1), model.get_value(iter2, 1))

    def configure_cb_filter_toggled(self, renderer, path):
        old_val = renderer.get_active()
        model = self.glade.get_widget('FlexRSS_Filters_List').get_model()
        iter = model.get_iter(path)
        if old_val:
            model.set_value(iter, 2, False)
            self.config.setFilter(model.get_value(iter, 0), 'enabled', False)
        else:
            model.set_value(iter, 2, True)
            self.config.setFilter(model.get_value(iter, 0), 'enabled', True)
        self.write_config()

    def configure_cb_cookie_new(self, src):
        self.configure_ui_cookie_reset()
        self.glade.get_widget("FlexRSS_Cookies_Editor").show()

    def configure_cb_cookie_save(self, src):
        import cookielib, time

        domain = self.glade.get_widget("FlexRSS_Cookie_Domain").get_text()
        path = self.glade.get_widget("FlexRSS_Cookie_Path").get_text()
        name = self.glade.get_widget("FlexRSS_Cookie_Name").get_text()
        value = self.glade.get_widget("FlexRSS_Cookie_Value").get_text()

        if (domain == ""):
            return

        if path == '':
            path = '/'

        # Fragile.
        self.cookies._policy._now = self.cookies._now = int(time.time())
        cookie = self.cookies._cookie_from_cookie_tuple((name, value, {"domain": domain, "path":path, "expires":2147483647}, {}), None)

        self.cookies.set_cookie(cookie)
        self.configure_ui_add_cookie(None, cookie)
        self.configure_ui_cookie_reset()
        self.glade.get_widget("FlexRSS_Cookies_Editor").hide()
        self.write_config(True)

    def configure_ui_add_cookie(self, model, cookie):
        if cookie.domain[0] == '.':
            domain = cookie.domain[1:]
        else:
            domain = cookie.domain

        if model == None:
            model = self.glade.get_widget("FlexRSS_Cookies_List").get_model()

        parent = None
        iter = model.get_iter_first()
        while iter:
            t = model.get_value(iter, 0)
            if t == domain:
                parent = iter
                break
            iter = model.iter_next(iter)

        if parent == None:
            parent = model.append(iter, (domain, "", "", ""))
        model.append(parent, (cookie.domain, cookie.path, cookie.name, cookie.value))

    def configure_ui_cookie_reset(self):
        self.glade.get_widget("FlexRSS_Cookie_Domain").set_text('')
        self.glade.get_widget("FlexRSS_Cookie_Path").set_text('/')
        self.glade.get_widget("FlexRSS_Cookie_Name").set_text('')
        self.glade.get_widget("FlexRSS_Cookie_Value").set_text('')

    def configure_cb_cookie_selected(self, selection):
        model, iter = selection.get_selected()

        self.configure_ui_cookie_reset()
        self.glade.get_widget("FlexRSS_Cookies_Editor").hide()

    def configure_cb_cookie_delete(self, src):
        selection = self.glade.get_widget("FlexRSS_Cookies_List").get_selection()
        model, iter = selection.get_selected()

        domain = None
        path = None
        name = None

        if not model.iter_has_child(iter):
            path = model.get_value(iter, 1)
            name = model.get_value(iter, 2)
        domain = model.get_value(iter, 0)

        try:
            self.cookies.clear("." + domain, path, name)
        except:
            pass
        try:
            self.cookies.clear(domain, path, name)
        except:
            pass

        # UI
        if model.iter_has_child(iter):
            i = model.iter_children(iter)
            while model.remove(i):
                pass
            model.remove(iter)
        else:
            p = model.iter_parent(iter)
            model.remove(iter)
            if not model.iter_has_child(p):
                model.remove(p)

        self.write_config(True)

    def configure_cb_toolbar_clicked(self, button):
        self.configure()

    def configure_ui_show_toolbar_button(self):
        if self.toolbar_button == None:
            import gtk
            import os.path

            icon = gtk.Image()
            icon.set_from_file(os.path.join(self.path, "FlexRSS.png"))
            self.toolbar_button = gtk.ToolButton(icon_widget=icon, label="FlexRSS")
            self.toolbar_button.connect("clicked", self.configure_cb_toolbar_clicked)
            self.interface.toolbar.add(self.toolbar_button)
            self.toolbar_button.show_all()

    def configure_cb_toolbar_toggled(self, box):
        if box.get_active():
            self.configure_ui_show_toolbar_button()
            self.config.show_toolbar_button = True
            self.write_config()
        else:
            self.toolbar_button.destroy()
            self.toolbar_button = None
            self.config.show_toolbar_button = False
            self.write_config()

    def configure_cb_threaded_toggled(self, box):
        self.config.threaded_retrieval = box.get_active()
        self.write_config()

    def configure(self, widget=None):
        if self.glade: # Dialog already running
            return

        import gtk, gtk.glade, gobject

        self.glade = gtk.glade.XML(self.path + "/FlexRSS.glade")

        # Intialize feed lists
        feeds_model = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING)
        feeds_view = self.glade.get_widget("FlexRSS_Feeds")
        filters_feeds_view = self.glade.get_widget("FlexRSS_Filters_Feed")
        feeds_view.set_model(feeds_model)
        filters_feeds_view.set_model(feeds_model)
        feeds_model.set_sort_func(1, self.configure_ui_sort_cmp)
        feeds_model.set_sort_column_id(1, gtk.SORT_ASCENDING)

        # Setup columns for feeds tab
        renderer_name = gtk.CellRendererText()
        column_name = gtk.TreeViewColumn(_("Feed Name"), renderer_name, text=1)
        feeds_view.append_column(column_name)
        renderer_url = gtk.CellRendererText()
        column_url = gtk.TreeViewColumn(_("URL"), renderer_url, text=2)
        feeds_view.append_column(column_url)
        feeds_view.set_search_column(1)
        feeds_view.set_search_equal_func(gtk_treeview_search_cb_stristr)

        # Set callback for when selection is changed in feeds tab
        # I can't figure out how to do this in Glade
        feeds_view.get_selection().connect("changed", self.configure_cb_feed_selected)

        # Setup columns for feed list on filters tab
        renderer_name = gtk.CellRendererText()
        column_name = gtk.TreeViewColumn(_("Feed Name"), renderer_name, text=1)
        filters_feeds_view.append_column(column_name)

        # Allow multiple selections of feeds in filters tab
        # I can't figure out how to do this in Glade
        filters_feeds_view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        # Populate feed lists
        if self.config.feeds:
            for feed in self.config.feeds:
                this_feed = feeds_model.append(None, (feed['id'], feed['name'], feed['url']))
                for item in self.feeds[feed['id']]['data']:
                    feeds_model.append(this_feed, (0, item['title'], item['link']))
                    

        # Initialize filters list
        filters_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
        filters_view = self.glade.get_widget("FlexRSS_Filters_List")
        filters_view.set_model(filters_model)
        feeds_model.set_sort_func(1, self.configure_ui_sort_cmp)
        filters_model.set_sort_column_id(1, gtk.SORT_ASCENDING)

        # Setup columns for filters list
        renderer_enabled = gtk.CellRendererToggle()
        column_enabled = gtk.TreeViewColumn(_("Enabled"), renderer_enabled, active=2)
        filters_view.append_column(column_enabled)
        renderer_enabled.connect('toggled', self.configure_cb_filter_toggled)
        renderer_name = gtk.CellRendererText()
        column_name = gtk.TreeViewColumn(_("Filter Name"), renderer_name, text=1)
        filters_view.append_column(column_name)

        # Set callback for when selection is changed in feeds tab
        # I can't figure out how to do this in Glade
        filters_view.get_selection().connect("changed", self.configure_cb_filter_selected)

        # Populate filters list
        if self.config.filters:
            for filter in self.config.filters:
                filters_model.append((filter['id'], filter['name'], filter['enabled']))

        # Filter types
        filter_types = self.glade.get_widget('FlexRSS_Filters_Type')
        filter_types.append_text(_("Generic"))
        filter_types.append_text(_("TV Show"))
        filter_types.append_text(_("TV Show (dated)"))

        # Calendar buttons for dated tv show history restrictions
        from CalendarButton import CalendarButton
        dated_from = CalendarButton()
        dated_from.connect('date-selected', self.configure_cb_test_filter)
        dated_to = CalendarButton()
        dated_to.connect('date-selected', self.configure_cb_test_filter)
        dated_from.show()
        dated_to.show()
        history_table = self.glade.get_widget('FlexRSS_History_TVShow_Dated')
        history_table.attach(dated_from, 1, 2, 0, 1, gtk.EXPAND|gtk.FILL, gtk.FILL)
        history_table.attach(dated_to, 1, 2, 1, 2, gtk.EXPAND|gtk.FILL, gtk.FILL)
        self.history_calendarbuttons = (dated_from, dated_to)

        # Initialize cookies list
        cookies_model = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
        cookies_view = self.glade.get_widget("FlexRSS_Cookies_List")
        cookies_view.set_model(cookies_model)
        cookies_view.get_selection().connect("changed", self.configure_cb_cookie_selected)

        # Setup column for cookies
        domain_renderer = gtk.CellRendererText()
        domain_column = gtk.TreeViewColumn(_("Domain"), domain_renderer, text=0)
        path_renderer = gtk.CellRendererText()
        path_column = gtk.TreeViewColumn(_("Path"), path_renderer, text=1)
        name_renderer = gtk.CellRendererText()
        name_column = gtk.TreeViewColumn(_("Name"), name_renderer, text=2)
        value_renderer = gtk.CellRendererText()
        value_column = gtk.TreeViewColumn(_("Value"), value_renderer, text=3)
        cookies_view.append_column(domain_column)
        cookies_view.append_column(path_column)
        cookies_view.append_column(name_column)
        cookies_view.append_column(value_column)

        for cookie in self.cookies:
            self.configure_ui_add_cookie(cookies_model, cookie)

        # Interface
        self.glade.get_widget("FlexRSS_Interface_ShowButton").set_active(self.config.show_toolbar_button)
        self.glade.get_widget("FlexRSS_Retrieval_Threaded").set_active(self.config.threaded_retrieval)

        # Callbacks for UI events
        actions = {
            # Feeds tab
            "on_FlexRSS_MainWindow_destroy"           : self.configure_cb_closed,
            "on_FlexRSS_Feeds_New_pressed"            : self.configure_cb_feed_new,
            "on_FlexRSS_Feeds_Save_pressed"           : self.configure_cb_feed_save,
            "on_FlexRSS_Feeds_Delete_pressed"         : self.configure_cb_feed_delete,
            "on_FlexRSS_Feeds_button_press_event"     : self.configure_cb_feed_popup,

            # Filters tab
            "on_FlexRSS_Filters_Add_pressed"          : self.configure_cb_filter_new,
            "on_FlexRSS_Action_Save_pressed"          : self.configure_cb_filter_save,
            "on_FlexRSS_Filter_Patern_Add_pressed"    : self.configure_cb_add_pattern,
            "on_FlexRSS_Filters_Type_changed"         : self.configure_cb_test_filter,
            "on_FlexRSS_Filters_Test_Pattern"         : self.configure_cb_test_filter,
            "on_FlexRSS_Filters_Delete_pressed"       : self.configure_cb_delete_filter,
            "on_FlexRSS_History_TVShow_From_Enabled_toggled" : self.configure_cb_filter_history_toggle,
            "on_FlexRSS_History_TVShow_Thru_Enabled_toggled" : self.configure_cb_filter_history_toggle,
            "on_FlexRSS_History_TVShow_Dated_From_Enabled_toggled" : self.configure_cb_filter_history_toggle,
            "on_FlexRSS_History_TVShow_Dated_Thru_Enabled_toggled" : self.configure_cb_filter_history_toggle,
            "on_FlexRSS_History_TVShow_From_Season_changed" : self.configure_cb_test_filter,
            "on_FlexRSS_History_TVShow_From_Episode_changed" : self.configure_cb_test_filter,
            "on_FlexRSS_History_TVShow_Thru_Season_changed" : self.configure_cb_test_filter,
            "on_FlexRSS_History_TVShow_Thru_Episode_changed" : self.configure_cb_test_filter,

            # Configuration tab
            "on_FlexRSS_Cookie_New_pressed"           : self.configure_cb_cookie_new,
            "on_FlexRSS_Cookie_Save_pressed"          : self.configure_cb_cookie_save,
            "on_FlexRSS_Cookie_Delete_pressed"        : self.configure_cb_cookie_delete,
            "on_FlexRSS_Interface_ShowButton_toggled" : self.configure_cb_toolbar_toggled,
            "on_FlexRSS_Retrieval_Threaded_toggled"   : self.configure_cb_threaded_toggled }
        if hasattr(self.interface, 'interactive_add_torrent_path'):
            actions["on_FlexRSS_Filter_Output_Location_current_folder_changed"] = self.configure_cb_output_set
        else:
            self.glade.get_widget('FlexRSS_Filter_Output').hide()
        self.glade.signal_autoconnect(actions)

        self.glade.get_widget("FlexRSS_MainWindow").show()

    def cmp_history(a, b):
        try:
            if a.has_key('series'):
                if a['series'] > b['series']:
                    return 1
                elif a['series'] < b['series']:
                    return -1
                else:
                    if a['episode'] > b['episode']:
                        return 1
                    elif a['episode'] < b['episode']:
                        return -1
                    else:
                        return 0
        except:
            return 0

    def strptime2regex(self, input):
        # Does'n exactly live up to its name yet. Currently just
        # replaces %y,%Y,%m,%d with named patterns. In the future, it
        # would be nice to allow escaping (e.g., %%Y means literal %Y)
        # and expand it to support other formats.
        patterns = [('%Y', '(?P<Y>[0-9]{4})'),
                    ('%y', '(?P<y>[0-9]{2})'),
                    ('%m', '(?P<m>[0-9]{1,2})'),
                    ('%d', '(?P<d>[0-9]{1,2})')]

        out = input
        for p in patterns:
            out = out.replace(p[0], p[1])

        return out

    def replace_tv_show_patterns(self, input):
        patterns = [('%s', '(?P<s>[0-9]+)'),
                    ('%e', '(?P<e>[0-9]+)')]

        out = input
        for p in patterns:
            out = out.replace(p[0], p[1])

        return out

    def test_range(self, type, data, h_from=None, h_thru=None):
        if type == self.config.constants['TV Show']:
            if h_from != None:
                if data['series'] < h_from['season']:
                    return False
                elif data['series'] == h_from['season']:
                    if data['episode'] < h_from['episode']:
                        return False

            if h_thru != None:
                if data['series'] > h_thru['season']:
                    return False
                elif data['series'] == h_thru['season']:
                    if data['episode'] > h_thru['episode']:
                        return False

            return True

        elif type == self.config.constants['TV Show (dated)']:
            if h_from != None:
                if data['year'] < h_from['year']:
                    return False
                elif data['year'] == h_from['year']:
                    if data['month'] < h_from['month']:
                        return False
                    elif data['month'] == h_from['month']:
                        if data['day'] < h_from['day']:
                            return False

            if h_thru != None:
                if data['year'] < h_thru['year']:
                    return False
                elif data['year'] == h_thru['year']:
                    if data['month'] < h_thru['month']:
                        return False
                    elif data['month'] == h_thru['month']:
                        if data['day'] < h_thru['day']:
                            return False

            return True

        else:
            return True

    def test_pattern(self, type, subject, pattern):
        import re, time
        result = False

        if len(pattern) < 1:
            return False

        if type == self.config.constants['TV Show (dated)']:
            pattern = self.strptime2regex(pattern)
        elif type == self.config.constants['TV Show']:
            pattern = self.replace_tv_show_patterns(pattern)

        # Wow, so this is lame...
        if pattern[0] != '^':
            pattern = '.*' + pattern

        try:
            exp = re.compile(pattern, re.IGNORECASE)
        except:
            print 'Broken expression: ' + pattern
            return False

        match = exp.match(subject)
        if match:
#             print 'Match: ' + subject
#             print '       ' + pattern
            if type == self.config.constants['TV Show']:
                try:
                    series = int(match.group('s'))
                except:
                    series = 0

                try:
                    episode = int(match.group('e'))
                except:
                    episode = 0

                result = { 'series'  : series,
                           'episode' : episode }

            elif type == self.config.constants['TV Show (dated)']:
                try:
                    year = int(match.group('Y'))
                except:
                    try:
                        year = int(match.group('y'))
                        if year > 70:
                            year += 1900
                        else:
                            year += 2000
                    except:
                        year = 0

                try:
                    month = int(match.group('m'))
                except:
                    month = 0

                try:
                    day = int(match.group('d'))
                except:
                    day = 0

                result = { 'year'  : year,
                           'month' : month,
                           'day'   : day }

            else:
                result = True

        return result

    def make_opener(self):
        import urllib2

        return urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookies))

    def make_request(self, location, referer=None):
        import urllib2, deluge.common

        req = urllib2.Request(location)
        req.add_header("User-Agent", "FlexRSS/%d.%d.%d (%s/%s)" % (self.version[0], self.version[1], self.version[2], deluge.common.PROGRAM_NAME, deluge.common.PROGRAM_VERSION))
        if referer != None:
            req.add_header('Referer', referer)

        return req

    def open_url(self, location):
        return self.make_opener().open(self.make_request(location))

    def download_torrent(self, location, path=None, queue_top=False, pause=False, referer=None):
        import tempfile, os, deluge.core

        try:
            fd = self.open_url(location)
        except:
            return False

        inf = fd.info()
        if inf["content-type"] != "application/x-bittorrent":
            print "Warning: torrent content-type not application/x-bittorrent"

        (tmpfd, filename) = tempfile.mkstemp(".torrent", "flexrss-")
        tfd = os.fdopen(tmpfd, 'wb')
        tfd.write(fd.read())
        fd.close()
        tfd.close()

        unique_id = False

        try:
            if path is None:
                path = self.interface.config.get('default_download_path')
            unique_id = self.interface.manager.add_torrent(filename, path, self.interface.config.get('use_compact_storage'))
            self.interface.torrent_model_append(unique_id)

            if queue_top == True:
                try:
                    self.interface.manager.queue_top(unique_id)
                except:
                    pass
            if pause == True:
                try:
                    self.interface.manager.set_user_pause(unique_id, True)
                except:
                    pass
        except deluge.core.DuplicateTorrentError, e:
            print 'FlexRSS: torrent already exists.'
            return True
        except:
            print '*** FlexRSS error: unable to add torrent.'
            return False

        return True

    def parse_feed(self, id):
        import time, feedparser, urllib2, cookielib

        feed = self.config.getFeed(id)

        #print 'Parsing feed: ' + feed['url']
        try:
            parsed = feedparser.parse(self.open_url(feed['url']))
            if (not parsed) or (not parsed.entries):
                print 'Unable to parse feed: ' + feed['url']
                return
        except:
            print 'Unable to update feed: ' + feed['url']
            return
        #print 'Retrieval successful: ' + feed['url']

        data = []

        for entry in parsed.entries:
            entryTitle = entry['title']

            try:
                entryLink = entry.links[0]['href']
            except:
                try:
                    entryLink = entry.enclosures[0]['href']
                except:
                    print "Skipping %s\n" % entryTitle
                    continue

            try:
                data.append({ 'title': entryTitle, 'link': entryLink })
            except:
                continue

            if self.config.filters:
                for filter in self.config.filters:
                    try:
                        if not ((feed['id'] in filter['feeds']) or (0 in filter['feeds'])):
                            continue
                    except TypeError:
                        filter['feeds'] = [0]

                    if filter['enabled'] != True:
                        continue

                    for pattern in filter['patterns']:
                        # (setq python-indent 4
                        #       tab-width 4)
                        # Okay, I dislike python substantially less now.
                        # Edit (~a month later): I still dislike it a lot, though.
                        try:
                            if pattern[1] == 'Title':
                                subject = entryTitle
                            else:
                                subject = entryLink
                        except:
                            print 'Unable to find subject.'

                        match = self.test_pattern(filter['type'], subject, pattern[0])
                        if match:
                            # Filter matched. Check history to see if
                            # we should download it.
                            if filter['type'] == self.config.constants['Generic']: # Dirty hack.
                                match = { 'url' : entryLink }

                            torrent_url = entryLink
                            replace = filter.get('replace', {'pattern': '', 'with': ''})
                            if len(replace['pattern']) > 0:
                                try:
                                    import re

                                    p = re.compile(replace['pattern'], re.IGNORECASE)
                                    torrent_url = p.sub(replace['with'], torrent_url)
                                except:
                                    print '*** FlexRSS error: s/%s/%s/i failed.' % (replace['pattern'], replace['with'])
                                    return

                            if not self.config.checkHistory(filter['id'], filter['type'], match):
                                print filter
                                if filter.has_key('history'):
                                    res = False

                                    if filter['type'] == self.config.constants['Generic']:
                                        if filter['history'].get(filter['type'], []).count(torrent_url) == 0:
                                            res = self.download_torrent(torrent_url, filter.get('path', None), filter['queue_top'], filter['pause'], feed['url'])
                                    else:
                                        h_from = filter['history'][filter['type']].get('from', None)
                                        h_thru = filter['history'][filter['type']].get('thru', None)
                                        if self.test_range(filter['type'], match, h_from, h_thru):
                                            res = self.download_torrent(torrent_url, filter.get('path', None), filter['queue_top'], filter['pause'], feed['url'])

                                    print res
                                    if res == True:
                                        if filter['delete'] == True:
                                            self.config.deleteFilter(filter['id'])
                                            self.write_config()

                                            model = self.glade.get_widget("FlexRSS_Filters_List").get_model()
                                            iter = model.get_iter_first();
                                            while iter != None:
                                                if model.get_value(iter, 0) == filter['id']:
                                                    model.remove(iter)
                                                    break
                                                iter = model.iter_next(iter)
                                        else:
                                            self.config.addHistory(filter['id'], filter['type'], match)
                                        self.write_config()

            self.feeds[feed['id']]['data'] = data
            if self.glade: # Update config window...
                feeds_model = self.glade.get_widget("FlexRSS_Feeds").get_model()
                iter = feeds_model.get_iter_first()
                while iter != None:
                    if id == feeds_model.get_value(iter, 0):
                        break
                    iter = feeds_model.iter_next(iter)

                i = feeds_model.iter_children(iter)
                if i != None:
                    while feeds_model.remove(i):
                        pass

                for item in data:
                    feeds_model.append(iter, (0, item['title'], item['link']))

    def update(self):
        import time, threading

        current_time = time.time()

        # I feel dirty for this. Oh, how I miss C.
        for id in self.feeds:
            if self.feeds[id]['cfg']['enabled'] == True:
                if (current_time - self.feeds[id]['cfg']['interval']) > self.feeds[id]['updated']:
                    self.feeds[id]['updated'] = current_time
                    if ( self.config.threaded_retrieval ):
                        threading.Thread(target=self.parse_feed, args=(self.feeds[id]['cfg']['id'],)).start()
                    else:
                        self.parse_feed(self.feeds[id]['cfg']['id'])
    
    def unload(self):
        if self.toolbar_button:
            self.toolbar_button.destroy()
            self.toolbar_button = None

    def deluge_version_compare(self, version):
        import deluge.common
        va = deluge.common.PROGRAM_VERSION.split('.')
        dv = int(va[0]) * 1000000
        dv = dv + (int(va[1]) * 10000)
        dv = dv + (int(va[2]) * 100)
        if len(va) >= 4:
            dv = dv + int(va[3])

        if dv < version:
            return -1
        elif dv > version:
            return 1
        else:
            return 0

    def __init__(self, path, core, interface, defaults):
        print "Found FlexRSS plugin..."
        self.path = path
        self.core = core
        self.interface = interface
        self.version = defaults['VERSION']

        self.load_config()

        if self.config.show_toolbar_button == True:
            self.configure_ui_show_toolbar_button()

        self.feeds = {}
        if self.config.feeds:
            for feed in self.config.feeds:
                self.feeds[feed['id']] = { 'cfg'     : feed,
                                           'updated' : 0,
                                           'data'    : [] }

        # Debugging
        # self.configure()
