var EXPORTED_SYMBOLS = ['AppIntent'];

const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyGetter(this, "Tracker", function() {
    var obj = {};
    Cu.import("resource://livemargins/track.jsm", obj);
    return obj.Tracker;    
});

XPCOMUtils.defineLazyGetter(this, "utils", function() {
    var obj = { };
    Cu['import']('resource://livemargins/utils.jsm', obj);
    return obj.utils;
});

XPCOMUtils.defineLazyGetter(this, "AppCenter", function() {
    var obj = { };
    Cu['import']('resource://livemargins/appcenter.jsm', obj);
    return obj.AppCenter;
});

XPCOMUtils.defineLazyGetter(this, "AppCenterDAO", function() {
    var obj = { };
    Cu['import']('resource://livemargins/dao.jsm', obj);
    return obj.AppCenterDAO;
});

XPCOMUtils.defineLazyGetter(this, "window", function() {
    return Cc["@mozilla.org/appshell/appShellService;1"]
             .getService(Ci.nsIAppShellService)
             .hiddenDOMWindow;
});

XPCOMUtils.defineLazyGetter(this, "SNS", function() {
    var obj = { };
    try {
        Cu["import"]("resource://share_all_cn/sns.jsm", obj);
    } catch (e) {
        let defSNS = {
            name: "sina",
            icon: "chrome://livemargins/skin/images/icons/sina.ico",
            height: 380,
            width: 630,
            getUrl: function(title, url, pic, extended) {
                return "http://v.t.sina.com.cn/share/share.php?appkey=1203606049&source=firefox&title="
                    + window.encodeURIComponent(extended + "    ")
                    + window.encodeURIComponent(title)
                    + "&url=" + window.encodeURIComponent(url)
                    + "&pic=" + window.encodeURIComponent(pic);
            }
        };
        return {
            getSNSPrefName: function() {
                return null;
            },
            
            getCurrentSNS: function() {
                return defSNS;
            },
            
            getSNSByName: function(name) {
                return defSNS;
            },
            
            installed: false
        };
    }
    return obj.SNS;
});

XPCOMUtils.defineLazyGetter(this, "_logger", function() {
    return new utils.logger("LM4.AppIntentModule");
});

XPCOMUtils.defineLazyGetter(this, "_stringBundle", function() {
    var stringBundleService = Cc['@mozilla.org/intl/stringbundle;1'].getService(Ci.nsIStringBundleService);
    return stringBundleService.createBundle("chrome://livemargins/locale/livemargins.properties");
});

function _log(msg) {
    _logger.trace(msg + "\n");
}

var _handlers = { };
var _activityQueue = { };

// init app intents
var _intents = {
    "image/*": [{
        "icon": "chrome://livemargins/skin/images/icons/gallery.png",
        "action": "app_gallery",
        "message": "collect",
        "type": "image/*",
        "label": "Save to Gallery",
        "labelStr": "intent.gallery.label"
    }, {
        "icon": "chrome://livemargins/skin/images/icons/xiuxiu.ico",
        "action": "{dcb0d1b8-7a02-41c3-9fc8-46b2405480b9}",
        "message": "edit",
        "type": "image/*",
        "label": "Edit using XiuXiu",
        "labelStr": "intent.xiuxiu.label"
    }, {
        "icon": "chrome://livemargins/skin/images/icons/maiku.png",
        "action": "{72600762-7580-43d7-a991-7d05c3eed5ed}",
        "message": "note",
        "type": "image/*",
        "label": "Save to Maiku",
        "labelStr": "intent.maiku.label"
    }],
    
    "text/*": [{
        "icon": "chrome://livemargins/skin/images/icons/search.png",
        "action": "app_search",
        "message": "search",
        "type": "text/*",
        "label": "Search using MultiSearch",
        "labelStr": "intent.multi_search.label"
    }, {
        "icon": "chrome://livemargins/skin/images/icons/youdao.gif",
        "action": "{a09cf36d-abbc-48ed-b0cc-77c650eb164e}",
        "message": "translate",
        "type": "text/*",
        "label": "Translate using Youdao",
        "labelStr": "intent.youdao.label"
    }, {
        "icon": "chrome://livemargins/skin/images/icons/maiku.png",
        "action": "{72600762-7580-43d7-a991-7d05c3eed5ed}",
        "message": "note",
        "type": "text/*",
        "label": "Save to Maiku",
        "labelStr": "intent.maiku.label"
    }, {
        "icon": "chrome://livemargins/skin/images/icons/hudong.png",
        "action": "{6e881146-62e9-461d-884a-3e2caf10b0ab}",
        "message": "search",
        "type": "text/*",
        "label": "Search using Hudong",
        "labelStr": "intent.hudong.label"
    }],
    
    "application/link": [{
        "icon": "chrome://livemargins/skin/images/icons/maiku.png",
        "action": "{72600762-7580-43d7-a991-7d05c3eed5ed}",
        "message": "note",
        "type": "application/link",
        "label": "Save to Maiku",
        "labelStr": "intent.maiku.label"
    }]
};

