<?xml version='1.0'?>
<!DOCTYPE bindings [
<!ENTITY % mc SYSTEM "/mc.dtd">
%mc;
<!ENTITY % mc-links SYSTEM "/links/mc.dtd">
%mc-links;
]>
<bindings xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <binding id="button">
        <resources>
            <stylesheet src="../../styles/mc/button.css"/>
        </resources>

        <content label="&mc.widget.name;">
            <xul:image anonid="mc-alertable-image" hidden="true" tooltiptext="&mc.widget.name;"/>
        </content>

        <implementation implements="nsIObserver, nsIDOMEventListener">
            <field name="mAlertableImage" readonly="true">
                this.elementByAttr("anonid", "mc-alertable-image");
            </field>

            <field name="api" readonly="true">this.module.api</field>

            <field name="wListener" readonly="true">
                this.api.Browser.getWindowListener(window)
            </field>

            <field name="NOTIFICATION_NAME" readonly="true">"mistype-corrector-notification"</field>
            <field name="SUGGEST_URL">"&mc.suggest.url;"</field>

            <method name="elementByAttr">
                <parameter name="attr"/>
                <parameter name="value"/>
                <body><![CDATA[return document.getAnonymousElementByAttribute(this,attr,value);]]></body>
            </method>

            <method name="showUrlbarImage">
                <parameter name="setTabData"/>
                <body><![CDATA[this.mAlertableImage.hidden = false;
if (setTabData)
{
let tabData = this.wListener.getTabData(gBrowser.mCurrentBrowser,this.NOTIFICATION_NAME);
tabData.redirect = {
from: this.getValidURL(this.mistyped),
to: this.getValidURL(this.module.getNavigateLink(this.mistyped)),
count: 0};
}
]]></body>
            </method>

            <method name="hideUrlbarImage">
                <body><![CDATA[this.mAlertableImage.hidden = true;]]></body>
            </method>

            <method name="sendStatistic">
                <parameter name="path"/>
                <parameter name="from"/>
                <parameter name="to"/>
                <body><![CDATA[var params = {
dtype: "stred",
pid: 12,
cid: 71560,
path: path,
from: from,
to: to,
"*": ""};
var data = [];
for(let [key, val] in Iterator(params)) data.push(key + ("=" + encodeURIComponent(val)));
var url = "http://clck.yandex.ru/jclck/" + data.join("/");
var request = new XMLHttpRequest();
request.open("GET",url,true);
request.send(null);]]></body>
            </method>

            <method name="getValidURL">
                <parameter name="url"/>
                <body><![CDATA[if (! /^https?:\/\//.test(url))
url = "http://" + url;
return url;]]></body>
            </method>

            <method name="_getNotification">
                <parameter name="tab"/>
                <body><![CDATA[tab = tab || gBrowser.mCurrentBrowser;
var notificationBox = gBrowser.getNotificationBox(tab);
return notificationBox.getNotificationWithValue(this.NOTIFICATION_NAME);]]></body>
            </method>

            <method name="_closeNotification">
                <parameter name="tab"/>
                <body><![CDATA[tab = tab || gBrowser.mCurrentBrowser;
var notification = this._getNotification(tab);
if (notification)
notification.close();]]></body>
            </method>

            <method name="_showNotification">
                <parameter name="tab"/>
                <parameter name="notificationProperties"/>
                <body><![CDATA[tab = tab || gBrowser.mCurrentBrowser;
var type = "suggestionURL" in notificationProperties ? "suggest" : "redirect";
if (type === "suggest" && this.isEqualDomains(tab.currentURI.spec,notificationProperties.suggestionURL))
{
this.wListener.removeTabData(tab,this.NOTIFICATION_NAME);
return;
}

var tabData = this.wListener.getTabData(tab,this.NOTIFICATION_NAME);
tabData.notificationProperties = notificationProperties;
var notificationBox = gBrowser.getNotificationBox(tab);
var notification = notificationBox.getNotificationWithValue(this.NOTIFICATION_NAME);
if (notification)
return;
var priority = type === "redirect" ? notificationBox.PRIORITY_CRITICAL_BLOCK : notificationBox.PRIORITY_WARNING_MEDIUM;
notification = notificationBox.appendNotification("",this.NOTIFICATION_NAME,"",priority,[]);
notification.mistypeCorrectorElement = this;
notification.setAttribute("anonid",this.NOTIFICATION_NAME);
["selectedIndex", "suggestionURL", "changedFromURL", "changedToURL"].forEach(function (propName) {
notification.removeAttribute("data-" + propName);
}
);
if (type === "suggest")
{
notificationProperties.selectedIndex = 0;
}
else
{
notificationProperties.selectedIndex = 1;
}

for(let [propName, propValue] in Iterator(notificationProperties)) notification.setAttribute("data-" + propName,propValue);
return notification;]]></body>
            </method>

            <method name="_showSuggestNotification">
                <parameter name="notificationProperties"/>
                <body><![CDATA[this._showNotification(gBrowser.mCurrentBrowser,notificationProperties);]]></body>
            </method>

            <method name="_showRollbackNotification">
                <parameter name="notificationProperties"/>
                <body><![CDATA[this._showNotification(gBrowser.mCurrentBrowser,notificationProperties);]]></body>
            </method>

            <method name="isEqualDomains">
                <parameter name="one"/>
                <parameter name="two"/>
                <body><![CDATA[return this.extractDomain(one) === this.extractDomain(two);]]></body>
            </method>

            <method name="extractDomain">
                <parameter name="value"/>
                <body><![CDATA[return (value || "").replace(/^https?:\/\//,"").replace(/^www\./,"").split("/")[0];]]></body>
            </method>

            <method name="_showSuggestionForURL">
                <parameter name="userInput"/>
                <parameter name="suggestionURL"/>
                <parameter name="suggestionFirstResult"/>
                <body><![CDATA[if (! suggestionURL)
return;
if (this.isEqualDomains(userInput,suggestionURL))
return;
if (suggestionFirstResult && this.isEqualDomains(userInput,suggestionFirstResult))
return;
var currentURL = gBrowser.currentURI && gBrowser.currentURI.spec || "";
if (this.isEqualDomains(currentURL,suggestionURL))
return;
if (suggestionFirstResult && this.isEqualDomains(currentURL,suggestionFirstResult))
return;
if (! /^https?:\/\//.test(suggestionURL))
suggestionURL = "http://" + suggestionURL;
this._showSuggestNotification({
suggestionURL: suggestionURL});]]></body>
            </method>

            <method name="getSuggest">
                <parameter name="value"/>
                <body><![CDATA[var url = this.SUGGEST_URL + encodeURIComponent(this.extractDomain(value));
var xhr = new XMLHttpRequest();
xhr.open("GET",url,true);
xhr.onreadystatechange = (function getSuggest_xhr_onready() {
if (xhr.readyState !== 4 || xhr.status !== 200)
return;
var url;
try {
url = JSON.parse(xhr.responseText)[2][1];
}
catch (e) {

}

if (! url)
return;
var firstResult;
try {
firstResult = JSON.parse(xhr.responseText)[1][0];
}
catch (e) {

}

this._showSuggestionForURL(value,url,firstResult);
}
).bind(this);
xhr.send(null);]]></body>
            </method>

            <method name="_forceSendMistypedValue">
                <parameter name="value"/>
                <body><![CDATA[var xhr = new XMLHttpRequest();
var url = "http://bar-navig.yandex.ru/u";
xhr.open("POST",url,true);
xhr.onreadystatechange = (function _forceSendMistypedValue_xhr_onready() {
if (xhr.readyState !== 4)
return;
if (xhr.status !== 200)
{
this.getSuggest(value);
return;
}

var xml = xhr.responseXML;
var r1Element = xml.getElementsByTagName("r1")[0];
if (r1Element)
{
let r1 = r1Element.childNodes[0].nodeValue;
if (r1 && r1 !== this.barR1)
this.barR1 = r1;
}

var validURL = xml.getElementsByTagName("MisspellResult")[0];
if (! validURL)
{
this.getSuggest(value);
return;
}

validURL = validURL.getElementsByTagName("text")[0].childNodes[0].nodeValue;
if (validURL.indexOf(" ") !== - 1 || (validURL.indexOf(".") === - 1 || validURL.indexOf(".ру") !== - 1))
{
this.getSuggest(validURL);
return;
}

if (! validURL)
{
this.getSuggest(value);
return;
}

this._showSuggestionForURL(value,validURL);
}
).bind(this);
var api = this.module.api;
var clid4Data = api.DistrData && api.DistrData.getRecord("clid4");
var clid4 = clid4Data && clid4Data.clid || "";
var dataToSend = ["yasoft=barff", "ver=" + api.Environment.addon.version, "rnd=" + Date.now(), "show=1", "url=" + encodeURIComponent(value), "urlinfo=4", "clid=" + encodeURIComponent(clid4), "ui=" + encodeURIComponent(api.Environment.addon.userID)];
if (this.barR1)
dataToSend.push("r1=" + encodeURIComponent(this.barR1));
xhr.send(dataToSend.join("&"));]]></body>
            </method>

            <method name="_sendMistypedValue">
                <body><![CDATA[this._closeNotification();
setTimeout((function () {
this._sendMistypedValueTimed(this.urlbarValue);
}
).bind(this),0);]]></body>
            </method>

            <method name="_sendMistypedValueTimed">
                <parameter name="value"/>
                <body><![CDATA[value = value.toLowerCase();
this.mistyped = value;
if (value.indexOf("moz-action:") === 0)
return;
this._whitelisted = false;
var whitelistCount = this.module.getWhitelistValue(value);
if (whitelistCount >= 2)
{
this._whitelisted = true;
this.showUrlbarImage(true);
return;
}

var savedLink = this.module.getNavigateLink(value);
if (savedLink)
{
this._redirected = true;
this.showUrlbarImage(true);
openUILink(savedLink);
this.api.Statistics.logShortAction(5320);
return;
}

this._forceSendMistypedValue(value);]]></body>
            </method>

            <property name="urlbarValue">
                <getter><![CDATA[var urlbar = document.getElementById("urlbar");
return urlbar && urlbar.value || "";]]></getter>
            </property>

            <property name="barR1">
                <getter><![CDATA[return this.module.api.Statistics.barnavigR1String;]]></getter>
                <setter><![CDATA[this.module.api.Statistics.barnavigR1String = val;]]></setter>
            </property>

            <method name="_attachToNavigateElements">
                <body><![CDATA[var urlbar = document.getElementById("urlbar");
if (urlbar)
{
urlbar.addEventListener("keydown",this,false);
urlbar.addEventListener("focus",this,false);
}

var gobutton = document.getElementById("urlbar-go-button") || document.getElementById("go-button");
if (gobutton)
gobutton.addEventListener("click",this,false);]]></body>
            </method>

            <method name="_detachFromNavigateElements">
                <body><![CDATA[var urlbar = document.getElementById("urlbar");
if (urlbar)
{
urlbar.removeEventListener("keydown",this,false);
urlbar.removeEventListener("focus",this,false);
}

var gobutton = document.getElementById("urlbar-go-button") || document.getElementById("go-button");
if (gobutton)
gobutton.removeEventListener("click",this,false);]]></body>
            </method>

            <method name="observe">
                <parameter name="aSubject"/>
                <parameter name="aTopic"/>
                <parameter name="aData"/>
                <body><![CDATA[switch (aTopic) {
case "WindowLocationChange":
{
let tabData = this.wListener.getTabData(aData.tab,this.NOTIFICATION_NAME);
let showIcon = ! ! ("redirect" in tabData);
this.mAlertableImage.hidden = ! showIcon;
if (tabData.notificationProperties)
this._showNotification(aData.tab,tabData.notificationProperties);
break;
}

case "PageHide":
{
let tabData = this.wListener.getTabData(aData.tab,this.NOTIFICATION_NAME);
if ("redirect" in tabData)
{
if (++tabData.redirect.count > 2)
{
this.wListener.removeTabData(aData.tab,this.NOTIFICATION_NAME);
this.mAlertableImage.hidden = true;
}

}

break;
}

}
]]></body>
            </method>

            <method name="handleEvent">
                <parameter name="aEvent"/>
                <body><![CDATA[switch (aEvent.type) {
case "focus":
{
this._closeNotification();
break;
}

case "click":
{
if (aEvent.target === this.mAlertableImage)
{
if (this._whitelisted)
{
this._forceSendMistypedValue(this.mistyped);
return;
}

let tabData = this.wListener.getTabData(gBrowser.mCurrentBrowser,this.NOTIFICATION_NAME);
if (tabData.redirect)
{
this._showRollbackNotification({
changedFromURL: tabData.redirect.from,
changedToURL: tabData.redirect.to});
}
else
{
this.hideUrlbarImage();
}

return;
}

if (aEvent.target && (aEvent.target.id === "urlbar-go-button" || aEvent.target.id === "go-button"))
{
this._sendMistypedValue();
}

break;
}

case "keydown":
{
if (aEvent.keyCode !== KeyEvent.DOM_VK_RETURN)
return;
if (! (aEvent.target && aEvent.target.id === "urlbar"))
return;
this._sendMistypedValue();
break;
}

}
]]></body>
            </method>

            <constructor><![CDATA[this.mAlertableImage.addEventListener("click",this,false);
this.wListener.addListener("WindowLocationChange",this);
this.wListener.addListener("PageHide",this);
window.setTimeout((function (e) {
if ("_attachToNavigateElements" in this)
this._attachToNavigateElements();
}
).bind(this),0);]]></constructor>

            <destructor><![CDATA[this.mAlertableImage.removeEventListener("click",this,false);
this.wListener.removeListener("WindowLocationChange",this);
this.wListener.removeListener("PageHide",this);
this._detachFromNavigateElements();]]></destructor>
        </implementation>
    </binding>
</bindings>
