EXPORTED_SYMBOLS = ["module"];

var module = function (app, common) { 
    function log(str) {
        app.log("[API]: " + str);
    }
    function logObj(ob, pref) {
        app.logObj(ob, "[API]: " + (pref || ""));
    }
    function logr(str) {
        app.logr("[API]: " + str);
    }

    var queries = {
        "me": {
            query: "SELECT uid, name FROM user WHERE uid = me()",
            parser: function (fql_result_set) {
                var user = fql_result_set[0];
                return {
                    loggedIn: true,
                    user: user
                }
            }
        },
        "notif": {
            query: "SELECT title_text FROM notification WHERE recipient_id = me() AND is_unread = 1 LIMIT 101",
            parser: function (fql_result_set) {
                return {
                    notifications_count: fql_result_set.length,
                    notifications: fql_result_set
                }
            }
        },
        "friendrequests": {
            query: "SELECT uid_from FROM friend_request WHERE uid_to = me() LIMIT 101",
            parser: function (fql_result_set) {
                return {
                    friend_requests_count: fql_result_set.length,
                    friend_requests: fql_result_set
                }
            }
        },
        "usernameresolver": {
            query: "SELECT uid, name FROM user WHERE " +
                    "uid IN (SELECT uid_from FROM #friendrequests) " +
                    "OR uid IN (SELECT snippet_author FROM #messages)",
            
            parser: function (fql_result_set) {
                return {
                    users: fql_result_set
                }
            }
        },
        "messages_count": {
            query: "SELECT unread_count FROM mailbox_folder WHERE folder_id = 0",
            parser: function (fql_result_set) {
                var result = fql_result_set[0];
                return {
                    messages_count: result.unread_count
                }
            }
        },
        "messages": {
            query: "SELECT thread_id, snippet_author, subject FROM thread WHERE folder_id = 0 AND unread != 0 LIMIT 10",
            parser: function (fql_result_set) {
                return {
                    messages: fql_result_set
                }
            }
        }
    };

    var errCount = 0;
    var maxErrCount = 2;
    var cookieMgr;
    
    return {
        userData: {},
        updating: null,
        _userId: "",
        _cred: {},
        _callbacks: null,
        init: function(callbacks) {
            this._callbacks = callbacks;
            cookieMgr = app.importModule('cookie');
        },
        setCredentials: function(userCred) {
            this._cred = userCred;
            var id = cookieMgr.getUserId();
            if (id != this._userId) {
                this.clearData();
                this._userId = id;
            }
        },
        clearData: function() {
            this.userData = {};
            this._userId = "";
            errCount = 0;
        },
        _abort: function() {
            if (this.updating) {
                this.updating.abort();
                this.updating = null;
            }
        },
        _setCounterData: function(counterData) {
            this.userData = counterData;
        },
        _handleError: function(st, text) {
            if (text != "abort") {
                errCount++;
            }
            this.userData.error = [st, text];
            if (errCount >= maxErrCount) {
                errCount = 0;
                var counterData = {
                    loggedIn: true,
                    user: this.userData.user,
                    error: this.userData.error
                };
                this._setCounterData(counterData);
                this._callbacks.onUpdate();
            }
            this._callbacks.onUpdateError(st, text);
        },
        _errorTypesMap: {
            190: [401, "*token*"],
            102: [401, "*token*"],
            1: [500, "*server*"],
            2: [500, "*server*"],
            4: [429, "*many*"],
            17: [429, "*many*"],
            10: [403, "*denied*"],
            200: [403, "*denied*"]
        },
        _parseResult: function(res) {
            if ("error_code" in res) {
                logObj(res, "FQL error:");
                var code = Math.min(res.error_code, 200);
                this._handleError.apply(this, this._errorTypesMap[code] || [0, "error"]);
                return;
            }
            var i, counterData = {};
            for (i = 0, l = res.length; i < l; ++i) {
                var response = res[i];
                var name = response.name;
                if (name in queries) {
                    var result_set = response.fql_result_set;
                    if (result_set) {
                        counterData = common.utils.copy(queries[name].parser(result_set), counterData);
                    }
                }
            }
            if (counterData.users) {
                var map = {};
                for (i = 0, l = counterData.users.length; i < l; ++i) {
                    map[counterData.users[i].uid] = counterData.users[i];
                }
                if (counterData.friend_requests) {
                    for (i = 0, l = counterData.friend_requests.length; i < l; ++i) {
                        counterData.friend_requests[i]._profile = map[counterData.friend_requests[i].uid_from];
                    }
                }
                if (counterData.messages) {
                    for (i = 0, l = counterData.messages.length; i < l; ++i) {
                        counterData.messages[i]._profile = map[counterData.messages[i].snippet_author];
                    }
                }
            }
            logObj(counterData, "counterData");
            this._setCounterData(counterData);
            this._callbacks.onUpdate();
        },
        _execFQL: function(query, callback, errback) {
            var method = "fql.query", queryField = "query";
            if (typeof query == "object") {
                method = "fql.multiquery";
                query = JSON.stringify(query);
                queryField = "queries";
            }
            log("execFQL, query = " + query);
            var params = {};
            params[queryField] = query;
            
            var headers = {
                "Authorization": "OAuth " + this._cred.access_token, //.replace(/\d/, 'h'),
                "Accept-Charset": null,
                "Accept-Language": null,
                "Accept": null,
                "Connection": null,
                "Keep-Alive": null,
                "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
            };
            return common.http.POST({
                url: app.config.FBdomain.api + "method/" + method + "?format=json",
                background: true,
                anonymous: true,
                scope: this,
                responseType: 'json',
                params: params,
                headers: headers,
                timeout: 10000,
                callback: callback,
                errback: errback
            });
        },
        
        update: function(force) {
            if (force) {
                this._abort();
            }
            if (this.updating) {
                return;
            }
            log("update");
			
			var q = {};
			for (var i in queries) {
				q[i] = queries[i].query;
			}
            
            logObj(q, "query");
			
			this.updating = this._execFQL(q, function (result, xhr) {
                    this.updating = false;
                    this._parseResult(result);
                },
                function (status, text) {
					log("FQL error (network): status=" + status + " text=" + text);
					this.updating = false;
                    this._handleError(status, text);
				});
        }
    };
};