function PMOResetPasswordRequest(userName) {
    if (userName == null || userName == undefined || userName == "") {
        PMError('Username cannot be blank');
        return false;
    }

    var postParams = buildPostParams('resetPasswordRequest');
    var params = new postParam()

    params.addParam("userName", userName);
    postParams.addParam('doc', params.getListAsDoc());

    var xml = talkPost_sync(bu.XMLHandler, postParams);

    if (xml == null || getStatus(xml) == null)
        return false;

    return getStatus(xml) == 'email sent';
}


function PMOResetPassword(userName, password, resetKey) {
    if (userName == null || userName == undefined || userName == "") {
        PMError('Username cannot be blank');
        return false;
    }
    if (password == null || password == undefined || password == "") {
        PMError('password cannot be blank');
        return false;
    }
    if (resetKey == null || resetKey == undefined || resetKey == "") {
        PMError('Reset Key cannot be blank');
        return false;
    }
    var params = new postParam()
    params.addParam("authHash", getAuthHash());
    params.addParam("userName", userName);
    params.addParam("password", password);
    params.addParam("resetKey", resetKey);

    var xml = talkPost_sync(bu.passwordReset, params, true);

    if (xml == null || getNodeValue(xml, 'passwordIsReset') == null)
        return false;

    return getNodeValue(xml, 'passwordIsReset') == 1;
}

function PMOLogin(userName, password, rememberUser) {
    var authHash = getAuthHash();
    params = new postParam()
    params.addParam("userName", userName);
    params.addParam("passwordHash", hex_md5(password));
    params.addParam("authHash", authHash);
    var xml = talkPost_sync(bu.Connect, params);
    
    if (xml == null)
        return false;
    var status = getStatus(xml);

    if (status != "logged in") {
        PMError('invalid reponse from login attempt. Status was found but was "' + status + '". Expected "logged in"');
        return false
    }

    authKey = XMLObj.getElementsByTagName("authKey")[0].firstChild.nodeValue;
    
    if (rememberUser == undefined || rememberUser == null)
        rememberUser = false;

    setCookie("authKey", authKey, !rememberUser); //3rd param is Expires? so it is right to negate it.
    setCookie("authHash", authHash, !rememberUser);
    setCookie("emailAddress", userName, false);
   
    return true;
    
}

