(function() {
    var ns = MOA.ns('AN.Notification');
    var Cu = Components.utils;

    /**
     * One tab can only attach one notification at the same time.
     * One notification can be attached to sevral tabs.
     * tabNotiQueue = {
     *     tab1_id: reminder1_id,
     *  tab2_id: reminder1_id
     *     ...
     * };
     *
     * Same notification should be removed simultaneously.
     *
     * notiTabQueue = {
     *     reminder1_id: [tab1_id, tab2_id]
     *  ...
     * }
     */
    var tabNotiQueue = {};
    var notiTabQueue = {};

    function _removeNotiFromQueue(rid) {
        if (!rid || !notiTabQueue[rid])
            return;

        var tabids = notiTabQueue[rid];
        for (var i = 0, len = tabids.length; i < len; i++) {
            delete tabNotiQueue[tabids[i]]
        }
        delete notiTabQueue[rid];
    }

    function _removeNotification(rid) {
        if (!rid || !notiTabQueue[rid])
            return;

        _removeNotiFromQueue(rid);
        // Already been shown, so do not show it again.
        // Remove the reminder from RuleCenter
        MOA.AN.RuleCenter.removeReminder(rid);
    }

    var showingNotifications = {};
    function _closeInstallNoti(tabId) {
        var notification = tabNotiQueue[tabId];
        if (!notification)
            return;

        var rid = notification.reminder_id;
        _removeNotification(rid);
        delete showingNotifications[rid];
    };

    var installAddon = function(tabId) {
        MOA.debug('Install right now: ' + this);

        var notification = tabNotiQueue[tabId];
        if (!!notification) {
            var reminder = MOA.AN.RuleCenter.getReminderById(notification.reminder_id);
            if (!!reminder) {
                if (reminder.type == 'addon') {
                    Cu['import']("resource://gre/modules/AddonManager.jsm")
                    AddonManager.getInstallForURL([reminder.xpi_url, "?src=external-cmnotification"].join(""), function(addonInstall) {
                        var webInstallListener = Cc["@mozilla.org/addons/web-install-listener;1"]
                                                    .getService(Ci.amIWebInstallListener);
                        AddonManager.addInstallListener(webInstallListener);
                        var browser = MOA.AN.Lib.getBrowserForTabId(tabId);
                        //AddonManager.installAddonsFromWebpage("application/x-xpinstall", browser.contentWindow, browser.currentURI, [addonInstall])
                        AddonManager.installAddonsFromWebpage("application/x-xpinstall",
                            browser.contentWindow,
                            Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI(reminder.xpi_url, null, null),
                            [addonInstall])
                    }, "application/x-xpinstall", null, reminder.addon_name);
                } else if (reminder.type == 'lm') {
                    var jsm = {};
                    Cu.import('resource://livemargins/appcenter.jsm', jsm);
                    jsm.AppCenter.installAndOpenApp(reminder.app_uid);
                } else if (reminder.type == 'text') {
                    gBrowser.selectedTab = gBrowser.addTab(reminder.learnmore_url);
                } else if (reminder.type == 'socialapi') {
                    let providerOrigin = JSON.parse(reminder.provider_value).origin;
                    let oldOrigin = Social.provider ? Social.provider.origin : "";

                    let provider = Social.activateFromOrigin(providerOrigin, socialActiveNotification(oldOrigin));

                    socialActiveNotification(oldOrigini)(provider);
                }
                _closeInstallNoti(tabId);
                MOA.AN.RuleCenter.clickOnInstall(notification.reminder_id);
                return;
            }
            MOA.AN.RuleCenter.clickOnInstall(notification.reminder_id);
        } else {
            _closeInstallNoti(tabId);
        }
    };

    function socialActiveNotification(oldOrigin) {
        return function(provider) {
            if (!provider) {
                return;
            }

            let description = document.getElementById("social-activation-message");
            let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
            let message = gNavigatorBundle.getFormattedString("social.activated.description",
                                                              [provider.name, brandShortName]);
            description.value = message;

            let notificationPanel = SocialUI.notificationPanel;
            notificationPanel.setAttribute("origin", provider.origin);
            notificationPanel.setAttribute("oldorigin", oldOrigin);

            notificationPanel.hidden = false;
            setTimeout(function () {
                notificationPanel.openPopup(SocialToolbar.button, "bottomcenter topright");
            }, 0);
        }
    };

    function reminderMeLater(tabId) {
        var notification = tabNotiQueue[tabId];
        if (!!notification) {
            MOA.AN.RuleCenter.clickOnLater(notification.reminder_id);
        }
        _closeInstallNoti(tabId);
    };

    function noMoreReminder(tabId) {
        var notification = tabNotiQueue[tabId];
        if (!!notification) {
            MOA.AN.RuleCenter.clickOnNoMore(notification.reminder_id);
        }
        _closeInstallNoti(tabId);
    };

    function closeIconClicked(tabId) {
        var notification = tabNotiQueue[tabId];
        if (!!notification) {
            MOA.AN.RuleCenter.clickOnCloseIcon(notification.reminder_id);
        }
    }

    /**
     * Add notification, called by RuleCenter.
     */
    ns.addNotification = function(rid, info) {
        if (!!tabNotiQueue[info.tabId])
            return;

        tabNotiQueue[info.tabId] = {
            reminder_id: rid,
            info: info
        };

        if (!notiTabQueue[rid])
            notiTabQueue[rid] = [];
        notiTabQueue[rid].push(info.tabId);
    };

    function _track_addon_noti(action, tabId) {
        var notification = tabNotiQueue[tabId];
        if (!notification)
            return;

        var reminder = MOA.AN.RuleCenter.getReminderById(notification.reminder_id);
        if (!reminder)
            return;

        MOA.AN.Tracker.track({
            type: reminder.type,
            rid: notification.reminder_id,
            action: action ? action : 'show'
        });
    };

    function _show_popup_notification(tabId, reminder) {
        var _notification = null;
        var _notify_countdown = new MOA.AN.Lib.CountDown({
            onFinish: function() {
                //PopupNotifications.remove(_notification)
                MOA.AN.Lib.get('notification-popup').hidePopup()
            }
        });
        var mainAction = {
            label: MOA.AN.Lib.getString(reminder.type + '.InstallNow'),
            accessKey: 'O',
            callback: function() {
                _track_addon_noti('install', tabId);
                setTimeout(installAddon, 25, tabId);
            }
        };
        var reminderName = reminder.addon_name || reminder.app_name || reminder.title || reminder.provider_name
        var popupOption = {
            timeout: Date.now() + 15000,
            eventCallback: function(state) {
                MOA.debug('popup state is '+state)
                switch (state) {
                    case "dismissed":
                        _notify_countdown.reset();
                        break;
                    case "removed":
                        setTimeout(reminderMeLater, 50, tabId);
                        _notify_countdown.destroy();
                        break;
                    case "shown":
                        _notify_countdown.start();
                        break;
                }
            },
            countdown: _notify_countdown,
            title: reminder.title || MOA.AN.Lib.getString(reminder.type + '.title'),
            closeicon: function() {
                _track_addon_noti('closeicon', tabId);
                closeIconClicked(tabId);
            },
            links: {
                learnmore: {
                    text: MOA.AN.Lib.getString(reminder.type + '.LearnMore'),
                    href: reminder.url,
                    tooltip: MOA.AN.Lib.getString(reminder.type + '.tooltip.LearnMore', [reminderName]),
                    callback: function(evt) {
                        _track_addon_noti('learnmore', tabId);
                        gBrowser.selectedTab = gBrowser.addTab(reminder.url);
                        evt.preventDefault()
                    }
                },
                neverremind: {
                    text: MOA.AN.Lib.getString(reminder.type + '.NeverRemind'),
                    tooltip: MOA.AN.Lib.getString(reminder.type + '.tooltip.NeverRemind', [reminderName]),
                    callback: function() {
                        _track_addon_noti('nomore', tabId);
                        noMoreReminder(tabId);
                        PopupNotifications.remove(_notification)
                    }
                },/*
                turnoff: {
                    text: MOA.AN.Lib.getString('addon.TurnOffRec'),
                    callback: function() {
                    }
                }*/
            }
        }
        var message = [MOA.AN.Lib.getString(reminder.type + '.FCERec2U', [reminderName]),
                       reminder.desc].join(' ')
        _notification = PopupNotifications.show(MOA.AN.Lib.getBrowserForTabId(tabId),
            "addon-notification-" + reminder.type,
            message,
            reminder.type + "s-notification-icon",
            mainAction,
            null,
            popupOption
        );
        _track_addon_noti('show', tabId);
    }

    /**
     * Show installation notification triggered by window url.
     */
    function _show_install_notification(tabId) {
        var notification = tabNotiQueue[tabId];
        var reminder = MOA.AN.RuleCenter.getReminderById(notification.reminder_id);

        if (showingNotifications[notification.reminder_id])
            return;
        else
            showingNotifications[notification.reminder_id] = 1;

        var curBrowser = MOA.AN.Lib.getBrowserForTabId(tabId);
        if (reminder.type == 'plugin_pfs') {
            var plugin = curBrowser.contentDocument.createElement('object');
            plugin.type = reminder.mime_type;
            gPluginHandler.pluginUnavailable(plugin, 'PluginNotFound');
            return;
        }
        _system_popup_countdown = new MOA.AN.Lib.CountDown({
            onCounting: function() {
                if (!PopupNotifications.isPanelOpen) {
                    _system_popup_countdown.option.onFinish()
                } else {
                    var _current_notification = PopupNotifications.getNotification('password-save', curBrowser) ||
                                                PopupNotifications.getNotification('password-change', curBrowser) ||
                                                PopupNotifications.getNotification('indexedDB-permissions-prompt', curBrowser) ||
                                                PopupNotifications.getNotification('indexedDB-quota-prompt', curBrowser) ||
                                                PopupNotifications.getNotification('indexedDB-quota-cancel', curBrowser) ||
                                                PopupNotifications.getNotification('geolocation', curBrowser) ||
                                                PopupNotifications.getNotification('webapps-install', curBrowser) ||
                                                PopupNotifications.getNotification('webRTC-shareDevices', curBrowser) ||
                                                PopupNotifications.getNotification('identity-request', curBrowser) ||
                                                PopupNotifications.getNotification('identity-logged-in', curBrowser) ||
                                                PopupNotifications.getNotification('addon-theme-change', curBrowser) ||
                                                PopupNotifications.getNotification('addon-install-cancelled', curBrowser) ||
                                                PopupNotifications.getNotification('xpinstall-disabled', curBrowser) ||
                                                PopupNotifications.getNotification('addon-install-blocked', curBrowser) ||
                                                PopupNotifications.getNotification('addon-progress', curBrowser) ||
                                                PopupNotifications.getNotification('addon-install-failed', curBrowser) ||
                                                PopupNotifications.getNotification('addon-install-complete', curBrowser) ||
                                                PopupNotifications.getNotification('click-to-play-plugins', curBrowser);
                    if(!_current_notification) {
                        _system_popup_countdown.option.onFinish()
                    }
                }
            },
            onFinish: function() {
                MOA.AN.Lib.get('notification-popup').hidePopup()
                _show_popup_notification(tabId, reminder);
                _system_popup_countdown.destroy()
            }
        });
        _system_popup_countdown.start()
    };

    /**
     * Show notification related with current tabBrowser.
     * Called by WebProgressListener.
     */
    ns.showNotification = function(webProgress) {
        // Get current tab browser ID.
        var win = webProgress.DOMWindow;
        var tabId = MOA.AN.Lib.getTabIdForWindow(win);
        if (!tabNotiQueue[tabId])
            return;

        var notification = tabNotiQueue[tabId];
        var reminder = MOA.AN.RuleCenter.getReminderById(notification.reminder_id);

        if (['addon', 'lm', 'plugin_pfs', 'text', 'socialapi'].indexOf(reminder.type) > -1) {
            _show_install_notification(tabId);
        }
        MOA.AN.RuleCenter.notificationShown()
    };

    ns.onTabClose = function(tabId) {
        var notification = tabNotiQueue[tabId];
        if (!notification)
            return;

        _removeNotiFromQueue(notification.reminder_id);
    };

    ns.clearAll = function() {
        tabNotiQueue = {};
        notiTabQueue = {};
        showingBalloonId = null;
        showingNotifications = {};
    };

    /******One tip one day*******/
    var _daytipreminders = null;
    var _current_day_tip_reminder = null;
    var _hide_daytip_countdown = new MOA.AN.Lib.CountDown({
        onFinish: function() {
            _track_daytip('auto_hide');
            _closeDayTip();
        },
    });

    function _closeDayTip() {
        MOA.AN.Lib.get('addon-notification-popup').hidePopup();
        try {
            _hide_daytip_countdown.destroy();
        } catch(e) {}
    };

    function _track_daytip(action) {
        MOA.AN.Tracker.track({
            type: 'daytip',
            rid: MOA.AN.RuleCenter.getRID(_current_day_tip_reminder),
            action: action ? action : 'show'
        });
    };

    function _show_day_tips(reminder) {
        var reminder_id = MOA.AN.RuleCenter.getRID(reminder);

        var target = MOA.AN.Lib.get(reminder.btn_id);
        if (!target)
            return;

        var panel = MOA.AN.Lib.get("addon-notification-popup");
        while (panel.lastChild)
            panel.removeChild(panel.lastChild);

        const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

        let doc = window.document;
        let popupnotification = doc.createElementNS(XUL_NS, "popupnotification");
        [title, desc] = reminder.desc.split(/<br\s?\/>/g);
        popupnotification.setAttribute("label", desc);
        popupnotification.setAttribute("id", "addon-notification-daytip");
        popupnotification.setAttribute("popupid", "addon-notification-daytip");
        popupnotification.setAttribute("closebuttoncommand", "MOA.AN.Notification.onClickDayTipCloseIcon()");
        var options = {
            countdown: _hide_daytip_countdown,
            title: title,
            links: {
                close: {
                    text: MOA.AN.Lib.getString('daytip.CloseDaytip'),
                    tooltip: MOA.AN.Lib.getString('daytip.tooltip.CloseDaytip'),
                    callback: function() {
                        MOA.AN.Notification.onClickDayTipClose()
                    }
                },
                turnoff: {
                    text: MOA.AN.Lib.getString('daytip.TurnOff'),
                    tooltip: MOA.AN.Lib.getString('daytip.tooltip.TurnOff'),
                    callback: function() {
                        MOA.AN.Notification.onClickDayTipTurnOff()
                    }
                }
            }
        }
        if (reminder.url) {
            options.links["learnmore"] = {
                text: MOA.AN.Lib.getString('daytip.ViewVideo'),
                href: reminder.url,
                callback: function(evt) {
                    gBrowser.selectedTab = gBrowser.addTab(reminder.url);
                    MOA.AN.Notification.onClickLearnMore();
                    evt.preventDefault()
                }
            }
        }
        if (_daytipreminders.length) {
            options.links["nexttip"] = {
                text: MOA.AN.Lib.getString('daytip.NextDaytip'),
                callback: function() {
                    MOA.AN.Notification.onClickNextDayTip()
                }
            }
        }
        popupnotification.notification = {
            options: options
        };
        panel.appendChild(popupnotification);
        panel.hidden = false;
        panel.openPopup(target, "bottomcenter topleft");
    }

    ns.showDayTip = function(force) {
        var last_show_time = MOA.AN.Lib.getFilePref('day_tip_show_time', null);

        if (!force) {
            if (!MOA.AN.Lib.getPrefs().getBoolPref('showDaytip')) {
                MOA.debug('Day tip has been turned off!');
                return;
            } else if (last_show_time) {
                var now = Date.now();
                if (MOA.AN.Lib.roundToDay(last_show_time) >= MOA.AN.Lib.roundToDay(now)) {
                    MOA.debug('Tip has been show today.');
                    return;
                }
            }

            MOA.AN.Lib.setFilePref('day_tip_show_time', Date.now());
        }

        _daytipreminders = MOA.AN.RuleCenter.getDayTipReminders(force);
        this.nextDayTip();
    };

    ns.nextDayTip = function() {
        if (_daytipreminders.length == 0) {
            MOA.debug('Reminders is empty.');
            return;
        }

        MOA.AN.Lib.get('addon-notification-popup').hidePopup();
        // set a interval to show next tip
        // make that popup's position will be refreshed.
        window.setTimeout(function() {
            _current_day_tip_reminder = _daytipreminders.shift();
            MOA.AN.RuleCenter.clickOnNoMore(MOA.AN.RuleCenter.getRID(_current_day_tip_reminder));
            _show_day_tips(_current_day_tip_reminder);
            try {
                _hide_daytip_countdown.start();
                _track_daytip();
            } catch(e) {}
        }, 1);
    };

    ns.onClickLearnMore = function() {
        _track_daytip('learnmore');
        _closeDayTip();
    }

    ns.onClickNextDayTip = function() {
        _track_daytip('next');
        this.nextDayTip();
    };

    ns.onClickDayTipCloseIcon = function() {
        _track_daytip('closeicon');
        _closeDayTip();
    };

    ns.onClickDayTipClose = function() {
        _track_daytip('close');
        _closeDayTip();
    };

    ns.onClickDayTipTurnOff = function() {
        _track_daytip('turnoff');
        MOA.AN.Lib.getPrefs().setBoolPref('showDaytip', false);
        _closeDayTip();
    };
})();