function _appendOrReplaceIntent(type, action, newIntent) {
    let _is = [];
    let _textIs = _intents[type];
    let _replaced = false;
    for (let i = 0; i < _textIs.length; i++) {
        let intent = _textIs[i];
        if (intent.action != action) {
            _is.push(intent);
        } else if (newIntent) {
            _replaced = true;
            _is.push(newIntent);
        }
    }
    
    if (newIntent && !_replaced) {
        _is.push(newIntent);
    }
    _intents[type] = _is;
}

function _getCurrentEngine() {
    let currentEngine = Cc["@mozilla.org/browser/search-service;1"]
                          .getService(Ci.nsIBrowserSearchService)
                          .currentEngine;
    let _engineIntent = null;
    if (currentEngine) {
        _engineIntent = {
            "icon": currentEngine.iconURI.spec,
            "action": "$app-search-engine$",
            "message": "search",
            "type": "text/*",
            "label": "Search using current engine",
            "labelStr": "intent.searchengine.label"
        };
    }   
    
    _appendOrReplaceIntent("text/*", "$app-search-engine$", _engineIntent);
}
_getCurrentEngine();

// Listen to the change of default search engine.
new utils.prefListener("browser.search.selectedEngine", function(branch, name) {
    _getCurrentEngine();
}).register();

function _updateCurrentShareEntry() {    
    _appendOrReplaceIntent("text/*", "$app-share-tool$", {
        "icon": SNS.getCurrentSNS().icon,
        "action": "$app-share-tool$",
        "message": "share",
        "type": "text/*",
        "label": "Share selection",
        "labelStr": "intent.share.label"
    });
    
    _appendOrReplaceIntent("application/link", "$app-share-tool$", {
        "icon": SNS.getCurrentSNS().icon,
        "action": "$app-share-tool$",
        "message": "share",
        "type": "application/link",
        "label": "Share link",
        "labelStr": "intent.share.label"
    });
}
_updateCurrentShareEntry();

if (SNS.getSNSPrefName()) {
    // Listen to the change of default search engine.
    new utils.prefListener(SNS.getSNSPrefName(), function(branch, name) {
        _updateCurrentShareEntry();
    }).register();
}

function _getRecentWindow() {
    var windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
    var wnd = windowMediator.getMostRecentWindow('navigator:browser');
    if (!wnd) {
        wnd = windowMediator.getMostRecentWindow('');
    }
    return wnd;
}

/**
 * Share text, image, or link with the current SNS site.
 */