function PMOUser() {
    this.isValid = false;
    this.passwordHash = null;

    var postParams = buildPostParams('getUser');
    var xml = talkPost_sync(bu.XMLHandler, postParams);
    if (xml == null || getNodeValue(xml, 'userName') == null) {
        return false;
    }

    this.userName = getNodeValue(xml, 'userName');
    this.firstName = getNodeValue(xml, 'firstName');
    this.screenName = getNodeValue(xml, 'screenName')
    this.isAnon = getNodeValue(xml, 'usageIsAnon') == 1;
    this.passwordReminder = getNodeValue(xml, 'passwordReminder');
    this.timeZone = getNodeValue(xml, 'timezone');

    var loc = new Location();
    this.countryCode = getNodeValue(xml, 'countryCode') == '--' ? loc.country_code : getNodeValue(xml, 'countryCode');
    this.region = getNodeValue(xml, 'region') == '--' ? loc.region : getNodeValue(xml, 'region');
    this.city = getNodeValue(xml, 'city') == '--' ? loc.city : getNodeValue(xml, 'city');

    this.isValid = true;

    this.External = new function() {
        this.Timeline = function() {

            var _width = 0;
            var _height = 0;
            var _colour = null;
            var _enabled = false;
            var _key = "";

            this.width = _width;
            this.height = _height;
            this.colour = _colour;
            this.enabled = _enabled;
            this.key = _key;
            this.code = "";

            this.load = function() {

                var postParams = buildPostParamsNew('getUserSparkLine');

                var oOptions = {
                    asynchronous: false,
                    method: 'post',
                    parameters: postParams.paramString,
                    onSuccess: function(oXHR, oJSON) {
                        //    alert(oXHR.responseXML.xml);
                        //alert(getNodeValue(xml, 'ddd'));
                        var xml = CreateXMLStringParser(oXHR.responseXML, postParams.handShake);

                        if (xml == null) {
                            return false;
                        }
                        _width = getNodeValue(xml, 'width');
                        _height = getNodeValue(xml, 'height');
                        _colour = getNodeValue(xml, 'colour');
                        _enabled = getNodeValue(xml, 'enabled') == '1';
                        _key = getNodeValue(xml, 'key');
                    },
                    onFailure: function(oXHR, oJSON) {
                        alert("Failed to obtain data from Server.");
                    }
                }
                var oReq = new Ajax.Request(bu.XMLHandler, oOptions);

                this.width = _width;
                this.height = _height;
                this.colour = _colour;
                this.enabled = _enabled;
                this.key = _key;
                this.code = '<a href="' + _baseURL + '?view=' + this.key + '" target="_new"><img src="' + _baseURL + '/gadgets/pmo/mygraph.php?p=' + this.key + '" border="0"></a>';
            }

            this.save = function() {
                var userDoc = new postParam();

                userDoc.addParam("width", this.width);
                userDoc.addParam("height", this.height);
                userDoc.addParam("colour", this.colour);
                userDoc.addParam("enabled", this.enabled);
                var postParams = new buildPostParamsNew('saveUserSparkLine', userDoc);
                var oOptions = {
                    method: 'post',
                    parameters: postParams.paramString,
                    onSuccess: function(oXHR, oJSON) {
                        //alert(oXHR.responseText);
                        var xml = CreateXMLStringParser(oXHR.responseXML, postParams.handShake);
                        if (xml == null) {
                            return false;
                        }
                        //                        alert(getNodeValue(oXHR.responseXML, 'Saved'));
                        //                        if (getNodeValue(xml, 'Saved') == "1") {
                        alert("Saved");
                        //                        }
                        //                        else {
                        //                            alert("Could not Save");
                        //                        }
                        //                        //                        _height = getNodeValue(xml, 'height');
                        //                        _colour = getNodeValue(xml, 'colour');
                        //                        _enabled = getNodeValue(xml, 'enabled') == '1';
                    },
                    onFailure: function(oXHR, oJSON) {
                        alert("Failed to save information.");
                    }
                }
                var oReq = new Ajax.Request(bu.XMLHandler, oOptions);

            }
        } //end timeline
    } //end External
    this.getFriendList = function() {
        var arr = new Array();

        var userDoc = new postParam();
        var postParams = new buildPostParamsNew('getFriendList', userDoc);
        var oOptions = {
            asynchronous: false,
            method: 'post',
            parameters: postParams.paramString,
            onSuccess: function(oXHR, oJSON) {
                //alert(oXHR.responseText);
                var xml = CreateXMLStringParser(oXHR.responseXML, postParams.handShake);
                if (xml == null) {
                    return false;
                }
                var fNodes = xml.getElementsByTagName('f');
                for (var i = 0; i <= fNodes.length - 1; i++) {
                    arr[i] = { screenName: fNodes[i].getAttribute("sn"), publicKey: fNodes[i].getAttribute("pk") };
                }
                return arr;
            },
            onFailure: function(oXHR, oJSON) {
                alert("Failed to save information.");
            }
        }
        var oReq = new Ajax.Request(bu.XMLHandler, oOptions);

        return arr;
    }     //end friends list
    this.getOtherUsersList = function() {
        var arr = new Array();

        var userDoc = new postParam();
        var postParams = new buildPostParamsNew('getFriendOtherUsersList', userDoc);
        var oOptions = {
            asynchronous: false,
            method: 'post',
            parameters: postParams.paramString,
            onSuccess: function(oXHR, oJSON) {
//                alert(oXHR.responseText);
                var xml = CreateXMLStringParser(oXHR.responseXML, postParams.handShake);
                if (xml == null) {
                    return false;
                }
                var fNodes = xml.getElementsByTagName('f');
                for (var i = 0; i <= fNodes.length - 1; i++) {
                    arr[i] = { screenName: fNodes[i].getAttribute("sn"), publicKey: fNodes[i].getAttribute("pk") };
                }
                return arr;
            },
            onFailure: function(oXHR, oJSON) {
                alert("Failed to save information.");
            }
        }
        var oReq = new Ajax.Request(bu.XMLHandler, oOptions);

        return arr;
    }      //end friends list
    this.getFollowersList = function() {
        var arr = new Array();

        var userDoc = new postParam();
        var postParams = new buildPostParamsNew('getFollowersList', userDoc);
        var oOptions = {
            asynchronous: false,
            method: 'post',
            parameters: postParams.paramString,
            onSuccess: function(oXHR, oJSON) {
                //alert(oXHR.responseText);
                var xml = CreateXMLStringParser(oXHR.responseXML, postParams.handShake);
                if (xml == null) {
                    return false;
                }
                var fNodes = xml.getElementsByTagName('f');
                for (var i = 0; i <= fNodes.length - 1; i++) {
                    arr[i] = { screenName: fNodes[i].getAttribute("sn"), publicKey: fNodes[i].getAttribute("pk") };
                }
                return arr;
            },
            onFailure: function(oXHR, oJSON) {
                alert("Failed to load followers.");
            }
        }
        var oReq = new Ajax.Request(bu.XMLHandler, oOptions);

        return arr;
    }     //end followers


    this.update = _updatePMOUser;
    return true;
}

