const EXPORTED_SYMBOLS = ["bookmarks"];
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
var utils;
const bookmarks = {
_DEFAULT_FILE_PATH: "native/fx/templates",
init: function Bookmarks_init(api, expiredDays) {
if (! this._initialized)
{
this._initialized = true;
this._api = api;
Cu.import(this._api.Package.resolvePath("/native/fx/modules/utils.jsm"));
this._yauth = this._getModule("yauth","/native/fx/modules/yauth.jsm");
this.__proto__ = new utils.NotificationSource();
}

}
,
loadBookmarks: function Bookmarks_loadBookmarks(forceUpdate, onSuccess, onError) {
forceUpdate = forceUpdate || this._isBookmarksUpdateRequired;
if (forceUpdate)
{
let finalWrapper = function (domXMLResponse) {
var tree = {
id: "0",
name: "root",
type: "folder",
url: "zakladki.yandex.ru",
tags: null,
desc: "root",
children: [],
parentNode: null};
this._buildBookmarksTree(tree,domXMLResponse.querySelector(":root > bookmarks"));
this._cachedTree = tree;
this._yauth.user.insertBookmarksTreeOpt(tree,(function () {
delete this._cachedTree;
if (onSuccess)
onSuccess();
}
).bind(this));
}
;
utils.sendRequest("http://zakladki.yandex.ru/bar/index.xml?newdescr=true",{
background: true,
callbackFunc: this._responseHandler.bind(this,finalWrapper.bind(this),onError),
bypassCache: true});
}
 else
{
if (onSuccess)
onSuccess();
}

}
,
_buildBookmarksTree: function Bookmarks__buildBookmarksTree(root, xmlBookmarks) {
var childs = xmlBookmarks.childNodes;
for (let i = 0, length = childs.length;i < length;i++) {
let node = childs[i];
if (node.nodeType !== node.ELEMENT_NODE)
continue;
if (node.localName === "folder")
{
let desc = node.querySelector("descr");
let folder = {
id: node.getAttribute("id"),
name: node.getAttribute("name"),
type: "folder",
tags: null,
url: null,
desc: desc.firstChild && desc.firstChild.nodeValue,
children: [],
parentNode: root};
root.children.push(folder);
this._buildBookmarksTree(folder,node);
}

if (node.localName === "links")
{
let links = node.querySelectorAll("link");
Array.prototype.forEach.call(links,function (link) {
var desc = link.querySelector("descr");
root.children.push({
id: link.getAttribute("id"),
name: link.getAttribute("name").trim() || link.getAttribute("url"),
type: "link",
tags: link.getAttribute("tags"),
url: link.getAttribute("url"),
desc: desc.firstChild && desc.firstChild.nodeValue,
parentNode: root});
}
);
}

}

}
,
_BOOKMARKS_UPDATE_PERIOD: 24 * 60 * 60,
get _isBookmarksUpdateRequired() {
if (! this._yauth.user)
return false;
var prevUpdate = this._yauth.user.getBookmarkTreeVersion();
return (Date.now() - prevUpdate) / 1000 > this._BOOKMARKS_UPDATE_PERIOD;
}
,
getBookmarksTree: function Bookmarks_getBookmarksTree(folderId) {
var arrBookmarks;
if (this._cachedTree)
{
if (folderId == 0)
{
arrBookmarks = this._cachedTree.children;
}
 else
{
arrBookmarks = this._selectBookmarksFromCache(this._cachedTree,folderId);
}

}
 else
{
arrBookmarks = this._yauth.user.selectBookmarkTree(folderId);
}

return arrBookmarks;
}
,
_selectBookmarksFromCache: function Bookmarks__selectBookmarksFromCache(bookmark, folderId) {
if (bookmark.id == folderId)
return bookmark.children;
var startIndex = 0;
var children = bookmark.children;
while (startIndex < children.length) {
let child = children[startIndex];
if (child.type == "folder")
{
if (child.id == folderId)
{
return child.children;
}
 else
{
children.concat(child.children);
}

}

startIndex++;
}

return null;
}
,
selectBookmarksStructure: function Bookmarks_selectBookmarksStructure() {
var folders = this._yauth.user.selectFolders();
folders.sort(function (a, b) {
var titleALower = a.name.toLowerCase(), titleBLower = b.name.toLowerCase();
return titleALower < titleBLower ? - 1 : titleALower > titleBLower ? 1 : 0;
}
);
var i = 0, j, len = folders.length;
for (j = 0;j < len;j++) {
folders[j].children = [];
}

while (i < len) {
let child = folders[i];
for (j = 0;j < len;j++) {
if (i != j)
{
if (child.parentId == folders[j].id)
{
child.parentNode = folders[j];
folders[j].children.push(child);
break;
}

}

}

i++;
}

for (j = 0;j < len;j++) {
if (folders[j].id == 0)
return folders[j];
}

}
,
addBookmarkFolder: function Bookmarks_addBookmarkFolder(folderData, onSuccess, onError) {
var strURL = "http://zakladki.yandex.ru/bar/addfolder.xml?" + utils.getNCRndStr();
var data = "name=" + encodeURIComponent(folderData.name) + "&parent_id=" + folderData.folder;
var finalWrapper = function (domXMLResponse) {
var id = domXMLResponse.querySelector("ok").getAttribute("id");
var bookmarkData = {
id: id,
name: folderData.name,
type: "folder",
parentId: folderData.folder,
url: null,
tags: null,
desc: ""};
var inserted = this._yauth.user.saveBookmark(bookmarkData);
if (onSuccess)
onSuccess(id);
}
;
utils.sendRequest(strURL,{
data: data,
timeout: 10000,
callbackFunc: this._responseHandler.bind(this,finalWrapper.bind(this),onError)});
}
,
editBookmark: function Bookmarks_editBookmark(bookmarkData, onSuccess, onError) {
var strURL = "http://zakladki.yandex.ru/bar/update" + bookmarkData.type + ".xml?" + utils.getNCRndStr();
var data = bookmarkData.type + "_id=" + bookmarkData.id + "&name=" + encodeURIComponent(bookmarkData.name) + "&descr=" + encodeURIComponent(bookmarkData.desc) + "&tags=" + encodeURIComponent(bookmarkData.tags);
if (bookmarkData.type == "link")
{
data += "&url=" + encodeURIComponent(bookmarkData.url);
}

var finalWrapper = function (domXMLResponse) {
var inserted = this._yauth.user.saveBookmark(bookmarkData);
if (onSuccess)
onSuccess(domXMLResponse);
}
;
utils.sendRequest(strURL,{
data: data,
timeout: 10000,
callbackFunc: this._responseHandler.bind(this,finalWrapper.bind(this),onError)});
}
,
getStructure: function Bookmarks_getStructure(onSuccess, onError) {
utils.sendRequest("http://zakladki.yandex.ru/bar/struct.xml?newdescr=true&" + utils.getNCRndStr(),{
timeout: 10000,
callbackFunc: this._responseHandler.bind(this,onSuccess,onError)});
}
,
addBookmark: function Bookmarks_addBookmark(bookmarkData, onSuccess, onError) {
var addonType = this._api.Environment.addon.type;
var onStructureSuccess = function (domXMLResponse) {
var xmlFolders = domXMLResponse.querySelectorAll("folder");
var parentId = bookmarkData.parentId;
var parentSelector = "folder[id=\"" + parentId + "\"]";
var parentFolder = domXMLResponse.querySelector(parentSelector);
bookmarkData.parentId = parentFolder ? parentId : "0";
var strURL = "http://zakladki.yandex.ru/bar/addlink.xml?" + utils.getNCRndStr();
var yaRuData = bookmarkData.yaru ? ["feed_id=" + encodeURIComponent(bookmarkData.yaru.feed_id), "status=" + encodeURIComponent(bookmarkData.yaru.status)] : [];
var data = ["name=" + encodeURIComponent(bookmarkData.name), "url=" + encodeURIComponent(bookmarkData.url), "descr=" + encodeURIComponent(bookmarkData.desc), "tags=" + encodeURIComponent(bookmarkData.tags), "folder_id=" + (bookmarkData.parentId || 0), "newfolder=", "from=" + encodeURIComponent(addonType)].concat(yaRuData);
var finalWrapper = function (domXMLResponse) {
bookmarkData.id = domXMLResponse.querySelector("ok").getAttribute("id");
var inserted = this._yauth.user.saveBookmark(bookmarkData);
if (onSuccess)
onSuccess(domXMLResponse);
}
;
utils.sendRequest(strURL,{
data: data.join("&"),
timeout: 10000,
callbackFunc: this._responseHandler.bind(this,finalWrapper.bind(this),onError)});
if (! parentFolder)
{
let folders = [];
for (let i = 0, length = xmlFolders.length;i < length;i++) {
let folder = {
id: xmlFolders[i].getAttribute("id"),
name: xmlFolders[i].getAttribute("name"),
type: "folder",
tags: null,
url: null,
desc: xmlFolders[i].getAttribute("descr"),
parentId: xmlFolders[i].getAttribute("parent_id")};
folders.push(folder);
}

this._yauth.user.updateFolders(folders);
}

}
;
this.getStructure(onStructureSuccess.bind(this),onError);
}
,
moveBookmark: function Bookmarks_moveBookmark(bookmarkData, onSuccess, onError) {
var onStructureSuccess = function (domXMLResponse) {
var xmlFolders = domXMLResponse.querySelectorAll("folder");
var parentId = bookmarkData.parentId;
var parentSelector = "folder[id=\"" + parentId + "\"]";
var parentFolder = domXMLResponse.querySelector(parentSelector);
if (parentFolder)
{
let strURL = "http://zakladki.yandex.ru/bar/move.xml?" + utils.getNCRndStr();
let data = "folder_id=" + bookmarkData.parentId + "&" + (bookmarkData.type == "folder" ? "fid" : "link_id") + "=" + bookmarkData.id;
let finalWrapper = function () {
var inserted = this._yauth.user.moveBookmark(bookmarkData);
if (onSuccess)
onSuccess(bookmarkData.id);
}
;
utils.sendRequest(strURL,{
data: data,
callbackFunc: this._responseHandler.bind(this,finalWrapper.bind(this),onError)});
}
 else
{
let folders = [];
for (let i = 0, length = xmlFolders.length;i < length;i++) {
let descr = xmlFolders[i].querySelector("descr");
let folder = {
id: xmlFolders[i].getAttribute("id"),
name: xmlFolders[i].getAttribute("name"),
type: "folder",
tags: null,
url: null,
desc: descr.firstChild && descr.firstChild.nodeValue,
parentId: xmlFolders[i].getAttribute("parent_id")};
folders.push(folder);
}

this._yauth.user.updateFolders(folders);
if (onSuccess)
onSuccess();
}

}
;
this.getStructure(onStructureSuccess.bind(this),onError);
}
,
deleteBookmark: function Bookmarks_deleteBookmark(bookmarkData, onSuccess, onError) {
var strURL = "http://zakladki.yandex.ru/bar/del.xml?" + utils.getNCRndStr();
var data = (bookmarkData.type == "folder" ? "fid" : "link_id") + "=" + bookmarkData.id;
var finalWrapper = function () {
var inserted = this._yauth.user.deleteBookmark(bookmarkData.id);
if (onSuccess)
onSuccess();
}
;
utils.sendRequest(strURL,{
data: data,
callbackFunc: this._responseHandler.bind(this,finalWrapper.bind(this),onError)});
}
,
subscribe: function Bookmarks_subscribe(onSuccess, onError) {
var strURL = "http://passport.yandex.ru/passport?mode=subscribe&from=zakladki&" + utils.getNCRndStr();
var finalWrapper = function (req) {
if (! utils.isReqError(req))
{
if (onSuccess)
onSuccess();
}
 else
{
if (onError)
onError(req.target.status);
}

}
;
utils.sendRequest(strURL,{
callbackFunc: finalWrapper});
}
,
getYaRuFriendsList: function Bookmarks_getYaRuFriendsList(strUsername, onSuccess, onError) {
var strURL = "http://zakladki.yandex.ru/bar/getfriendlast.xml?" + utils.getNCRndStr();
var destDoc = this._api.XMLUtils.getDOMParser(null,null,true).parseFromString("<emptyDoc/>","text/xml");
var xulBuilder = (function (domXMLResponse) {
var xul = this._api.XMLUtils.transformXMLToFragment(domXMLResponse,this._xslBookmarksYaRuListDoc,destDoc,{
login: strUsername});
if (onSuccess)
onSuccess(xul);
}
).bind(this);
var onErrorWrapper = (function (strError) {
var domXMLError = this._api.XMLUtils.getDOMParser(null,null,false).parseFromString("<yaru error=\"true\"/>","text/xml");
var xul = this._api.XMLUtils.transformXMLToFragment(domXMLError,this._xslBookmarksYaRuListDoc,destDoc);
if (onError)
onError(xul);
}
).bind(this);
var request = utils.sendRequest(strURL,{
callbackFunc: this._responseHandler.bind(this,xulBuilder,onErrorWrapper),
timeout: 10000});
}
,
getYaRuCommunities: function Bookmarks_getYaRuCommunities(onSuccess, onError) {
var strURL = "http://zakladki.yandex.ru/bar/getcommunities.xml?" + utils.getNCRndStr();
utils.sendRequest(strURL,{
callbackFunc: this._responseHandler.bind(this,onSuccess,onError)});
}
,
_responseHandler: function Bookmarks__responseHandler(onSuccess, onError, req) {
var strErrorMsg = "";
if (! utils.isReqError(req))
{
let domXMLResponse = this._api.XMLUtils.getDOMParser(null,null,false).parseFromString(utils.createXMLString(req.target.responseText),"text/xml");
let xmlError = domXMLResponse.querySelector("err");
let xmlXScriptFailed = domXMLResponse.querySelector("xscript_invoke_failed");
if (xmlError)
{
strErrorMsg = xmlError.firstChild.nodeValue;
if ("spam" === xmlError.getAttribute("code"))
{
strErrorMsg = "spam";
}
 else
{
if (strErrorMsg.indexOf("Exception:") !== - 1)
{
strErrorMsg = strErrorMsg.replace("Exception:","").trim();
}

}

}
 else
if (xmlXScriptFailed)
{
strErrorMsg = "CORBA:" + xmlXScriptFailed.getAttribute("error");
}
 else
{
if (onSuccess)
onSuccess(domXMLResponse);
return;
}

}
 else
{
if (req.target.timeout && ! req.target.status)
{
strErrorMsg = "timeout";
}
 else
{
strErrorMsg = req.target.status;
}

}

if (onError)
onError(strErrorMsg);
}
,
_BOOKMARKS_YARU_LIST_XSL: "xsl-yaru-friends-links.xsl",
get _xslBookmarksYaRuListDoc() {
var xslDoc = null;
try {
let filePath = this._DEFAULT_FILE_PATH + "/" + this._BOOKMARKS_YARU_LIST_XSL;
let channel = this._api.Package.getFileInputChannel(filePath);
xslDoc = this._api.XMLUtils.xmlDocFromStream(channel.contentStream,utils.newURI(this._api.Package.resolvePath(filePath),null,null),null,true);
delete this._xslBookmarksYaRuListDoc;
this.__defineGetter__("_xslBookmarksYaRuListDoc",function () xslDoc);
return xslDoc;
}
catch (ex) {
this._api.logger.error(ex);
return null;
}

}
,
_getModule: function Bookmarks__getModule(moduleName, modulePath) {
var mScope = {
};
Cu.import(this._api.Package.resolvePath(modulePath),mScope);
var module = mScope[moduleName];
if (! module)
throw new Error("No module '" + moduleName + "' in " + modulePath);
if (typeof module.init == "function")
module.init(this._api);
return module;
}
};
