"use strict";
const EXPORTED_SYMBOLS = ["DataProvider"];
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
if ("nsIPrivateBrowsingChannel" in Ci)
XPCOMUtils.defineLazyModuleGetter(this,"PrivateBrowsingUtils","resource://gre/modules/PrivateBrowsingUtils.jsm"); else
this.PrivateBrowsingUtils = null;
const HTTP_OK = 200;
var DataProvider = {
SUGGEST_TIMEOUT: 500,
PROVIDER_NAME: "online-yandex-suggest",
DATA_SERVICE: "yaOmniBoxSuggestDataService",
_statData: {
exprt: 0,
r: 0,
time: 0},
init: function SuggestDataProvider_init(core) {
this._suggestsURL = core.brandingData.suggestionsURL;
this._core = core;
this.api = core.api;
this._searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
Cu.import(this.api.Package.resolvePath("/native/urlengine.js"),this);
this.URLEngine.init(this.api);
this._providerService = this.api.Services.obtainService(this.api.componentID,this.DATA_SERVICE,this);
if (! this._providerService)
return;
if (! this._providerService.registerDataProvider(this))
return;
}
,
observeServiceEvent: function SuggestDataProvider_observeServiceEvent(aProviderID, aServiceName, aTopic, aData) {
if (this.DATA_SERVICE != aServiceName || this.api.componentID != aProviderID)
return;
switch (aTopic) {
case "start-collecting":
this._startSearch(aData);
break;
case "stop-collecting":
this._stopSearch();
break;
}

}
,
_startSearch: function SuggestDataProvider__startSearch(aSearchStrings) {
this._stopSearch();
this._originalSearchString = aSearchStrings[0];
this._suggestions = [];
var searchProvidersEnabled = this.api.Settings.PrefsModule.get("browser.search.suggest.enabled",null);
var trimmedSearchString = this._trimmedSearchString = (aSearchStrings[0] || "").trim();
if (! trimmedSearchString || ! searchProvidersEnabled)
{
this._finishSearch(true);
return;
}

this.suggestURL = this._core.makeSuggestURLForString(trimmedSearchString);
if (! this.suggestURL)
{
this._finishSearch(true);
return;
}

var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
req.open("GET",this.suggestURL,true);
if (PrivateBrowsingUtils && req.channel instanceof Ci.nsIPrivateBrowsingChannel)
{
let topBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (topBrowserWindow)
req.channel.setPrivate(PrivateBrowsingUtils.isWindowPrivate(topBrowserWindow));
}

req.channel.notificationCallbacks = new SearchSuggestLoadListener();
var that = this;
this._requestTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._requestTimer.initWithCallback(function () that._finishSearch(true),this.SUGGEST_TIMEOUT,Ci.nsITimer.TYPE_ONE_SHOT);
function onReadyStateChange() that._onReadyStateChange(trimmedSearchString)
req.onreadystatechange = onReadyStateChange;
req.send(this.SUGGEST_POSTDATA);
this._time = new Date();
this._request = req;
}
,
_stopSearch: function SuggestDataProvider_stopSearch() {
if (this._request)
this._request.abort();
this._finishSearch(false);
}
,
_finishSearch: function SuggestDataProvider__finishSearch(aNotify) {
if (this._requestTimer)
{
this._requestTimer.cancel();
this._requestTimer = null;
}

if (aNotify)
this._notifyResults(false);
delete this._originalSearchString;
delete this._suggestions;
}
,
_notifyResults: function SuggestDataProvider__notifyResults() {
this._providerService.handleResponse("start-collecting",{
originalSearchStrings: [this._originalSearchString],
suggestions: this._suggestions,
stat: this._statData,
searchResult: Ci.nsIAutoCompleteResult.RESULT_SUCCESS},this);
}
,
_onReadyStateChange: function SuggestDataProvider__onReadyStateChange(aSearchString) {
if (aSearchString !== this._trimmedSearchString)
return;
if (! this._request || this._request.readyState != 4)
return;
this._handleResponse();
this._finishSearch(true);
}
,
_parseResponse: function SuggestDataProvider__parseResponse(responseText) {
var suggestionResults = [];
var navigationSuggest = [];
var comments = [];
var infoObject = {
};
try {
let res = JSON.parse(responseText)[1];
if (Array.isArray(res))
suggestionResults = res;
}
catch (e) {

}

try {
let res = JSON.parse(responseText)[2];
if (Array.isArray(res))
comments = res;
}
catch (e) {

}

try {
let res = JSON.parse(responseText)[4];
if (res && "object" == typeof res)
infoObject = res;
}
catch (e) {

}

var suggestTypes = [];
if (Array.isArray(infoObject["google:suggesttype"]))
{
suggestTypes = infoObject["google:suggesttype"];
}

var typesWeight = {
weather: 6,
traffic: 5,
market: 4,
lingvo: 3,
maps: 2,
units_converter: 1};
var answers = new Array(suggestionResults.length);
if (Array.isArray(infoObject["yandex:answer"]))
{
infoObject["yandex:answer"].forEach(function (answer) {
if (! (answer && typeof answer == "object" && typeof answer.answer == "object" && answer.type in typesWeight && answer.position))
return;
var position = parseInt(answer.position,10) - 1;
if (position < 0 || position > suggestionResults.length)
return;
var a = answers[position] || null;
if (! a || typesWeight[a.type] < typesWeight[answer.type])
answers[position] = answer;
}
);
}

var suggestions = [];
suggestionResults.forEach(function (res, index) {
var answerData = answers[index] || null;
var textComment = comments[index] || "";
var url = answerData && answerData.answer.url || this._getNavigationSuggestURL(res);
url = url && this.URLEngine.validateURL(url);
var showingText;
var showingURL = url;
if (answerData)
{
if (showingURL)
showingURL = this.URLEngine.getURIParam(showingURL,"host") || showingURL;
let image;
switch (answerData.type) {
case "units_converter":
showingText = suggestionResults[index];
break;
case "weather":
{
if (answerData.answer.image)
{
let url = "http://i.yandex.st/weather/i/icons/22x22/" + answerData.answer.image + ".png";
image = "<img data-type='weather' src='" + url + "'/>";
}

break;
}

case "traffic":
{
if (["green", "red", "yellow"].indexOf(answerData.answer.semaphore) != - 1)
{
let url = this.api.Package.resolvePath("/icons/traffic/" + answerData.answer.semaphore + ".png");
image = "<img data-type='traffic' src='" + url + "'/>";
}

break;
}

}

textComment = [answerData.answer.title, image, answerData.answer.text].filter(function (el) ! ! el).join(" ") || textComment;
}

var style = "yaSearchSuggest";
if (! showingText && showingURL)
{
if (index === 0 && suggestTypes[0] == "NAVIGATION")
style = "yaSuperNavigationSuggest"; else
style = "yaNavigationSuggest";
}

if (showingText)
style = "yaOfflineSearchHistory";
var suggest = {
value: showingText || showingURL || res,
comment: textComment,
image: "",
style: style};
if (url)
{
suggest.action = {
type: "openurl",
value: url};
}

suggestions.push(suggest);
}
,this);
return suggestions;
}
,
_handleResponse: function SuggestDataProvider__handleResponse(aSearchString) {
if (! this._request)
return;
var status;
try {
status = this._request.status;
}
catch (e) {

}

if (status != HTTP_OK)
return;
var responseText = this._request.responseText;
if (responseText == "")
return;
this._statData.time = new Date() - this._time;
this._suggestions = this._parseResponse(responseText);
}
,
_getNavigationSuggestURL: function SuggestDataProvider__getNavigationSuggestURL(aString) {
var [type, url] = this.URLEngine.getInputType(aString,true);
if (type == "url" && /^(https?|ftp):\/\//.test(url) && url.split("/")[2].indexOf(".") > 0)
{
return url;
}

return null;
}
};
function SearchSuggestLoadListener() {

}

SearchSuggestLoadListener.prototype = {
notifyCertProblem: function SSLL_certProblem() true,
notifySSLError: function SSLL_SSLError() true,
getInterface: function SSLL_getInterface(iid) this.QueryInterface(iid),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBadCertListener2, Ci.nsISSLErrorListener, Ci.nsIInterfaceRequestor])};
