function Rimzu() {}
Rimzu.serviceUrl = "http://www.rimzu.com/RimzuService";

/// Use this for functions returning non-arrays
Rimzu.rimzuInvoke = function(funcName, isArray, args, callback, context) {
    if (typeof(callback) != 'undefined') {
        SOAPClient.invoke(Rimzu.serviceUrl, funcName, isArray, args, true, callback, context);
    } else {
        var result;
        try {
            result = SOAPClient.invoke(Rimzu.serviceUrl, funcName, isArray, args, false);
        } catch (e) {
            alert("Exception: " + e.message + " in " + funcName);
            throw e;
        }
        //return result['return'];

        return result;
    }
}

Rimzu.prototype.getNumUsers = function(callback, context) {
    var pl = new SOAPClientParameters();

    return Rimzu.rimzuInvoke("getNumUsers", false, pl, callback, context);
}


Rimzu.prototype.requestInvitation = function(email, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("email", email);

    return Rimzu.rimzuInvoke("requestInvitation", false, pl, callback, context);
}


Rimzu.prototype.login = function(user, password, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("user", user);
    pl.add("password", password);

    return Rimzu.rimzuInvoke("login", false, pl, callback, context);
}


Rimzu.prototype.newUser = function(email, token, user, password, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("email", email);
    pl.add("token", token);
    pl.add("user", user);
    pl.add("password", password);

    return Rimzu.rimzuInvoke("newUser", false, pl, callback, context);
}


Rimzu.prototype.logout = function(callback, context) {
    var pl = new SOAPClientParameters();

    return Rimzu.rimzuInvoke("logout", false, pl, callback, context);
}


Rimzu.prototype.getUserId = function(callback, context) {
    var pl = new SOAPClientParameters();

    return Rimzu.rimzuInvoke("getUserId", false, pl, callback, context);
}

Rimzu.getUsersInfoCallback = function(isError, usersInfo, context) {
    if (!isError) { // if we have a real userInfo, fix its date.
        for (var i = 0; i < usersInfo.length; ++i) {
            usersInfo[i].birthday = Rimzu.stringToDate(usersInfo[i].birthday);
        }
    }

    // delegate to user-provided callback
    return context.callback(isError, usersInfo, context.realContext);
}

Rimzu.prototype.getUsersInfo = function(userIds, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userIds", userIds);

    var dummyContext = { callback : callback, realContext : context };

    if (callback == undefined) {    // in synchronous calls, fix the birthday in the returned value
        var usersInfo = Rimzu.rimzuInvoke("getUsersInfo", true, pl);
        for (var i = 0; i < usersInfo.length; ++i) {
            usersInfo[i].birthday = Rimzu.stringToDate(usersInfo[i].birthday);
        }
        return usersInfo;
    } else {  // asynchronous call - the callback will fix the birthday
        return Rimzu.rimzuInvoke("getUsersInfo", true, pl, Rimzu.getUsersInfoCallback, dummyContext);
    }
}


Rimzu.stringToDate = function(sdate) {
    if (sdate == undefined) {
        return undefined;
    }
    var value = sdate;
    value = value + "";
    value = value.substring(0, (value.lastIndexOf("T") == -1 ? value.length : value.lastIndexOf("T")));
    value = value.replace(/-/gi,"/");

    var d = new Date();
    d.setTime(Date.parse(value));										
    return d;				
}


Rimzu.getUserInfoCallback = function(isError, userInfo, context) {
    if (!isError) { // if we have a real userInfo, fix its date.
        userInfo.birthday = Rimzu.stringToDate(userInfo.birthday);
    }

    // delegate to user-provided callback
    return context.callback(isError, userInfo, context.realContext);
}


Rimzu.prototype.getUserInfo = function(userId, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userId", userId);

    var dummyContext = new Object();
    dummyContext.callback = callback;
    dummyContext.realContext = context;

    if (callback == undefined) {    // in synchronous calls, fix the birthday in the returned value
        var userInfo = Rimzu.rimzuInvoke("getUserInfo", false, pl);
        userInfo.birthday = Rimzu.stringToDate(userInfo.birthday);
        return userInfo;
    } else {  // asynchronous call - the callback will fix the birthday
        return Rimzu.rimzuInvoke("getUserInfo", false, pl, Rimzu.getUserInfoCallback, dummyContext);
    }
}


Rimzu.prototype.setUserInfo = function(userInfo, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userInfo", userInfo);

    return Rimzu.rimzuInvoke("setUserInfo", false, pl, callback, context);
}


Rimzu.prototype.changePassword = function(newPassword, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("newPassword", newPassword);

    return Rimzu.rimzuInvoke("changePassword", false, pl, callback, context);
}


Rimzu.prototype.getContacts = function(userId, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userId", userId);

    return Rimzu.rimzuInvoke("getContacts", true, pl, callback, context);
}


Rimzu.prototype.inviteUserToContacts = function(userId, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userId", userId);

    return Rimzu.rimzuInvoke("inviteUserToContacts", false, pl, callback, context);
}


Rimzu.prototype.inviteEmailToContacts = function(email, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("email", email);

    return Rimzu.rimzuInvoke("inviteEmailToContacts", false, pl, callback, context);
}


Rimzu.prototype.removeUserFromContacts = function(userId, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userId", userId);

    return Rimzu.rimzuInvoke("removeUserFromContacts", false, pl, callback, context);
}


Rimzu.prototype.getPendingInvitations = function(callback, context) {
    var pl = new SOAPClientParameters();

    return Rimzu.rimzuInvoke("getPendingInvitations", true, pl, callback, context);
}


Rimzu.prototype.rejectInvitation = function(userId, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("userId", userId);

    return Rimzu.rimzuInvoke("rejectInvitation", false, pl, callback, context);
}


Rimzu.prototype.requestQuestion = function(callback, context) {
    var pl = new SOAPClientParameters();

    return Rimzu.rimzuInvoke("requestQuestion", false, pl, callback, context);
}


Rimzu.prototype.answerQuestion = function(answerUserId, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("answerUserId", answerUserId);

    return Rimzu.rimzuInvoke("answerQuestion", false, pl, callback, context);
}


Rimzu.prototype.getLatestRankings = function(callback, context) {
    var pl = new SOAPClientParameters();

    return Rimzu.rimzuInvoke("getLatestRankings", true, pl, callback, context);
}


Rimzu.prototype.getRankings = function(rankingDate, callback, context) {
    var pl = new SOAPClientParameters();
    pl.add("date", rankingDate);

    return Rimzu.rimzuInvoke("getRankings", true, pl, callback, context);
}

// --------------------------------------------------------------------- //

function RimzuRanking(traitId, percentile, lowPercentile, highPercentile) {
    this.traitId = traitId;
    this.percentile = percentile;
    this.lowPercentile = lowPercentile;
    this.highPercentile = highPercentile;
}

function Trait(traitAdjective, traitNoun) {
    this.traitAdjective = traitAdjective;
    this.traitNoun = traitNoun;
}

function UserInfo(firstName, lastName, birthday, email) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.birthday = birthday;
    this.email = email;
}

