#!/usr/bin/python

from os import path
import urllib2
import pygtk
pygtk.require ( '2.0' )

import gobject
import gtk
import gtk.glade
import gconf
import dbus

GLADEFILE = 'evolution-plugin-spambayes.glade'
for gladedir in ['/usr/share/evolution/2.6/glade', '/usr/local/share/evolution/2.6/glade']:
    filename = path.join ( gladedir, GLADEFILE )
    if path.exists (filename):
        GLADEFILE = filename
        break

GCONF_DIR = '/apps/evolution/mail/junk/spambayes'
GCONF_TRAIN_ON_ALL_MESSAGES = GCONF_DIR + '/train_on_all_messages'
GCONF_HAM_CUTOFF = GCONF_DIR + '/ham_cutoff'
GCONF_SPAM_CUTOFF = GCONF_DIR + '/spam_cutoff'

class SpamBayesSettings:
    def __init__ ( self ):
        self.glade = gtk.glade.XML ( GLADEFILE )
        self.window = self.glade.get_widget('mainwindow')
        self.window.connect('destroy', gtk.main_quit)
        self.window.show_all ()
        self.glade.signal_autoconnect ( {'train on all messages': self.trainOnAllMessages,
                                         'spam cutoff format': self.formatSpamCutoff,
                                         'ham cutoff format': self.formatHamCutoff,
                                         'spam cutoff changed': self.spamCutoffChanged,
                                         'ham cutoff changed': self.hamCutoffChanged,
                                         'drag data received': self.dragDataReceived,
                                         'dialog response': gtk.main_quit
                                         } )
        
        self.train_on_all_messages = self.glade.get_widget('train on all messages')
        self.ham_cutoff = self.glade.get_widget('ham cutoff')
        self.spam_cutoff = self.glade.get_widget('spam cutoff')
        self.test_view = self.glade.get_widget('test view')
        self.dnd_label = self.glade.get_widget('dnd label')
        self.dnd_image = self.glade.get_widget('dnd image')
        self.test_view = self.glade.get_widget('test view')
        self.test_model = gtk.ListStore ( gobject.TYPE_STRING, gobject.TYPE_DOUBLE )
        self.test_view.set_model ( self.test_model )
        renderer = gtk.CellRendererText()
        self.test_view.append_column ( gtk.TreeViewColumn ( 'Clue', renderer, text = 0 ) )
        self.test_view.append_column ( gtk.TreeViewColumn ( 'Score', renderer, text = 1 ) )
        self.test_view.set_headers_visible ( True )
        self.test_view.set_search_column ( 0 )
        #self.test_view.set_headers_clickable ( True )
        self.test_model.set_sort_func ( 0, self.clueSortFunction )
        self.test_model.set_sort_column_id ( 0, gtk.SORT_DESCENDING )
        
        self.dnd_label.drag_dest_set ( gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY )
        self.dnd_image.drag_dest_set ( gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 1)], gtk.gdk.ACTION_COPY )
        
        self.gconf_client = gconf.client_get_default()
        self.gconf_client.add_dir ( GCONF_DIR, gconf.CLIENT_PRELOAD_NONE )
        self.gconf_client.notify_add ( GCONF_DIR, self.gconfKeyChanged )
        
        self.gconfKeyChanged ( self.gconf_client, -1, self.gconf_client.get_entry(GCONF_TRAIN_ON_ALL_MESSAGES, "", True) )
        self.gconfKeyChanged ( self.gconf_client, -1, self.gconf_client.get_entry(GCONF_HAM_CUTOFF, "", True) )
        self.gconfKeyChanged ( self.gconf_client, -1, self.gconf_client.get_entry(GCONF_SPAM_CUTOFF, "", True) )

        self.bus = dbus.SessionBus ()
    
    def clueSortFunction ( self, treemodel, iter1, iter2 ):
        clue1 = treemodel.get(iter1, 0)[0]
        clue2 = treemodel.get(iter2, 0)[0]
        
        if clue1[0] == '*' and clue2[0] == '*':
            return cmp(clue1, clue2)
        elif clue1[0] == '*':
            return 1
        elif clue2[0] == '*':
            return -1
        else:
            return cmp ( treemodel.get(iter1, 1)[0], treemodel.get(iter2, 1)[0] )
    
    def dragDataReceived ( self, received, context, x, y, data, id, time ):
        print 'dragDataReceived', data.data
        ret = False
        try:
            server_obj = self.bus.get_object ('net.halfdans.Spam', '/net/halfdans/SpamBayes')
            server = dbus.Interface ( server_obj, 'net.halfdans.Spam' )
            
            filename = data.data
            
            fp = urllib2.urlopen(filename, 'r')
            msg = fp.read()
            fp.close ()
            
            msg = msg.encode('utf-8')
            
            score = server.score(msg)
            clues = server.clues(msg)
            
            if score < self.ham_cutoff.get_value():
                self.dnd_label.set_label ( 'Rated as "ham" with a score of %f' % score )
            elif score > self.spam_cutoff.get_value():
                self.dnd_label.set_label ( 'Rated as "spam" with a score of %f' % score )
            else:
                self.dnd_label.set_label ( 'Rated as "unsure" with a score of %f' % score )
            
            self.test_model.clear()
            for clue, score in clues:
                it = self.test_model.append ()
                self.test_model.set ( it, 0, clue, 1, score )
            
        except Exception, e:
            print e
            import traceback
            traceback.print_exc()
            ret = False
        
        context.finish ( ret, False, time )
    
    def gconfKeyChanged ( self, client, contextId, entry, *extra ):
        if entry.get_key() == GCONF_TRAIN_ON_ALL_MESSAGES and self.train_on_all_messages:
            self.train_on_all_messages.set_active ( client.get_bool(GCONF_TRAIN_ON_ALL_MESSAGES) )
            
        elif entry.get_key() == GCONF_HAM_CUTOFF:
            self.ham_cutoff.set_value ( client.get_float(GCONF_HAM_CUTOFF) )
        
        elif entry.get_key() == GCONF_SPAM_CUTOFF:
            self.spam_cutoff.set_value ( client.get_float(GCONF_SPAM_CUTOFF) )
        
        else:
            print 'Unkown gconf entry changed: ', entry.get_key()
    
    def trainOnAllMessages ( self, checkbox ):
        self.gconf_client.set_bool ( GCONF_TRAIN_ON_ALL_MESSAGES, checkbox.get_active() )
    
    def hamCutoffChanged ( self, scaler, scroll_type, value ):
        if value > self.spam_cutoff.get_value():
            self.spam_cutoff.set_value ( value )
            self.gconf_client.set_float ( GCONF_SPAM_CUTOFF, value )
        self.gconf_client.set_float ( GCONF_HAM_CUTOFF, value )

    def spamCutoffChanged ( self, scaler, scroll_type, value ):
        if value < self.ham_cutoff.get_value():
            self.ham_cutoff.set_value ( value )
            self.gconf_client.set_float ( GCONF_HAM_CUTOFF, value )
        self.gconf_client.set_float ( GCONF_SPAM_CUTOFF, value )
    
    def formatCutoff ( self, value ):
        if value < 0.01:
            return 'None (%.2f)'
        elif value < 0.05:
            return 'Very High (%.2f)'
        elif value < 0.15:
            return 'High (%.2f)'
        elif value < 0.25:
            return 'Normal (%.2f)'
        elif value < 0.45:
            return 'Low (%.2f)'
        elif value < 0.99:
            return 'Very Low (%.2f)'
        else:
            return 'All (%.2f)'
    
    def formatSpamCutoff ( self, scaler, value ):
        return self.formatCutoff ( 1 - value ) % value

    def formatHamCutoff ( self, scaler, value ):
        return self.formatCutoff(value) %  value

if __name__ == '__main__':
    main = SpamBayesSettings ()
    gtk.main ()