function _startShareActivity(activity) {
    let href = null;
    let sns = SNS.getCurrentSNS();
    switch (activity.data.type) {
    case "text/*":
        href = sns.getUrl(activity.data.title, activity.data.href, "", activity.data.text);
        break;
    case "image/*":
        href = sns.getUrl("", "", activity.data.imgsrc, "");
        break;
    case "application/link":
        href = sns.getUrl(activity.data.title, activity.data.href, "", "");
        break;
    }
    
    function _openInCenter(pageURL, title, w, h) {
        var left = (window.screen.width / 2) - (w / 2);
        var top = (window.screen.height / 2)-(h / 2);
        return window.open(pageURL, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=no, width=' + w +', height=' + h + ', top=' + top + ', left=' + left);
    }
    
    if (sns.name == "mail") {
        let extProtocolSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
        let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
        let uri = ioService.newURI(href, null, null);
        extProtocolSvc.loadUrl(uri);
    } else {
        _openInCenter(href, sns.name, sns.width, sns.height);
    }
}

/**
 * Search text with default search engine.
 */
function _startSearchEngineActivity(activity) {
    // Only handle activity with type 'text/*'
    if (activity.data.type != "text/*") {
        return;
    }
    
    let currentEngine = Cc["@mozilla.org/browser/search-service;1"]
                          .getService(Ci.nsIBrowserSearchService)
                          .currentEngine;
    if (null == currentEngine) {
        return;
    }
    
    _getRecentWindow().openUILinkIn(currentEngine.getSubmission(activity.data.text, null).uri.spec, "foreground");
}

/**
 * Replace intent label by localized string.
 */
function _localizeLabel(intent) {
    if (intent.labelStr) {
        intent.label = _stringBundle.GetStringFromName(intent.labelStr);
    }
    return intent;
}

var AppIntent = {
    isSNSInstalled: function() {
        return SNS.installed !== false;
    },
    
    getIntentsByText: function(text) {
        var intents = [];
        _intents["text/*"].forEach(function(intent) {
            intents.push(_localizeLabel(intent));
        });

        return intents;
    },
    
    getIntentsByLink: function(text, href) {
        var intents = [];
        _intents["application/link"].forEach(function(intent) {
            intents.push(_localizeLabel(intent));
        });
        return intents;
    },
    
    getIntentsByImage: function(src) {
        var intents = [];
        _intents["image/*"].forEach(function(intent) {
            intents.push(_localizeLabel(intent));
        });

        return intents;
    },
    
    /*
        interface Activity {
            string action;
            string message;
            string type;
            object data;
            void postResult(in object data);
            void postException(in string type, in string message);
        }
        
      @param activity
     
      @see https://github.com/mozilla/openwebapps/blob/master/docs/ACTIVITIES.md
     
     */
    startActivity: function(activity) {
        var appUID = activity.action;
        if (!appUID) {
            return;
        }
        
        switch (appUID) {
        case "$app-share-tool$":
            _startShareActivity(activity);
            break;
        case "$app-search-engine$":
            // search text with default search engine.
            _startSearchEngineActivity(activity);
            break;
        default:
            if (_getHandler(activity.action)) {
                // focus app window
                AppCenter.installAndOpenApp(appUID);
                _getHandler(activity.action)(activity.data, activity.message);
            } else {
                AppCenter.installAndOpenApp(appUID);
                // App window may not be initialized, push activity to queue temporarily.
                _activityQueue[activity.action] = activity;
            }
            break; 
        }
        Tracker.track(Tracker.intent.type, Tracker.intent.actions.OPEN_INENT, appUID, activity.from);
    },
    
    registerHandler: function(action, handler) {
        // for simplicity, only one handler is allowed.
        _handlers[action] = handler;   
        // check if temporary activity exists.
        if (_activityQueue[action]) {
            let activity = _activityQueue[action];
            handler(activity.data, activity.message)
            delete _activityQueue[action];
        }       
    },
    
    unregisterHandler: function(action, handler) {
        delete _handlers[action];
    }
};

function _getHandler(action) {
    return _handlers[action];
}