function _updatePMOUser() {
    //valdate
    throwIf(this.userName, "", "userName cannot be blank");
    throwIf(this.screenName, "", "screenName cannot be blank");
    throwIf(this.passwordHash, hex_md5('zzzzzfakepasswordzzzzz'), "password cannot be zzzzzfakepasswordzzzzz");

    var postParams = buildPostParams('updateUser');
    var userDoc = new postParam();

    userDoc.addParam("userName", this.userName);
    userDoc.addParam("firstName", this.firstName);
    userDoc.addParam("screenName", this.screenName);
    userDoc.addParam("isAnon", this.isAnon);
    userDoc.addParam("passwordReminder", this.passwordReminder);
    if (this.passwordHash != null)
        userDoc.addParam("passwordHash", this.passwordHash);

    userDoc.addParam("country", this.countryCode);
    userDoc.addParam("region", this.region);
    userDoc.addParam("city", this.city);
    alert('|' + this.timeZone + '|');
    userDoc.addParam("timeZone", this.timeZone);
    postParams.addParam('doc', userDoc.getListAsDoc());
    var xml = talkPost_sync(bu.XMLHandler, postParams, null, true);
    if (xml == null) {
        return false;
    }
    return true;
}

function PMONewUser(screenName, emailAddress, password) {
    if (!ValidateEmail(emailAddress)) {
        PMError("Email address is invalid");
        return false;
    }
    if (screenName == null || screenName == undefined || screenName == "") {
        PMError("Screen name cannot be blank");
        return false;
    }
    if (password == null || password == undefined || password == "") {
        PMError("password cannot be blank");
        return false;
    }


    var postParams = buildPostParams('createUser');
    var userDoc = new postParam();

    userDoc.addParam("userName", emailAddress);
    userDoc.addParam("passwordHash", hex_md5(password));
    userDoc.addParam("authHash", getAuthHash());
    userDoc.addParam("screenName", screenName);
    postParams.addParam('doc', userDoc.getListAsDoc());

    var xml = talkPost_sync(bu.XMLHandler, postParams);

    if (XMLObj == null)
        return false;
    var status = getStatus(XMLObj);

    if (status != "user created ok") {
        PMError(status);
        return false
    }

    return true;
}

function getStatus(oXML){
    if (oXML== null){
        PMError("invalid xml. Failed to get status");
        return false
    }
    
    var oStatus = XMLObj.getElementsByTagName("status");
        
    if (oStatus == null) {
        PMError("invalid reponse from login attempt");
        return false
    }
    
    if (oStatus.length > 1) {
        PMError("invalid reponse from login attempt. Status was found more than once.");
        return false
    }

    return oStatus[0].firstChild.nodeValue;
}

function getAuthHash(){
    var nVer = navigator.appVersion;
    var nAgt = navigator.userAgent;

    var ident = nVer + "\n" + nAgt;//need to add more here;
    var res = Crc32Str(ident);
    return res
    
}

function PMOLogout(authKey, authHash) {
    var postParams = buildPostParams('logout');
    var xml = talkPost_sync(bu.XMLHandler, postParams, {ignoreReconnect: true});

    setCookie("authKey", '', true); //3rd param is Expires? so it is right to negate it.
    setCookie("authHash", '', true);
    return true;
    /*
    if (xml == null)
        false;

    if (getStatus(xml) == "logged ok")
        return true;

    return false;
    */        
}