var info = {
    name        : 'Activity',
    description : 'Pop up an alert when a certain condition is met',
    version     : '0.1.0',
    author      : 'Massimiliano Mirra <bard [at] hyperstruct [dot] net>',
    license     : 'GPL2',
    home        : 'http://repo.hyperstruct.net/sameplace/scriptlets/activity.js',
};


// DEFINITIONS
// ----------------------------------------------------------------------

var Cc = Components.classes;
var Ci = Components.interfaces;

const srvAlert = Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService);

var channel, busy, rules = [];


// ----------------------------------------------------------------------
// RULE EXAMPLES
//
// Show alert whenever a contact or a chat room participant changes
// state (warning, that might be quite often!):
// 
//     rule({
//         event: 'presence'
//     });
//
// Show alert when 'john@jabber.org' changes state:
//
//     rule({
//         event: 'presence'
//         from: 'john@jabber.org'
//     });
// 
// Show alert when 'john@jabber.org' or anyone in the
// 'users@places.sameplace.cc' chatroom changes state:
//
//     rule({
//         event: 'presence'
//         from: [
//             'john@jabber.org',
//             'users@places.sameplace.cc'
//         ]
//     });
// 
// Show alert when 'john@jabber.org' sends us a message:
//
//     rule({
//         event: 'presence'
//         from: [
//             'john@jabber.org',
//             'users@places.sameplace.cc'
//         ]
//     });
//
// ----------------------------------------------------------------------


// ----------------------------------------------------------------------
// BEGIN RULES
// ----------------------------------------------------------------------

rule({
    event : 'message',
    show_when: 'sameplace_unfocused'
});
/*
rule({
    event : 'presence',
    show_when: 'always'
});
*/
// ----------------------------------------------------------------------
// END RULES
// ----------------------------------------------------------------------



// TODO: Gecko 1.9 supports document.hasFocus().  Use that if
// available to make certain notifications appear only when window
// isn't focused.

function init() {
    channel = XMPP.createChannel();
    busy    = false;
    rules.forEach(function(rule) {
        channel.on(patternFor(rule), actionFor(rule));
    });
}    

function finish() {
    channel.release();
}

function show(title, image, message) {
    if(!busy) {
        busy = true;
        srvAlert.showAlertNotification(
            image, title, message, false, 'Activity', this);
    }
}

function observe(subject, topic, data) {
    if(data != 'Activity')
        return;
    
    switch(topic) {
    case 'alertfinished':
        busy = false;
        break;
    case 'alertclickcallback':
        break;
    }
}

function rule(desc) {
    rules.push(desc);
}

function eventMatcher(rulePart) {
    if(rulePart instanceof Array)
        return function(event) {
            return rulePart.indexOf(event) != -1;
        } 
    else
        function(event) {
            return rulePart == event;
        }
}

function stanzaMatcher(rulePart) {
   if(rulePart instanceof Array)
        return function(stanza) {
            return rulePart.indexOf(XMPP.JID(stanza.@from).address) != -1;
        }
    else
        return function(stanza) {
            return rulePart == XMPP.JID(stanza.@from).address;
        }
}

// Given a user rule, produces an xmpp4moz-style event selector.

function patternFor(rule) {
    var pattern = {
        direction: 'in'
    };
    
    var stanzaMatchers = [];
    
    if(rule.event) {
        pattern.event = rule.event;
        
        // If stanza is a message, we want to ensure that we don't
        // catch stanzas which actually contain something.

        stanzaMatchers.push(function(stanza) {
            if(stanza.name() == 'message')
                return stanza.body.text() != undefined;
            else
                return true;
        });
    }

    if(rule.from)
        stanzaMatchers.push(stanzaMatcher(rule.from));

    if(stanzaMatchers.length != 0)
        pattern.stanza = function(stanza) {
            return stanzaMatchers.every(function(matcher) {
                return matcher(stanza);
            })
        };
    
    return pattern;
}

// Tries to produce an alert suitable for the event depending on the
// rule that is used to match the event.  For now, this means just:
// display the event type as the alert title ("Presence" or "Message")
// and the sender as the alert content.

function actionFor(rule) {
    if(rule.show_when == 'sameplace_unfocused')
        return function(e) {
            if(!top.sameplace.isReceivingInput())
                show(capitalize(e.event.toString()),
                     'chrome://xmpp4moz/skin/status/available.png',
                     e.stanza.@from);
        }
    else if(rule.show_when == 'always' ||
            rule.show_when == undefined)
        return function(e) {
            show(capitalize(e.event.toString()),
                 'chrome://xmpp4moz/skin/status/available.png',
                 e.stanza.@from);
        }
}

function capitalize(s) {
    return s.substr(0, 1).toUpperCase() + s.substr(1);
}

function isCurrentWindow() {
    return top == Cc['@mozilla.org/appshell/window-mediator;1']
        .getService(Ci.nsIWindowMediator)
        .getMostRecentWindow('');
}
