/*

Table of Contents:
 * Globals
 * Constants
 * General
     * RESTRUCTURE
     * TIMING
     * DISPLAY
     * FOCUS
     * FRAMES
     * FORMS
     * VALUE
     * COLOR
     * PULSE
     * REFERENCES
     * REDIRECT
     * INFLATABLE
 * Keystrokes
 * AJAX
     * GENERAL
     * REQUESTS
     * SPINNERS
 * Server Requests
     * INPUT
     * OUTPUT
 * Lightboxes
 * Forms
 * Dialogs
 * Events
 * WYSIWYG
 * Main Page
 * Relationships
 * Page Editing
 * Discussion
 * Image Upload
 * Login
 * E-mail Protection
 * On Load
 * EOF

NOTE:
 * All input textfields should have unique names or Safari automatically fills 
       in forms and gets mixed up.

*/

/** Globals ***************************************************************** */

var ALT_KEY = false;
var CTRL_KEY = false;
var DEFAULT_VALUE = {};
var DOC = {};
var EVENTS = {};
var INSERTED = 0;
var LOADED = {};
var NUM_TEMP_NODES = 0;
var PAGE_EMPTY = false;
var PULSING = {};
var SHIFT_KEY = false;
var TEMP_TREES = {};

var IE6 = /MSIE\s*6/.exec(navigator.userAgent);



/** Constants *************************************************************** */

var XML_HTTP__REQUEST_NOT_INITIALIZED = 0;
var XML_HTTP__REQUEST_SET_UP = 1;
var XML_HTTP__REQUEST_SENT = 2;
var XML_HTTP__REQUEST_IN_PROCESS = 3;
var XML_HTTP__REQUEST_COMPLETE = 4;
var XML_HTTP__STATUS_OK = 200;



/** General ***************************************************************** */

/** == RESTRUCTURE == **/

function replaceWithHTML(replacee, html) {
    var temp = document.createElement('div');
    temp.innerHTML = html;
    
    replace(replacee, temp.firstChild);
}

function replace(replacee, replacer) {
    if (typeof(replacee) == "string") {
        replacee = document.getElementById(replacee);
    }
    
    if (replacee && replacee.parentNode && replacer) {
        replacee.parentNode.replaceChild(replacer, replacee);
    }
}


/** == TIMING == **/

function whenLoaded(id, onLoaded) {
    var elem = document.getElementById(id);
    
    if (!elem) {
        var tryAgain = function() {
            whenLoaded(id, onLoaded);
        }
        
        setTimeout(tryAgain, 100);
    }
    
    onLoaded();
}


/** == DISPLAY == **/

function swapDisplay(fromId, toId) {
    var from = document.getElementById(fromId);
    var to = document.getElementById(toId);
    
    from.style.display = 'none';
    to.style.display = 'block';
}

var hiddenPattern = /hidden\s*/;

function reveal(elem) {
    elem.className = elem.className.replace(hiddenPattern, "");
}

function hide(elem) {
    if (!hiddenPattern.exec(elem.className)) {
        elem.className = "hidden " + elem.className;
    }
}


/** == FOCUS == **/

function whenFocus(id, proc) {
    var field = document.getElementById(id);
    
    if (field) {
        var f = field.onfocus;
        field.onfocus = function(e) { if (f) { f(e); }  proc(e); };
        
    } else {
        setTimeout(function() { whenFocus(id, proc); }, 100);
    }
}

function moveCursorToEnd(id) {
    var elem = document.getElementById(id);
    if (!elem) {
        return;
    }
    
    var val = elem.value;
    
    try { // IE
        sel = elem.createTextRange();
        
        if (sel) {
            sel.moveStart('character', val.length);
            sel.select();
        }
        
    } catch (e) { // FF, etc.
        elem.focus();
        
        elem.value = val + " ";
        elem.value = val;
    }
}



/** == FRAMES == **/

function getFrameContent(frameId) {
    var frame = document.getElementById(frameId);

    if (frame) {
        if (frame.contentDocument) {
            return frame.contentDocument.body.innerHTML;
                    
        } else if (frame.contentWindow) {
            return frame.contentWindow.document.body.innerHTML;
                        
        } else {
            return window.frames[frameId].document.body.innerHTML;
        }
        
    } else {
        return undefined;
    }
}

function setFrameContent(frame, val) {
    if (typeof(frame) == "String") {
        frame = document.getElementById(frame);
    }
    
    if (frame) {
        if (frame.contentDocument) {
            frame.contentDocument.body.innerHTML = val;
                    
        } else if (frame.contentWindow) {
            frame.contentWindow.document.body.innerHTML = val;
                        
        } else {
            window.frames[frame.id].document.body.innerHTML = val;
        }
    }
}

function focusFrame(frame) {
    frame.focus();
    
    if (document.all) {
        DOC[frame.id].getElementsByTagName('html')[0].focus();
        DOC[frame.id].body.focus();
        
    } else if (frame.contentWindow) {
        frame.contentWindow.focus();
    }
}


/** == FORMS == **/

function formKeyDown(submitButtonId) {
    return function(e) {
        var keycode = getKeyCode(e);
           
        // CTRL + ENTER (13)
        if (CTRL_KEY && keycode == 13) {
            var submit = document.getElementById(submitButtonId);
            
            var ret = submit.click();
        }
    }
}

function handleCtrlEnter(formId, submitButtonId) {
    var form = document.getElementById(formId);
    form.onkeydown = formKeyDown(submitButtonId);
}

function defaultInit(inputId, defaultText) {
    var input = document.getElementById(inputId);
    
    DEFAULT_VALUE[inputId] = defaultText;
    
    if (input) {
        input.onfocus = function() {
            defaultOff(inputId, defaultText);
        }
        
        input.onblur = function() {
            defaultOn(inputId, defaultText);
        }
        
        defaultOn(inputId, defaultText);
    }
}

function defaultOff(inputId, defaultText) {
    var input = document.getElementById(inputId);
    
    if (!input) {
        return;
    }
    
    if (input.tagName == "SELECT") {
        if (input.selectedIndex == 0) {
            input.firstChild.innerHTML = "";
            
            if (input.className.search(/default/) != -1) {
                input.className = input.className.replace(/default/, "");
            }
        }

    } else {
        if (input.value == defaultText) {
            input.value = "";
            
            if (input.className.search(/default/) != -1) {
                input.className = input.className.replace(/default/, "");
            }
            
            if (input.className.search(/password/) != -1) {
                try {
                    input.type = "password";
                    
                } catch (e) {} // IE
            }
        }
    }
}

function defaultOn(inputId, defaultText) {
    var input = document.getElementById(inputId);
    
    if (!input) {
        return;
    }
    
    if (input.tagName == "SELECT") {
        if (input.selectedIndex == 0) {
            input.firstChild.innerHTML = defaultText;
            
            if (input.className.search(/default/) == -1) {
                input.className += " default";
            }
        }

    } else {
        if (input.value == "" || input.value == defaultText) {
            input.value = defaultText;
            
            if (input.className.search(/default/) == -1) {
                input.className += " default";
            }
            
            if (input.className.search(/password/) != -1) {
                // IE and Safari workaround for changing field types.
                if (!input.clone) {                        
                    var clone = document.getElementById(inputId + "Clone");
                    
                    if (clone) {
                        clone.onfocus = function() {
                            clone.className += " cloneHack";
                            input.style.display = "block";
                            
                            input.focus();
                        };
                        
                        input.clone = clone;
                    }
                }
                
                if (input.clone) {
                    input.style.display = "none";
                    input.clone.className = input.clone.className.replace(/cloneHack/, "");
                }
            }
        }
    }
}

function curlyKeyPress(submitId) {
    return function(e) {
        var keycode = getKeyCode(e);
        
        if (submitId && keycode == 13) { // ENTER
            return document.getElementById(submitId).click();
        }
    }
}


/** == VALUE == **/

function getValue(id, defaultValue) {
    var obj = document.getElementById(id);
    var ret = defaultValue;
    
    if (obj) {
        ret = obj.value;
    }
    
    if (id in DEFAULT_VALUE && ret == DEFAULT_VALUE[id]) {
        ret = defaultValue;
    }
    
    return ret;
}

function getSelect(id, defaultValue) {
    var obj = document.getElementById(id);
    var ret = defaultValue;
    
    if (obj) {
        ret = obj.options[obj.selectedIndex].text;
    }
    
    if (id in DEFAULT_VALUE && ret == DEFAULT_VALUE[id]) {
        ret = defaultValue;
    }
    
    return ret;
}

function getChecked(id, defaultValue) {
    var obj = document.getElementById(id);
    var ret = defaultValue;
    
    if (obj) {
        ret = obj.checked;
    }
    
    return ret;
}


/** == COLOR == **/

function parseCSSColor(color) {
    if (color.search(/rgb/) != -1) {
        return {
            red: parseInt(color.replace(/rgba?\(\s*(\d+).*/, "$1")),
            green: parseInt(color.replace(/rgba?\(\s*\d+\s*,\s*(\d+).*/, "$1")),
            blue: parseInt(color.replace(/rgba?\(\s*\d+\s*,\s*\d+\s*,\s*(\d+).*/, "$1"))
        };
        
    } else if (color.search(/^#/) != -1) {
        return {
            red: parseInt(color.substr(1, 2), 16),
            green: parseInt(color.substr(3, 2), 16),
            blue: parseInt(color.substr(5, 2), 16)
        };   
        
    } else {
        // Safari
    }
}


/** == PULSE == **/

function PulseState(element, step, color) {
    var fromCSSColor = "";
    
    var node = element;
    while (node) {
        if (window.getComputedStyle) {
            fromCSSColor = window.getComputedStyle(node, null).getPropertyValue("background-color");
            
        } else if (node.currentStyle) {
            fromCSSColor = node.currentStyle.backgroundColor;
               
        }
        
        if (fromCSSColor == "" || fromCSSColor == "transparent" || fromCSSColor == "rgba(0, 0, 0, 0)") {
            node = node.parentNode;

        } else {
            break;
        }
    }
    
    this.original = fromCSSColor;
    
    if (fromCSSColor == "" || fromCSSColor == "transparent" || fromCSSColor == "rgba(0, 0, 0, 0)") {
        fromCSSColor = "#FFFFFF";
    }
    
    
    var fromColor = parseCSSColor(fromCSSColor);
    
    var toColor = parseCSSColor(color);
    
    this.color = {
        red: {
            source: fromColor.red,
            delta: toColor.red - fromColor.red
        },
        green: {
            source: fromColor.green,
            delta: toColor.green - fromColor.green
        },
        blue: {
            source: fromColor.blue,
            delta: toColor.blue - fromColor.blue
        }
    };
    
    this.step = step;
    
    this.current = 0.0;
}

function pulser(lastTime, element, pulseState) {
    var thisTime = new Date().getTime();
    var deltaTime = (thisTime - lastTime)/1000;

    pulseState.current += pulseState.step * deltaTime;
    
    if (pulseState.current < 0.0) {
        element.style.backgroundColor = pulseState.original;
        
        PULSING[element] = false;

        return;
        
    } else if (pulseState.current >= 1.0) {
        pulseState.current = 1.0;
        
        pulseState.step = -pulseState.step;
    }
    
    r = pulseState.color.red.source + (pulseState.color.red.delta * pulseState.current);
    g = pulseState.color.green.source + (pulseState.color.green.delta * pulseState.current);
    b = pulseState.color.blue.source + (pulseState.color.blue.delta * pulseState.current);
    
    element.style.backgroundColor = 'rgb(' + parseInt(r) + ', ' + parseInt(g) + ', ' + parseInt(b) + ')';
    
    function pulseAgain() {
        pulser(thisTime, element, pulseState);
    }
    
    setTimeout(pulseAgain, 100);
}

function pulse(element, color) {
    if (!element || PULSING[element]) {
        return;
        
    } else {
        PULSING[element] = true;
    }
    
    pulser(
        new Date().getTime(),
        element, 
        new PulseState(element, 2.0, (color == undefined ? "#FFF7C0" : color))
    );
}



/** == REFERENCES == **/

function expandReference(sectionId, refNum) {
    var ref = document.getElementById('bgReference' + sectionId + '.' + refNum);
    var expand = document.getElementById('expandRefControl' + sectionId + '.' + refNum);
    var contract = document.getElementById('contractRefControl' + sectionId + '.' + refNum);
    var content = document.getElementById('refContent' + sectionId + '.' + refNum);
    
    ref.className = 'expanded bgReference';
    
    expand.style.display = 'none';
    contract.style.display = 'inline';
    content.style.display = 'block';
}

function contractReference(sectionId, refNum) {
    var ref = document.getElementById('bgReference' + sectionId + '.' + refNum);
    var expand = document.getElementById('expandRefControl' + sectionId + '.' + refNum);
    var contract = document.getElementById('contractRefControl' + sectionId + '.' + refNum);
    var content = document.getElementById('refContent' + sectionId + '.' + refNum);
    
    ref.className = 'contracted bgReference';
    
    expand.style.display = '';
    contract.style.display = 'none';
    content.style.display = 'none';
}


/** == REDIRECT == **/

function redirect(pageURL) {
    if (CTRL_KEY) {
        window.open(pageURL, '_blank');        
        
    } else {
        window.location = pageURL;
    }
}


/** == INFLATABLE == **/

function inflate() {
    var inflatable = document.getElementById('inflatable');
    
    if (inflatable) {
        inflatable.className = 'inflated';
    }
}

function deflate() {
    var inflatable = document.getElementById('inflatable');
    
    if (inflatable) {
        inflatable.className = 'deflated';
    }
}



/** Keystrokes ************************************************************** */

function getKeyCode(e) {
    if (window.event) {
        return window.event.keyCode;
            
    } else if (e.which) {
        return e.which;
    }
}

function keyDown(e) {
    switch (getKeyCode(e)) {
        case 16: SHIFT_KEY = true; break;
        case 17: CTRL_KEY = true; break;
        case 18: ALT_KEY = true; break;
    }
}

function keyBlur(e) {
    SHIFT_KEY = false;
    CTRL_KEY = false;
    ALT_KEY = false;
}

function keyUp(e) {
    switch (getKeyCode(e)) {
        case 16: SHIFT_KEY = false; break;
        case 17: CTRL_KEY = false; break;
        case 18: ALT_KEY = false; break;
    }
}



/** AJAX ******************************************************************** */

/** == GENERAL == **/

function stripResponse(str) {
    var stripRE = /^\s*(.*?)\s*$/;
    return str.replace(stripRE, "$1");
};

function buildQueryString(params) {
    var queryString = "";

    for (var key in params) {
        var value = params[key];
        
        if (queryString != "") {
            queryString += '&';
        }
        
        queryString += encodeURIComponent(''+key) + '=' + escape(encodeURIComponent(''+value));
    }
    
    return queryString;
};


/** == REQUESTS == **/

function getXmlHttp() {
    try { return new XMLHttpRequest(); }
    catch (e) {
        try { return new ActiveXObject("Msxml2.XMLHTTP"); }
        catch (e) {
            try { return new ActiveXObject("Microsoft.XMLHTTP"); }
            catch (e) { return null; }
        }
    }
};

function sendRequest(method, action, params, fn, failFn) {
    var xmlHttp = getXmlHttp();
    
    if (xmlHttp == null) {
        alert('Your browser does not seem to support the xmlHttpRequest object.');
        return;
    }
    
    xmlHttp.onreadystatechange = function() {
        switch (xmlHttp.readyState) {
            case XML_HTTP__REQUEST_COMPLETE:
                var response = stripResponse(xmlHttp.responseText);
                
                try {
                    if (xmlHttp.status == XML_HTTP__STATUS_OK) {
                        if (fn != undefined && typeof(fn) == "function") {
                            fn(response);
                        }
                        
                    } else {
                        if (failFn != undefined && typeof(failFn) == "function") {
                            failFn(xmlHttp.status, response);
                        }
                    }
                } catch (e) {
                    failFn("NS_ERROR_NOT_AVAILABLE", response);
                }
                
                break;
            
            default:    
                break;
        }
    };
    
    var qs = buildQueryString(params);
    
    try { 
        if (method == "POST") {
            xmlHttp.open("POST", action, true);
            xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
            xmlHttp.send(qs);

        } else {
            xmlHttp.open("GET", action + '?' + qs, true);
            xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
            xmlHttp.send(null);
        }

    } catch (e) {
        alert('Could not connect!');
    }
};

// Browsers sometimes cache GET requests
function getRequest(action, params, fn, failFn) {
    sendRequest("GET", action, params, fn, failFn);
};

function postRequest(action, params, fn, failFn) {
    sendRequest("POST", action, params, fn, failFn);
};


/** == SPINNERS == **/

function ajaxWaiting(element, img) {
    img = (img == undefined ? "/layout/spinner.gif" : img);

    var ajaxWaiting = document.createElement('img');
    
    ajaxWaiting.src = img;
    
    replace(element, ajaxWaiting);
    
    function revert() {
        replace(ajaxWaiting, element);
    }
        
    return revert;
}

function spinButton(buttonId) {
    var button = document.getElementById(buttonId);
    
    if (button == undefined) {
        return;
    }
    
    var width = button.offsetWidth;
    var height = button.offsetHeight;
    
    var oldWidth = button.style.width;
    var oldHeight = button.style.height;
    var oldContent = button.innerHTML; 
    
    button.innerHTML = '<img src="/images/tinyspin.gif" />';
    button.style.width = width + "px";
    button.style.height = height + "px";
   
    var oldDisabled = button.disabled;
    button.disabled = true;
    
    button.blur();
    
    function revert() {
        if (button) {
            button.disabled = oldDisabled;
            button.innerHTML = oldContent;
            button.height = oldHeight;
            button.width = oldWidth;
        }
    }
    
    return revert;
}



/** Server Requests ********************************************************* */

/** == INPUT == **/

function requestLoadDialog(name, onSuccess, onFail) {
    postRequest('/dialog-' + name, null, onSuccess, onFail);
}

function requestUpdateLogin(onSuccess, onFail) {
    postRequest('/update-login', null, onSuccess, onFail);
}

function requestLoginInfo(onSuccess, onFail) {
    postRequest('/login-info', null, onSuccess, onFail);
}

function requestGetReplyForm(parent, comment, onSuccess, onFail) {
    var params = {
        'parent': parent,
        'content': comment
    };
    
    postRequest('/get-reply-form', params, onSuccess, onFail);
}

function requestSearchAddAConnection(query, offset, numResults, onSuccess, onFail) {
    var params = {
        'q': query,
        'o': offset,
        'n': numResults
    };
    
    postRequest('/search-add-a-connection', params, onSuccess, onFail);
}

function requestDisambiguationInline(connectionName, onSuccess, onFail) {
    var params = {
        'name': connectionName
    };
    
    postRequest('/disambiguation-inline', params, onSuccess, onFail);
}

function requestUpdateConnections(page, onSuccess, onFail) {
    var params = {
        'page': page
    };
    
    postRequest('/update-connections', params, onSuccess, onFail);
}

function requestMoreRelationships(page, offset, num, onSuccess, onFail) {
    var params = {
        'page': page,
        'offset': offset,
        'num': num
    };
    
    postRequest('/relationships-chunk', params, onSuccess, onFail);
}

function requestGetEditHeader(page, onSuccess, onFail) {
    var params = {
        'page': page
    };
    
    postRequest('/get-edit-header', params, onSuccess, onFail);
}

function requestGetHeader(page, onSuccess, onFail) {
    var params = {
        'page': page
    };
    
    postRequest('/get-header', params, onSuccess, onFail);
}

function requestNextQuestion(page, onSuccess, onFail) {
    var params = {
        'page': page
    };
    
    postRequest('/dialog-question', params, onSuccess, onFail);
}


/** == OUTPUT == **/

function requestNewBio(name, tagline, image, onSuccess, onFail) {
    var params = {
        'name': name
    };
    
    if (tagline) {
        params['tagline'] = tagline;
    }
    
    if (image) {
        params['image'] = image;
    }
    
    postRequest('/new-bio', params, onSuccess, onFail);
}

function requestPostFeedback(page, feedback, email, onSuccess, onFail) {
    var params = {
        'page': page,
        'email': email,
        'feedback': feedback
    };
    
    postRequest('/feedback', params, onSuccess, onFail);
}

function requestRevert(page, rev, onSuccess, onFail) {
    var params = {
        'page': page,
        'rev': rev
    };
    
    postRequest('/revert', params, onSuccess, onFail);
}

function requestUpdateHeader(page, image, name, tagline, email, invite, onSuccess, onFail) {
    var params = {
        "page": page,
        "image": image,
        "name": name,
        "tagline": tagline,
        "email": email,
        "invite": (invite ? "yes" : "no")
    };

    postRequest('/update-header', params, onSuccess, onFail);
}

function requestSaveRelation(page, relation, img, name, tagline, description, onSuccess, onFail) {
    var params = {
        'page': page,
        'relation': relation,
        'img': img,
        'name': name,
        'tagline': tagline,
        'description': description
    };
    
    postRequest('/save-relation', params, onSuccess, onFail);
}

function requestSaveSection(page, section, title, level, content, onSuccess, onFail) {
    var params = {
        'page': page,
        'section': section,
        'title': title,
        'level': level,
        'content': content
    };
    
    postRequest('/save-section', params, onSuccess, onFail);
}

function requestInsertSection(page, section, side, title, level, content, onSuccess, onFail) {
    var params = {
        'page': page, 
        'section': section,
        'side': side,
        'title': title,
        'level': level,
        'content': content
    };

    postRequest('/insert-section', params, onSuccess, onFail);
}

function requestNewThread(page, title, content, onSuccess, onFail) {
    var params = {
        'page': page,
        'title': title,
        'content': content
    };
    
    postRequest('/new-thread', params, onSuccess, onFail);
}

function requestSaveDiscussionDescription(page, title, description, onSuccess, onFail) {
    var params = {
        'page': page,
        'title': title,
        'description': description
    };
    
    postRequest('/save-discussion-description', params, onSuccess, onFail);
}

function requestPostComment(page, reply, content, onSuccess, onFail) {
    var params = {
        'page': page,
        'reply': reply,
        'content': content
    };
    
    postRequest('/post-comment', params, onSuccess, onFail);
}

function requestLogin(user, pass, onSuccess, onFail) {
    var params = {
        'user': user,
        'pass': pass
    };
    
    postRequest('/login', params, onSuccess, onFail);
}

function requestLinkedInLogin(user, pass, onSuccess, onFail) {
    var params = {
        'user': user,
        'pass': pass
    };
    
    postRequest('/linked-in-login', params, onSuccess, onFail);
}

function requestLinkedInCaptcha(answer, secret, id, onSuccess, onFail) {
    var params = {
        'answer': answer,
        'secret': secret,
        'id': id
    };
    
    postRequest('/linked-in-captcha', params, onSuccess, onFail);
}

function requestRegister(user, pass, email, onSuccess, onFail) {
    var params = {
        'user': user,
        'pass': pass,
        'email': email
    };
    
    postRequest('/register', params, onSuccess, onFail);
}

function requestLogoff(onSuccess, onFail) {
    postRequest('/logoff', null, onSuccess, onFail);
}

function requestAddConnection(page1, page2, onSuccess, onFail) {
    var params = {
        'page1': page1,
        'page2': page2
    };
    
    postRequest('/add-connection', params, onSuccess, onFail);
}

function requestRemoveConnection(page1, page2, onSuccess, onFail) {
    var params = {
        'page1': page1,
        'page2': page2
    };
    
    postRequest('/remove-connection', params, onSuccess, onFail);
}

function requestSaveSettings(image, 
        email, mineChanged, mineConnChanged, createdChanged, createdConnChanged, 
        website, 
        oldPassword, newPassword,
        gender, 
        birthMonth, birthDay, birthYear, 
        address, city, state, zip, 
        onSuccess, onFail) {

    var params = {
        'image': image,
        'email': email,
        'mc': mineChanged,
        'mcc': mineConnChanged,
        'cc': createdChanged,
        'ccc': createdConnChanged,
        'website': website,
        'oldpass': oldPassword,
        'newpass': newPassword,
        'gender': gender,
        'month': birthMonth,
        'day': birthDay,
        'year': birthYear,
        'address': address,
        'city': city,
        'state': state,
        'zip': zip
    };
    
    postRequest('/save-settings', params, onSuccess, onFail);
} 

function requestSaveQuestion(page, questionId, response, onSuccess, onFail) {
    var params = {
        'page': page,
        'id': questionId,
        'response': response
    };
    
    postRequest('/question-response', params, onSuccess, onFail);
}

function requestSkipQuestion(page, questionId, onSuccess, onFail) {
    var params = {
        'page': page,
        'id': questionId
    };
    
    postRequest('/question-skip', params, onSuccess, onFail);
}

function requestCloseQuestion(page, questionId, onSuccess, onFail) {
    var params = {
        'page': page,
        'id': questionId
    };

    postRequest('/question-close', params, onSuccess, onFail);
}



/** Lightboxes ************************************************************** */

function spinBox() {
    var darkBox = document.createElement('div');
    document.body.appendChild(darkBox);
    darkBox.className = "spinBox darkBox";
    
    var lightBox = document.createElement('div');
    document.body.appendChild(lightBox);
    lightBox.className = "spinBox lightBox";
    
    var lightBoxContent = document.createElement('div');
    lightBox.appendChild(lightBoxContent);
    lightBoxContent.className = "lightBoxContent";
    lightBoxContent.style.width = '50px';
    lightBoxContent.style.height = '50px';
    
    var spinner = document.createElement('img');
    lightBoxContent.appendChild(spinner);
    spinner.src = '/layout/spinner.gif';    
    
    centerElement(lightBox);
    
    function revert() {
        if (darkBox) {
            darkBox.parentNode.removeChild(darkBox);
        }
        
        if (lightBox) {
            lightBox.parentNode.removeChild(lightBox);
        }
    }
    
    darkBox.onclick = revert
    lightBox.onclick = revert
    
    return revert;
}

function createLightBox(title, formName, procs, query) {    
    var darkBox = document.createElement('div');
    document.body.appendChild(darkBox);
    darkBox.id = formName + "DarkBox";
    darkBox.className = "darkBox";
    darkBox.style.visibility = "hidden";
    
    darkBox.onclick = function () { 
        closeLightBox(formName);
    };
    
    var lightBox = document.createElement('div');
    document.body.appendChild(lightBox);
    lightBox.id = formName + "LightBox";
    lightBox.className = "lightBox";
    lightBox.style.visibility = "hidden";
    
    var agent = navigator.userAgent.toLowerCase();
    
    // IE 6 and under do not support PNG.
    var isPNG = true;
    if (agent.indexOf('msie') != -1) {
        var major = parseInt(navigator.appVersion);
        var minor = parseFloat(navigator.appVersion);
        
        isPNG = !(major < 4 ||
            (major == 4 && (agent.indexOf('msie 4') != -1 ||
                agent.indexOf('msie 5') != -1 ||
                agent.indexOf('msie 6') != -1)));
    }

    if (!isPNG) {
        var browserHeight = document.body.offsetHeight;
        darkBox.style.height = browserHeight + "px";   
    }


    // Get IE6 playing along...
    var browserHeight = document.body.offsetHeight;
    darkBox.style.height = browserHeight + "px";
    
    
    var header = document.createElement('div');
    lightBox.appendChild(header);
    header.className = "lightBoxHeader";
    
    var lightBoxContent = document.createElement('div');
    lightBox.appendChild(lightBoxContent);
    lightBoxContent.className = "lightBoxContent";
    lightBoxContent.id = 'lightBoxContent';
    var titleText = document.createElement('div');
    header.appendChild(titleText);
    titleText.className = "lightBoxTitle";
    titleText.innerHTML = title;
    
    if (document.all) { // IE
        lightBox.style.width = "600px";
    }
    
    function closeOnEscape(evt) {
        var keynum = getKeyCode(evt);
                
        if (keynum == 27) {
            //closeLightBox(formName);
            setTimeout( // FF bug
                function() { darkBox.onclick(); }, 1);
        }
        
        return true;
    }
    
    lightBox.onkeydown = closeOnEscape; // FF, etc.
    lightBox.onkeypress = closeOnEscape; // IE
    
    function loadContent(content) {        
        var dynamicContentDiv = document.createElement('div');
        dynamicContentDiv.className = 'dynamicContent';

        dynamicContentDiv.innerHTML = content;

        lightBoxContent.appendChild(dynamicContentDiv);

        centerElement(lightBox);
        
        darkBox.style.visibility = "visible";
        lightBox.style.visibility = "visible";

        for (i in procs) {
            var elem = document.getElementById(i);
            
            if (elem) {
                procs[i](elem);
            }
        }
    };
    
    var onLoad = function(response) {
        loadContent(response);
    };
    
    var onFail = function(response) {
        loadContent("Sorry, an error occurred. Please try again later.<br><br>" +
            "(<a href='#' onclick='closeLightBox(unescape(\"" + escape(formName) + "\"));'>Close</a>)");
    };
    
    requestLoadDialog(formName + (query ? "?" + query : ""), onLoad, onFail);
}

function centerElement(element) {
    var height, width;
    if (window.getComputedStyle) {
        width = window.getComputedStyle(element, null).getPropertyValue("width");
        height = window.getComputedStyle(element, null).getPropertyValue("height");
        
    } else if (element.currentStyle) {
        width = element.currentStyle.width;
        height = element.currentStyle.height;
        
    }
    
    if (width == "auto") { // IE   
        width = element.offsetWidth + 'px';
    }
    
    if (height == "auto") { // IE
        height = element.offsetHeight + 'px';
    }
    
    wd = parseInt(width.replace(/(\d*)px/, "$1"));
    ht = parseInt(height.replace(/(\d*)px/, "$1"));
        
    element.style.marginLeft = -parseInt(wd/2) + 'px';
    element.style.marginTop = -parseInt(ht/2) + 'px';
}

function closeLightBox(boxId) {
    var lightBox = document.getElementById(boxId + "LightBox");
    var darkBox = document.getElementById(boxId + "DarkBox");
    
    if (lightBox) {
        lightBox.parentNode.removeChild(lightBox);
    }
    
    if (darkBox) {
        darkBox.parentNode.removeChild(darkBox);
    }
}



/** Dialogs ***************************************************************** */

function loginForm() {
    var proc = {
        'loginUser': function(loginUser) {
            loginUser.focus();
        }
    };

    createLightBox('Login', 'login', proc);
}

function registerForm() {
    var proc = {
        'regUser': function(regUser) {
            regUser.focus();
        }
    };
    
    createLightBox('Register', 'register', proc);
}

function feedbackForm() {
    var proc = {
        'feedbackEmail': function(input) {
            input.focus();
        }
    };
    
    createLightBox('Feedback', 'feedback', proc);
}

function feedbackThanksForm() {
    var proc = {
        'feedbackThanksOkButton': function(button) {
            button.focus();
        }
    }
    
    createLightBox('Thanks', 'thanks-for-feedback', proc);
}

function pictureForm(imageFilename, whenDone) {
    var proc = {
        'pic': function(pic) {
            pic.src = imageURL(imageFilename);
        },
        'done': function(done) {
            done.focus();
        },
        'pictureForm': function(pictureForm) {
            pictureForm.onsubmit = function() {
                try {
                    var frame = document.getElementById('frame');
                
                    if (whenDone && frame) {
                        var content = stripResponse(getFrameContent('frame'));
                        
                        if (content != "" && content != "INVALID") {
                            whenDone(content);
                        }
                    }
                    
                    closeLightBox('choose-photograph');
                    
                } finally {
                    return false;
                }
            };
        }
    };

    createLightBox('Choose Photo', 'choose-photograph', proc)
}

function friendConnect() {
   newConnectionForm();
}

function friendDisconnect() {
    var proc = {
        'removeConnectionsCancel': function(button) {
            button.focus();
        }
    };
    
    createLightBox('Remove a Connection', 
                   'remove-connections', 
                   proc, 
                   'page=' + PAGE_ID);
}

function cannotFind() {
    var proc = {
        'cannotFindFullNameInput': function(input) {
            input.focus();
        }
    }
    
    createLightBox('New Biography', 'create-a-new-biography', proc);
}

function newConnectionForm() {
    var proc = {
        'cannotFindFullNameInput': function(input) {
            input.focus();
        }
    }
    
    createLightBox('New Connection', 'create-a-new-connection', proc);
}

function disambiguation(connectionName) {    
    closeLightBox('create-a-new-connection');
    
    function onFail(response) {
        newConnection(connectionName);
    }
    
    function onSuccess(response) {
        if (response == "NO") {
            newConnection(connectionName);
            
        } else {
            var proc = {
                'peopleSearchFullResults': function(div) {
                    div.innerHTML = response;
                },
                'brandNewConnection': function(button) {
                    button.onclick = function() {
                        newConnection(connectionName);
                        closeLightBox('disambiguation');
                    };
                    
                    button.focus();
                }
            };
    
            createLightBox('Are You Looking For...?', 'disambiguation', proc);
        }
    }
    
    requestDisambiguationInline(connectionName, onSuccess, onFail);
}

function newConnection(connectionName) {
    function onFail(response) {
        var connectErr = document.getElementById('connectErr');
        
        if (connectErr) {
            connectErr.innerHTML = "Sorry. The change could not be made.";
            
            pulse(connectErr);
        }
    };

    function connect(response) {
        if (response == "BAD CALL") {
            onFail(response);
            
        } else {
            addConnection(response);
        }
    };
    
    requestNewBio(connectionName, undefined, undefined, connect, onFail);
}

function submitNewBio(name, tagline, image) {
    if (name == "") {
        var newBioErr = document.getElementById('newBioErr');
        
        if (newBioErr) {
            newBioErr.innerHTML = "Please enter a name.";
        
            pulse(newBioErr);
            
        } else {
            alert("Please enter a name.");
        }
        
        return;
    }
    
    var params = {
        'name': name
    };
    
    if (tagline != undefined) params['tagline'] = tagline;
    if (image != undefined) params['image'] = image;
    
    window.location = "/disambiguation?" + buildQueryString(params);
}

function newBiography(name, tagline, image) {
    function onFail(response) {
        var newBioErr = document.getElementById('newBioErr');
        
        if (newBioErr) {
            newBioErr.innerHTML = "Sorry, there was an error creating a new biography.";

        } else {
            alert("Sorry, there was an error creating a new biorgaphy.");
        }
    };
    
    function onSuccess(response) {
        window.location = "/view/" + response;
    };

    requestNewBio(name, tagline, image, onSuccess, onFail);
}

function sendFeedback() {
    var cancel = document.getElementById('cancelFeedbackButton');
    cancel.disabled = true;

    var backSpin = spinButton('submitFeedbackButton');
    
    var email = getValue('feedbackEmail', "");
    var feedbackArea = getValue('feedbackArea', "");
    
    if (feedbackArea == "") {
        closeLightBox('feedback');
        backSpin();
        return;
    }
    
    function fail(status, response) {
        cancel.disabled = false;
        backSpin();
        
        var feedbackErr = document.getElementById('feedbackErr');
        feedbackErr.innerHTML = "Sorry, there was an error delivering your feedback.";
        pulse(feedbackErr);
    };
    
    function feedbackSent(response) {
        closeLightBox('feedback');
        
        feedbackThanksForm();
        
        backSpin();
    };
    
    requestPostFeedback(PAGE_ID, feedbackArea, email, feedbackSent, fail); 
}

function questionForm() {
    var proc = {
        'questionResponse': function(textarea) {
            moveCursorToEnd(textarea.id);
        },
        'questionDarkBox': function(darkbox) {
            darkbox.onclick = function() {
                closeQuestion();
            };
        },
        'completeQuestionButton': function(button) {
            button.focus();
        }
    };
    
    var qs = buildQueryString({
        'page': PAGE_ID
    });
    
    inflate();
    
    createLightBox("", "question", proc, qs);
}

function nextQuestion() {
    var saveBackSpin = spinButton('saveQuestionButton');
    var nextBackSpin = spinButton('nextQuestionButton');
    
    function onSuccess(response) {
        replaceWithHTML('questionDialog', response);
        
        var onLoaded = function() {
            moveCursorToEnd('questionResponse');
        };
        
        whenLoaded('questionResponse', onLoaded);
    }
    
    function onFail(response) {
        saveBackSpin();
        nextBackSpin();
        
        var err = document.getElementById('questionErr');
        if (err) {
            err.innerHTML = "Sorry. There was a problem. Please try again later.";
            
            reveal(err);
            pulse(err);
        }
    }
    
    requestNextQuestion(PAGE_ID, onSuccess, onFail);
}

function saveQuestion() {
    var questionId = getValue('questionId', "");
    var response = getValue('questionResponse', "");
    var template = getValue('questionTemplate', "");

    if (response == "" || response == template) {
        return skipQuestion();
    }

    var saveBackSpin = spinButton('saveQuestionButton');
    var nextBackSpin = spinButton('nextQuestionButton');
    
    function onSuccess(response) {
        var s = response.split(" ");

        var id = s.shift();
        var newSection = s.join(" ");
        
        if (id == "NEW") {
            var temp = document.createElement('div');
            temp.innerHTML = newSection;
            
            id = temp.firstChild.id;
            
            var content = document.getElementById('biography');
            if (content) {
                content.insertBefore(temp.firstChild, 
                    content.lastChild.nextSibling);
                    
                if (!IE6) {
                    window.location.hash = id;
                }
            }

        } else {
            var id = parseInt(id)
            
            section = document.getElementById('pageSection' + id);
            replaceWithHTML(section, newSection);
            
            if (!IE6) {
                window.location.hash = 'pageSection' + id;
            }
        }
        
        nextQuestion();
    }
    
    function onFail(response) {
        saveBackSpin();
        nextBackSpin();
        
        var err = document.getElementById('questionErr');
        if (err) {
            err.innerHTML = "Sorry. There was a problem saving your " +
                "response. Please try again later.";
            
            reveal(err);
            pulse(err);
        }
    }
    
    requestSaveQuestion(PAGE_ID, questionId, response, onSuccess, onFail);
}

function skipQuestion() {
    var questionId = getValue('questionId');

    var saveBackSpin = spinButton('saveQuestionButton');
    var nextBackSpin = spinButton('nextQuestionButton');
    
    function onSuccess(response) {
        replaceWithHTML('questionDialog', response);
        moveCursorToEnd('questionResponse');
    }
    
    function onFail(response) {
        nextQuestion();
    }
    
    requestSkipQuestion(PAGE_ID, questionId, onSuccess, onFail);
}

function closeQuestion() {
    function onSuccess() {
        if (document.getElementById('pageSectionT0')) {
            window.location.hash = 'pageSectionT0';
            focusFrame(document.getElementById('editSectionFrameT0'));
            
        } else {
            window.location.hash = "#top";
        }
        
        deflate();
        
        closeLightBox("question");
    }
    
    var onFail = onSuccess;

    var questionId = getValue('questionId', ""); 
    if (questionId != "") {
        requestCloseQuestion(PAGE_ID, questionId, onSuccess, onFail);
        
    } else {
        onSuccess();
    }
}

function completeQuestion() {
    var answerQuestions = document.getElementById('answerQuestions');
    if (answerQuestions) {
        hide(answerQuestions);
    }
    
    closeQuestion();
}



/** Forms ******************************************************************* */

function editForm() { 
    for (var i = 0; i < arguments.length; i++) {
        var plain = document.getElementById('plain.' + decodeURIComponent(arguments[i]));
        if (plain) { 
            hide(plain); 
        }
            
        var edit = document.getElementById('edit.' + decodeURIComponent(arguments[i]));
        if (edit) { 
            reveal(edit); 
        }
    }
}

function revertForm() { 
    for (var i = 0; i < arguments.length; i++) {
        var plain = document.getElementById('plain.' + decodeURIComponent(arguments[i]));
        if (plain) {
            reveal(plain); 
        }
        
        var edit = document.getElementById('edit.' + decodeURIComponent(arguments[i]));
        if (edit) { 
            hide(edit); 
        }
    }
}



/** Events ****************************************************************** */

function addListener(eventName, proc) {
    if (EVENTS[eventName] == undefined) {
        EVENTS[eventName] = [];
    }
    
    EVENTS[eventName].push(proc);
}

function triggerEvent(eventName, info) {
    for (i in EVENTS[eventName]) {
        var proc = EVENTS[eventName][i];

        if (proc != undefined && typeof(proc) == "function") {
            proc(info);
        }
    }
}



/** Settings Page *********************************************************** */

function saveSettings() {
    var backSpin = spinButton('saveButton');

    var image = getValue('pictureFrame', "");
    
    var email = getValue('emailInput', "");
    var mineChanged = getChecked('mineChanged', false);
    var mineConnChanged = getChecked('mineConnChanged', false);
    var createdChanged = getChecked('createdChanged', false);
    var createdConnChanged = getChecked('createdConnChanged', false);
    
    var website = getValue('websiteInput', "");
    
    var oldPassword = getValue('oldPassword', "");
    var newPassword = getValue('newPassword', "");
    var confirmNewPassword = getValue('confirmNewPassword', "");
    
    if (newPassword != confirmNewPassword) {
        backSpin();
        
        var settingsMessages = document.getElementById('settingsMessages');
        settingsMessages.style.display = "block";
        
        var err = document.getElementById('settingsErr');
        err.innerHTML = "New passwords do not match.";
        
        var msg = document.getElementById('settingsMsg');
        msg.innerHTML = "";
        
        pulse(err);
        
        return;
    }
    
    if (newPassword == "" && oldPassword != "") {
        backSpin();
        
        var settingsMessages = document.getElementById('settingsMessages');
        settingsMessages.style.display = "block";
        
        var err = document.getElementById('settingsErr');
        err.innerHTML = "New password cannot be blank.";
        
        var msg = document.getElementById('settingsMsg');
        msg.innerHTML = "";
        
        pulse(err);
        
        return;
    }

    var gender = getSelect('genderSelect', "");
    var birthMonth = getSelect('monthSelect', "");
    var birthDay = getSelect('daySelect', "");
    var birthYear = getValue('yearInput', "");
    
    var address = getValue('addressInput', "");
    var city = getValue('cityInput', "");
    var state = getValue('stateInput', "");
    var zip = getValue('zipInput', "");
    
    function onFail(response) {
        var err = document.getElementById('settingsErr');
        var msg = document.getElementById('settingsMsg');
        
        err.innerHTML = "Sorry, there was an error saving your settings.";
        msg.innerHTML = "";
        
        pulse(err);
    };
    
    function onSuccess(response) {
        backSpin();
        
        var settingsMessages = document.getElementById('settingsMessages');
        settingsMessages.style.display = "block";
        
        var err = document.getElementById('settingsErr');
        var msg = document.getElementById('settingsMsg');
        
        if (response == "BAD PASSWORD") {
            err.innerHTML = "Sorry, current password is wrong.";
            msg.innerHTML = "";
            
            pulse(err);

        } else if (response == "OK") {
            err.innerHTML = "";
            msg.innerHTML = "Your changes have been saved.";
            
            pulse(msg);
            
        } else {
            onFail(response);
        }
    };
    
    requestSaveSettings(image, 
        email, mineChanged, mineConnChanged, createdChanged, createdConnChanged, 
        website, 
        oldPassword, newPassword,
        gender, 
        birthMonth, birthDay, birthYear, 
        address, city, state, zip, 
        onSuccess, onFail);
}



/** WYSIWYG ***************************************************************** */

function registerEditDocument(frameId, doc) {
    DOC[frameId] = doc;

    function handleResize() {
        var replyFrame = document.getElementById(frameId);
        
        if (replyFrame == undefined) {
            return;
        }

        if (document.all) {
            var docHeight = DOC[frameId].body.scrollHeight;

        } else {
            var docHeight = DOC[frameId].body.offsetHeight;
        }

        var newHeight = docHeight + 'px';
        if (replyFrame.style.height != newHeight) {
            replyFrame.style.height = newHeight;   
            
        } else {
            LOADED[frameId] = true;
        }
        
        setTimeout(handleResize, 100);
    }
        
    setTimeout(handleResize, 100);
}



/** Main Page *************************************************************** */

function newBioMain() {
    var backSpin = spinButton('createBio.new-bio-main');

    var name = getValue('name.new-bio-main', "");
    if (name == "") {
        var err = document.getElementById('createErr.new-bio-main');
        
        if (err) {
            err.innerHTML = "Please enter a name.";
            
            reveal(err);
            pulse(err);
            
        } else {
            alert('Please enter a name.');
        }
        
        backSpin();
        
        return;
    }
    
    var image = getValue('frame.new-bio-main', undefined);
    
    var params = {
        'name': name
    };
    
    if (image != "anonymous.gif" && image != undefined) params['image'] = image;
    
    window.location = "/disambiguation?" + buildQueryString(params);
}



/** Relationships *********************************************************** */

function editRelationship(id) {
    var editRelationship = document.getElementById('editRelationship.' + id);
    var relationship = document.getElementById('relationship.' + id);
    var tagline = document.getElementById('relationshipTagline.' + id);
    var content = document.getElementById('relationshipDescription.' + id);
    var curly = document.getElementById('curly.' + id);
    var clicky = document.getElementById('relationshipClicky.' + id);
    var image = document.getElementById('image.' + id);
    var imageFilename = document.getElementById('imageFilename.' + id);
    var name = document.getElementById('name.' + id);
    
    relationship.className = relationship.className + " editMode";
    
    var newContent = content.cloneNode(false);
    content.parentNode.insertBefore(newContent, content);
    newContent.style.display = "none";
    
    var editName = document.createElement('input');
    editName.id = "editName." + id;
    editName.className = "textfield name";
    editName.value = name.innerHTML;
    
    var editTagline = document.createElement('input');
    editTagline.id = "editTagline." + id;
    editTagline.className = "textfield tagline";
    editTagline.value = tagline.innerHTML; 
    
    var addPhoto = document.createElement('button');
    addPhoto.id = "addPhoto." + id;
    addPhoto.className = "choosePhoto";
    addPhoto.innerHTML = "Add Photo...";
    addPhoto.onclick = function() {
        function whenDone(response) {
            imageFilename.value = response;
            image.src = imageURL(response);
        }

        pictureForm(imageFilename.value, whenDone);
    }
    
    /*var editLabel = document.createElement('label');
    newContent.appendChild(editLabel);
    editLabel.innerHTML = "How X knows " + name.innerHTML + ":";*/
    
    var editFrame = document.createElement('iframe');
    editFrame.frameBorder = "no";
    editFrame.scrolling = "no";
    editFrame.id = "editFrame." + content.id;
    editFrame.className = "replyFrame";
    editFrame.src = "/include-relation" +
        "?frame=" + encodeURIComponent(editFrame.id) + 
        "&page=" + encodeURIComponent(PAGE_ID) + 
        "&relation=" + id;
    newContent.appendChild(editFrame);
    
    var err = document.createElement('div');
    newContent.appendChild(err);
    err.className = "hidden errorMessage";
    
    var buttons = document.createElement('div');
    newContent.appendChild(buttons);
    buttons.className = "buttons";
    
    var clearHack = document.createElement('div');
    newContent.appendChild(clearHack);
    clearHack.className = "clearHack";
    
    function onCancel() {
        replace(newContent, content);
        replace(editTagline, tagline);
        replace(editName, name);
        editRelationship.style.display = "";
        
        relationship.removeChild(addPhoto);
        curly.removeChild(subLinks);
        
        relationship.className = relationship.className.replace(/\s*editMode/g, "");
        
        delete LOADED[editFrame.id];
    };
    
    function onSave() {
        var img = getValue(imageFilename.id, "");
        var name = getValue(editName.id, "");
        var tag = getValue(editTagline.id, ""); 
        var description = stripResponse(getFrameContent(editFrame.id));

        function onFail(response) {
            err.innerHTML = "Sorry, there was an error saving your changes.";
            
            reveal(err);
            
            pulse(err);
        };
        
        function onSuccess(response) {
            if (response == "NOP") {
                return onCancel();
            }

            replaceWithHTML(relationship, response);
            delete LOADED[editFrame.id];
            updateConnections();
        };
        
        requestSaveRelation(PAGE_ID, decodeURIComponent(id), img, name, tag, 
            description, onSuccess, onFail);
    };
    
    var saveButton = document.createElement('button');
    buttons.appendChild(saveButton);
    saveButton.onclick = onSave;
    saveButton.innerHTML = "Done";
    
    var subLinks = document.createElement('div');
    subLinks.className = "subLinks";
    subLinks.appendChild(document.createTextNode("["));
    
    var deleteLink = document.createElement('a');
    subLinks.appendChild(deleteLink);
    deleteLink.innerHTML = "delete";
    deleteLink.className = "delete";
    deleteLink.href = "#";
    deleteLink.onclick = function() {
        removeConnection(id);
        return false;
    }
    
    subLinks.appendChild(document.createTextNode("] ["));
    
    var cancelLink = document.createElement('a');
    subLinks.appendChild(cancelLink);
    cancelLink.innerHTML = "cancel";
    cancelLink.className = "cancel";
    cancelLink.href = "#";
    cancelLink.onclick = function() {
        onCancel();
        return false;
    }
    
    subLinks.appendChild(document.createTextNode("]"));
    
    function checkLoaded() {
        var frame = LOADED[editFrame.id];
        
        if (frame == undefined) {
            return setTimeout(checkLoaded, 100);
        }
    
        var scrollPos = document.body.scrollTop;

        content.parentNode.removeChild(content);
        
        newContent.style.display = "";
        if (!document.all) { // IE6 bug
            DOC[editFrame.id].designMode = 'on'; // FF2 bug
        } 
        
        if (document.all) {
            // IE has bizarre behavior where sometimes the iframe will render
            //    and sometimes it won't, depending on the contents. 
            //    Changing the height forces a render.
            try {
                var twiddle = editFrame.style.height;
                twiddle = parseInt(twiddle.replace(/px/, ""));
                editFrame.style.height = (twiddle + 1) + "px";
            } catch (e) {}
        }
        
        replace(name, editName);
        replace(tagline, editTagline);
        curly.appendChild(subLinks);
        relationship.appendChild(addPhoto);
        
        document.body.scrollTop = scrollPos;
        
        focusFrame(editFrame);
    };
    
    checkLoaded();
}
 
                    
/** Page Editing ************************************************************ */

function revertTo(revisionId) {
    function onFail(response) {
        var revisionErr = document.getElementById('revisionErr');
        
        revisionErr.innerHTML = "Sorry, there was a problem while reverting.";
        
        pulse(revisionErr, "#FFFFFF");
    };

    function onRevert(response) {
        if (response != "BAD CALL") {
            window.location = "/view/" + PAGE_ID;
            
        } else {
            onFail(response);
        }
    };
    
    requestRevert(PAGE_ID, revisionId, onRevert, onFail);
}

function addAnother() {
    hide(document.getElementById('addAnotherEmailAddress'));
    reveal(document.getElementById('editEmailAddress'));
    
    document.getElementById('emailInput').focus();
}

function saveHeader(cancelButtonId, doneButtonId) {
    var cancelButton = document.getElementById(cancelButtonId);
    if (cancelButton) {
        cancelButton.disabled = true;
    }

    var backSpin = spinButton(doneButtonId);
    
    function onFail() {
        backSpin();
        
        if (cancelButton) {
            cancelButton.disabled = false;
        }
        
        var editDetailsErr = document.getElementById('editDetailsErr');
        editDetailsErr.innerHTML = "Sorry, there was a problem saving your changes.";
        pulse(editDetailsErr);
    }
    
    function onSave(response) {
        getHeader();
    }
    
    var image = getValue('imageFrame', "");
    var name = getValue('editName', "");
    var tagline = getValue('editTagline', "");
    var email = getValue('emailInput', "");
    var invite = getChecked('inviteCheckboxInput', false);
    
    requestUpdateHeader(PAGE_ID, image, name, tagline, email, invite, onSave, onFail);
}

function savePageSection(sectionId, onSave, onFail) {
    var title = document.getElementById('editSectionTitle' + sectionId).value;
    var level = 1;
    var content = stripResponse(getFrameContent('editSectionFrame' + sectionId));
    
    requestSaveSection(PAGE_ID, sectionId, title, level, content, onSave, onFail);
}

function deletePageSection(sectionId, onDelete, onFail) {
    // Saving with an empty title and no content will delete a section.
    requestSaveSection(PAGE_ID, sectionId, "", 0, "", onDelete, onFail);
}

function insertPageSection(sectionId, trees_index, parentId, side, onSave, onFail) {
    var section = typeof(parentId) == typeof(0) ? parentId : 0;
    var title = document.getElementById('editSectionTitle' + sectionId).value;
    var level = 1;
    var content =  stripResponse(getFrameContent('editSectionFrame' + sectionId));
    
    requestInsertSection(PAGE_ID, section, side, title, level, content, onSave, onFail);
}

function editPageSection(sectionId) {
    var section = document.getElementById('pageSection' + sectionId);
    var head = document.getElementById('pageSectionHead' + sectionId);
    var title = document.getElementById('pageSectionTitle' + sectionId);
    var content = document.getElementById('pageSectionContent' + sectionId);
    var edit = document.getElementById('editPageSection' + sectionId);
    
    var err = document.createElement('div');
    
    edit.style.display = "none";
    
    var oldTitle = title.innerHTML;
    var oldContent = content.innerHTML;
    
    var editSectionTitle = document.createElement('input');
    editSectionTitle.id = 'editSectionTitle' + sectionId;
    editSectionTitle.className = 'editSectionTitle textfield';
    
    var temp = document.createElement('textarea');
    temp.innerHTML = oldTitle;
    
    editSectionTitle.value = temp.value;
    
    function onCancel() {
        edit.style.display = "inline";
        
        replace(editSectionTitle, title);
        newContent.innerHTML = oldContent;
        
        head.parentNode.removeChild(topControls);
        newContent.parentNode.removeChild(bottomControls);
        
        delete LOADED[editFrame.id];
    };
    
    function onFailSave(response) {
        err.innerHTML = "Sorry, there was an error saving your changes.";
        reveal(err);
        pulse(err);
    };
    
    function onSave(response) {
        if (response == "BAD CALL") {
            onFailSave(response);
            
            return;
            
        } else if (response == "EMPTY" && NUM_TEMP_NODES == 0) {
            PAGE_EMPTY = true;
            
            section.parentNode.innerHTML = 
                '<div id="firstThread">' +
                    'This biography is empty. Don\'t hesitate to ' +
                    '<a href="#" onclick="firstThread(unescape(\'' + escape(PAGE_ID) + '\')); return false">' +
                        'spill the beans' +
                    '</a>' +
                    '.' +
                '</div>';
               
            initEmptyBio();
            
            delete LOADED[editFrame.id];
            
            return;
            
        } else if (response == "DEL" || response == "EMPTY") {
            if (response == "EMPTY") {
                PAGE_EMPTY = true;
                
            } else {
                PAGE_EMPTY = false;
            };
            
            section.parentNode.removeChild(section);

            delete LOADED[editFrame.id];
            
            return;
            
        } else if (response == "NOP") {
            onCancel();
            
            return;
        }
        
        edit.style.display = "inline";
        
        newContent.parentNode.removeChild(newContent); // IE bug
        section.innerHTML = response;
        
        delete LOADED[editFrame.id];
    };
    
    function checkLoaded() {
        var frame = LOADED[editFrame.id];
        
        if (frame == undefined) {
            return setTimeout(checkLoaded, 100);
        }
    
        var scrollPos = document.body.scrollTop;

        content.parentNode.removeChild(content);
        
        newContent.style.display = "";
        if (!document.all) { // IE6 bug
            DOC[editFrame.id].designMode = 'on'; // FF2 bug
        } 
        
        if (document.all) {
            // IE has bizarre behavior where sometimes the iframe will render
            //    and sometimes it won't, depending on the contents. 
            //    Changing the height forces a render.
            var twiddle = editFrame.style.height;
            twiddle = parseInt(twiddle.replace(/px/, ""));
            editFrame.style.height = (twiddle + 1) + "px";
        }
        
        replace(title, editSectionTitle);
    
        head.parentNode.insertBefore(topControls, head);
        newContent.parentNode.insertBefore(bottomControls, content.nextSibling);
        
        document.body.scrollTop = scrollPos;
        
        focusFrame(editFrame);
    };
    
    var topControls = document.createElement('div');
    topControls.className = "topControls";
   
    var subLinks = document.createElement('div');
    topControls.appendChild(subLinks);
    subLinks.className = "subLinks";
    subLinks.appendChild(document.createTextNode("["));
    
    var deleteLink = document.createElement('a');
    subLinks.appendChild(deleteLink);
    deleteLink.innerHTML = "delete";
    deleteLink.className = "delete";
    deleteLink.href = "#";
    deleteLink.onclick = function() {
        deletePageSection(sectionId, onSave, onFailSave);
        return false;
    }
    
    subLinks.appendChild(document.createTextNode("] ["));
    
    var cancelLink = document.createElement('a');
    subLinks.appendChild(cancelLink);
    cancelLink.innerHTML = "cancel";
    cancelLink.className = "cancel";
    cancelLink.href = "#";
    cancelLink.onclick = function() {
        onCancel();
        return false;
    }
    
    subLinks.appendChild(document.createTextNode("]"));
    
    var newSectionTop = document.createElement('a');
    topControls.appendChild(newSectionTop);
    newSectionTop.className = "newSection";
    newSectionTop.href = "#";
    newSectionTop.onclick = function() {
        try {
            if (TEMP_TREES[sectionId] == undefined) {
                TEMP_TREES[sectionId] = [sectionId];
            }
            
            insertSection(section, "before", function() { return sectionId; }, sectionId);
            
        } finally {
            return false;
        }
    };
    newSectionTop.innerHTML = "insert a new section here <img src='/layout/uparrow.gif' />";
        
    var newContent = content.cloneNode(false);
    content.parentNode.insertBefore(newContent, content);
    newContent.style.display = "none";
    
    var editFrame = document.createElement('iframe');
    editFrame.frameBorder = "no";
    editFrame.scrolling = "no";
    editFrame.id = "editSectionFrame" + sectionId;
    newContent.appendChild(editFrame);
    editFrame.className = "replyFrame";
    editFrame.src = "/include-section?page=" + encodeURIComponent(PAGE_ID) + 
        "&section=" + encodeURIComponent(sectionId) +
        "&frame=" + encodeURIComponent(editFrame.id) +
        "&time=" + new Date().getTime();
      
    var bottomControls = document.createElement('div');
    bottomControls.className = "bottomControls";
    
    bottomControls.appendChild(err);
    err.className = "hidden errorMessage";
    
    var save = document.createElement('button');
    bottomControls.appendChild(save);
    save.id = "saveSection" + sectionId;
    save.innerHTML = 'Done';
    
    save.onclick = function() {
        subLinks.style.display = "none";
        var backSpin = spinButton(save.id);

        function onFail(response) {
            subLinks.style.display = ""; 
            backSpin();
            
            onFailSave(response);
        };

        savePageSection(sectionId, onSave, onFail);
    };
    
    var newSectionBottom = document.createElement('a');
    bottomControls.appendChild(newSectionBottom);
    newSectionBottom.className = "newSection";
    newSectionBottom.href = "#";
    newSectionBottom.onclick = function() {
        try {
            if (TEMP_TREES[sectionId] == undefined) {
                TEMP_TREES[sectionId] = [sectionId];
            }
            
            insertSection(section, "after", function() { return sectionId; }, sectionId);
            
        } finally {
            return false;
        }
    };
    newSectionBottom.innerHTML = "insert a new section here  <img src='/layout/downarrow.gif' />";
        
    checkLoaded();
}

// TODO: wretched hive of scum and villainy
function firstThread() {
    PAGE_EMPTY = true;
    
    sectionId = 'T' + INSERTED;

    TEMP_TREES[sectionId] = [];
    
    firstThreadDiv = document.getElementById('firstThread') ;

    insertSection(firstThreadDiv, "before", function() {return 0;}, sectionId);
    
    TEMP_TREES[sectionId] = [sectionId];
    
    firstThreadDiv.parentNode.removeChild(firstThreadDiv);
    
    return sectionId;
}

function initEmptyBio() { 
    var sectionId = firstThread();
    
    var newSectionBeforeId = 'newSectionBefore' + sectionId;
    var titleId = 'editSectionTitle' + sectionId;
    var frameId = 'editSectionFrame' + sectionId;
    var cancelId = 'cancelButton' + sectionId;

    hide(document.getElementById(newSectionBeforeId).parentNode);

    var t = document.getElementById(titleId);
    hide(t);
    var newT = document.createElement('span');
    newT.id = 'emptyBioTitle' + sectionId;
    newT.innerHTML = 'Overview';
    newT.style.display = 'block';
    newT.onclick = function() {
        swapDisplay(newT.id, t.id);
        t.focus();
        t.select();
    }
    t.parentNode.appendChild(newT);

    var f = document.getElementById(frameId);
    
    function checkLoaded() {
        var frame = LOADED[f.id];
        
        if (frame == undefined) {
            return setTimeout(checkLoaded, 100);
        }
        
        focusFrame(f);
    
        //questionForm();
    }
    
    checkLoaded();
    
    hide(document.getElementById(cancelId));
}

function insertSection(section, side, getParentId, trees_index) {
    NUM_TEMP_NODES += 1;

    var sectionId = 'T' + INSERTED;
    INSERTED += 1;
    
    var tree = TEMP_TREES[trees_index];
    
    for (var i = 0; i < tree.length; i++) {
        if (tree[i] == getParentId()) {
            if (side == "before") {
                tree.splice(i, 0, sectionId);
                
            } else {
                tree.splice(i+1, 0, sectionId);
            }
            
            break;
        }
    }
    
    var newSection = document.createElement('div');
    newSection.id = 'pageSection' + sectionId;
    newSection.className = 'pageSection';
    
    newSection.innerHTML = 
        '<div class="topControls">' +
            '<div id="subLinks' + escape(sectionId) + '" class="subLinks">' +
                '[<a id="delete' + escape(sectionId) + '" class="delete" href="#">delete</a>] ' +
                '[<a id="cancel' + escape(sectionId) + '" class="cancel" href="#">cancel</a>]' +
            '</div>' +
            '<a id="newSectionBefore' + escape(sectionId) + '" class="newSection" href="#">insert a new section here <img src=\'/layout/uparrow.gif\' /></a>' +
        '</div>' +
        '<div id="pageSectionHead' + escape(sectionId) + '" class="pageSectionHead">' +
            '<h4>' +
                '<input id="editSectionTitle' + escape(sectionId) + '" class="editSectionTitle textfield" value="Overview" />' +
            '</h4>' +
        '</div>' +
        '<div id="pageSectionContent' + escape(sectionId) + '" class="pageSectionContent">' +
            '<iframe id="editSectionFrame' + escape(sectionId) + '" class="replyFrame" scrolling="no" frameborder=0 ' +
                'src="/form-blank-comment?frame=editSectionFrame' + escape(sectionId) + '">' + 
            '</iframe>' +
        '</div>' +
        '<div id="newSectionErr' + escape(sectionId) + '" class="hidden errorMessage"></div>' +
        '<div class="bottomControls">' +
            '<button id="saveButton' + escape(sectionId) + '">Done</button>' +
            '<a id="newSectionAfter' + escape(sectionId) + '" class="newSection" href="#">insert a new section here  <img src=\'/layout/downarrow.gif\' /></a>' +
        '</div>';

    if (side == "before") {
        section.parentNode.insertBefore(newSection, section);
    } else {
        section.parentNode.insertBefore(newSection, section.nextSibling);
    }
    
    var subLinks = document.getElementById('subLinks' + sectionId);
    
    var err = document.getElementById('newSectionErr' + sectionId);
    
    var newSectionBefore = document.getElementById('newSectionBefore' + sectionId);
    newSectionBefore.onclick = function() {
        insertSection(newSection, "before", function(){ return sectionId; }, trees_index);
            
        return false;
    };
    
    var editSectionTitle = document.getElementById('editSectionTitle' + sectionId);
    if (editSectionTitle) {
        editSectionTitle.focus();
        editSectionTitle.select();
    }
    
    function onCancel() {
            NUM_TEMP_NODES -= 1;
    
            if (NUM_TEMP_NODES == 0 && PAGE_EMPTY == true) {
                newSection.parentNode.innerHTML = 
                    '<div id="firstThread">' +
                        'This biography is empty. Don\'t hesitate to ' +
                        '<a href="#" onclick="firstThread(unescape(\'' + escape(PAGE_ID) + '\')); return false">' +
                            'spill the beans' +
                        '</a>' +
                        '.' +
                    '</div>';
                    
               initEmptyBio();
                    
            } else {
                newSection.parentNode.removeChild(newSection);
            }
        }
    
    var deleteTopLink = document.getElementById('delete' + sectionId);
    deleteTopLink.onclick = function() {
        onCancel();
        return false;
    };
    
    var cancelLink = document.getElementById('cancel' + sectionId);
    cancelLink.onclick = function() {
        onCancel();
        return false;
    };
    
    var saveButton = document.getElementById('saveButton' + sectionId);
    saveButton.onclick = function () {
        backSpin = spinButton(saveButton.id);
        subLinks.style.display = "none";

        var tree = TEMP_TREES[trees_index];
        var index = null;
        var nearestNode = null;
        var dir = "after";
        
        for (var i = 0; i < tree.length; i++) {
            if (typeof(tree[i]) == typeof(0)) {
                nearestNode = tree[i];
                
                if (index != null) {
                    break;
                }
                
            } else if (tree[i] == sectionId) {
                index = i;
                
                if (nearestNode != null) {
                    break;
                    
                } else {
                    dir = "before";
                }
            }
        }
        
        function onFail(response) {
            backSpin();
            subLinks.style.display = "";
            
            err.innerHTML = "Sorry, there was an error saving your changes.";
            reveal(err);
            pulse(err);
        };
        
        function onSave(response) {
            if (response == "BAD CALL") {
                return onFail(response);
            }
            
            backSpin();
            subLinks.style.display = "";
            
            if (response == "-1") {
                onCancel();
                
                return;
            }
            
            PAGE_EMPTY = false;
            
            tree = TEMP_TREES[trees_index];
            
            oldSectionId = sectionId;
               
            var section = document.getElementById('pageSection' + oldSectionId);
            var editFrame = document.getElementById('editSectionFrame' + oldSectionId);
            
            editFrame.parentNode.removeChild(editFrame); // IE bug
            section.innerHTML = response;
            
            for (var i = 0; i < tree.length; i++) {
                if (tree[i] == oldSectionId) {
                    tree[i] = parseInt(section.firstChild.id.replace("pageSection", ""));
                    break;
                }
            }
            
            NUM_TEMP_NODES -= 1;
        }
        
        insertPageSection(sectionId, trees_index, nearestNode, dir, onSave, onFail);
    };
    
    var newSectionAfter = document.getElementById('newSectionAfter' + sectionId);
    newSectionAfter.onclick = function() { 
        insertSection(newSection, "after", function() { return sectionId; }, trees_index);
            
        return false;
    };
}


/** URLs **/

var urlPattern = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?");

function findURL(text) {
    var chunks = text.split(/(\s|\n)*/);
    
    for (var i = 0; i < chunks.length; i++) {
        var match = urlPattern.exec(chunks[i]);
        
        if (match) {
            alert('found!');
        }
    }
}



/** Discussion ************************************************************** */

function postNewThread(newThreadDivId, titleId, contentFrameId) {
    if (DOC[contentFrameId] == null) {
        return;
    }
    
    var title = document.getElementById(titleId);
    var titleData = title.value;
    
    var contentFrame = document.getElementById(contentFrameId);
    var contentData = stripResponse(getFrameContent(contentFrameId));
    
    function onFail(response) {
        var newThreadErr = document.getElementById('newThreadErr');
        
        newThreadErr.innerHTML = "Sorry, there was an error posting your new thread.";
        
        pulse(newThreadErr);
    };
    
    function save(response) {
        if (response == "BAD CALL") {
            return onFail(response);
        }

        var newThread = document.createElement('div');
        newThread.innerHTML = response;

        var newThreadDiv = document.getElementById(newThreadDivId);
        if (newThreadDiv != undefined) {
            newThreadDiv.parentNode.insertBefore(newThread, newThreadDiv.nextSibling);
        }
        
        title.value = "Untitled";
        
        // TODO: Remove magic values
        contentFrame.src = "/form-blank-comment?frame=newThreadFrame";
        hideNewThreadForm('newThreadComment', 'newThreadLink');
        
        var noComments = document.getElementById('noComments');
        if (noComments != undefined) {
            noComments.parentNode.removeChild(noComments);
        }
    };
    
    requestNewThread(PAGE_ID, titleData, contentData, save, onFail);
}

function saveDiscussionDescription() {
    var title = getValue('descriptionTitle', "");
    var desc = getFrameContent('descriptionFrame');
    
    var backSpin = spinButton('postDescription');
    
    function onFail(response) {
        backSpin();
        
        var err = document.getElementById('descriptionErr');
        err.innerHTML = "Sorry. There was an error while saving. Please try again later.";
        
        reveal(err);
        pulse(err);
    }
    
    function onSuccess(response) {
        replaceWithHTML('talkDescription', response);
    }
    
    requestSaveDiscussionDescription(PAGE_ID, title, desc, onSuccess, onFail);
}

function submitComment(replyId, contentFrameId) {
    if (DOC[contentFrameId] == null) {
        return;
    }
    
    var contentFrame = document.getElementById(contentFrameId);
    var contentData = stripResponse(getFrameContent(contentFrameId));
    
    function onFail(response) {
        var replyErr = document.getElementById('replyErr' + replyId);
        
        replyErr.innerHTML = "Sorry, there was an error posting your reply.";
        
        pulse(replyErr);
    }
    
    function save(response) {
         removeReplyForm(replyId);
         
         appendReply(replyId, response);
    }
    
    requestPostComment(PAGE_ID, replyId, contentData, save, onFail);
}

function revealNewThreadForm(commentId, linkId) {
    var link = document.getElementById(linkId);
    if (link != undefined) {
        link.style.display = "none";
    }
    
    var comment = document.getElementById(commentId);
    if (comment != undefined) {
        comment.style.visibility = "visible";
        comment.style.height = "auto";
    }
    
    var title = document.getElementById('newThreadTitle');
    if (title != undefined) {
        title.focus();
        title.select();
    }
}

function hideNewThreadForm(commentId, linkId) {
    var link = document.getElementById(linkId);
    if (link != undefined) {
        link.style.display = "block";
    }
    
    var comment = document.getElementById(commentId);
    if (comment != undefined) {
        comment.style.height = "0px";
        comment.style.visibility = "hidden";
    }
}

function insertReplyForm(commentId) {
    var replyLink = document.getElementById('replyLink' + commentId);
    replyLink.style.visibility = "hidden";
    
    function insertForm(content) {
        var replyForm = document.createElement('div');
        replyForm.id = 'reply' + commentId + 'Form';
        replyForm.className = 'reply';
        replyForm.innerHTML = content;

        var response = document.getElementById('response' + commentId);
        response.parentNode.insertBefore(replyForm, response.nextSibling);
        
        var replyFrame = document.getElementById('replyFramereply' + commentId);
        if (replyFrame != undefined) {
            function checkLoaded() {
                var frame = LOADED[replyFrame.id];
                
                if (frame == undefined) {
                    return setTimeout(checkLoaded, 100);
                }
                
                focusFrame(replyFrame);
            }
            
            checkLoaded();
        }
    };
    
    function onFail(response) {
        insertForm("<div class='errorMessage'>Sorry, there was an error.</div>");
    };
    
    function handleResponse(response) {
        insertForm(response);
    };
    
    requestGetReplyForm(commentId, 'reply' + commentId, handleResponse, onFail);
}

function removeReplyForm(commentId) {
    var replyLink = document.getElementById('replyLink' + commentId);
    replyLink.style.visibility = "visible";
    
    var replyForm = document.getElementById('reply' + commentId + 'Form');
    replyForm.parentNode.removeChild(replyForm);
}

function appendReply(parentId, replyData) {
    var reply = document.createElement('div');
    reply.className = 'reply';
    reply.innerHTML = replyData;
    
    var response = document.getElementById('response' + parentId);
    response.parentNode.insertBefore(reply, response.nextSibling);
}

function addAConnectionSearch(searchString, resultsElementId, offset, num) {
    var resultsElement = document.getElementById(resultsElementId);
    
    function onFail(response) {
        resultsElement.innerHTML = "Sorry, there was an error.";
        resultsElement.style.visibility = "visible";
    };
    
    function showResults(response) {
        if (response != "") {
            resultsElement.innerHTML = response;
            resultsElement.style.visibility = "visible";
            
        } else {
            onFail(response);
        }
    };
    
    offset = offset ? offset : 0;
    num = num ? num : 8;
    
    requestSearchAddAConnection(searchString, offset, num, showResults, onFail);
}



/** Image Upload ************************************************************ */

function updateImage(formId, frameId, imageId, errId) {
    var form = document.getElementById(formId);
    var image = document.getElementById(imageId);
    
    var revertWaiting = ajaxWaiting(image);
    
    if (form) {
        var frame = document.getElementById(frameId);
        
        if (frame) {
            function changeImage() {
                if (image) {
                    var filename = stripResponse(getFrameContent(frameId));
                    
                    if (filename) {
                        if (filename == "INVALID") {
                            var errBox = document.getElementById(errId);

                            if (errBox) {
                                errBox.innerHTML = "That file cannot be used.";
                                
                                pulse(errBox);
                            }
                            
                            revertWaiting();
                            
                        } else {
                            image.src = imageURL(filename);
                            image.onload = revertWaiting;
                        }
                    }
                }
            }

            frame.onload = changeImage; // FF, etc.
            
            frame.onreadystatechange = function () { // IE
                switch (frame.readyState) {
                    case 'complete':
                        changeImage();
                        break;
            
                    default:
                        break;
                }
            };
            
            form.target = frameId;
            form.submit();
        }
    }
}


/** Login ******************************************************************* */

function submitLogin() {
    var userField = document.getElementById('loginUser');
    var passField = document.getElementById('loginPass');
    
    function onFail(response) {
        var loginErr = document.getElementById('loginErr');
        
        loginErr.innerHTML = "Sorry, an error occurred while logging in. Please try again later.";
        
        pulse(loginErr);
    };
    
    function onLogin(response) {
        switch (response) {
            case "OK": 
                closeLightBox('login');
                triggerEvent('login', "logged in");
                
                break;
            
            case "NO":
                var loginErr = document.getElementById('loginErr');
                loginErr.innerHTML = "Invalid username or password. Please try again.";
                pulse(loginErr);
                
                break;
                
            default: 
                onFail(response); 
                
                break;
        }
    };
    
    var user = userField.value;
    var pass = passField.value;
    
    requestLogin(user, pass, onLogin, onFail); 
}

function submitRegister() {
    var userField = document.getElementById('regUser');
    var passField = document.getElementById('regPass');
    var emailField = document.getElementById('regEmail');

    function onFail(response) {
        var regErr = document.getElementById('regErr');
        
        regErr.innerHTML = "An error occurred while registering. Please try again later.";
        
        pulse(regErr);
    };

    function onRegister(response) {
        switch (response) {
            case "OK": 
                closeLightBox('register');
                triggerEvent('login', 'logged in');
                
                break;
            
            case "NO":
                var regErr = document.getElementById('regErr');
                regErr.innerHTML = "Username taken, or invalid registration information.";
                pulse(regErr);
                
                break;
                
            default: 
                onFail(response);
                
                break;
        }
    };
    
    var user = userField.value;
    var pass = passField.value;
    var email = emailField.value;
    
    requestRegister(user, pass, email, onRegister, onFail);
}

function submitLogoff() {
    function onFail(response) {
        var login = document.getElementById('login');
        
        login.innerHTML = "There was an error. Please refresh the page.";
    };

    function update(response) {
        triggerEvent('login', "logged out");
    };

    requestLogoff(update, onFail);
}

function updateLogin(info) {
    var login = document.getElementById('login');
    
    if (login == undefined) {
        return;
    }
    
    function onFail(response) {
        var login = document.getElementById('login');
        
        login.innerHTML = 'There was an error. Please refresh the page.';
    };

    function display(response) {
        replaceWithHTML(login, response);
    };
    
    requestUpdateLogin(display, onFail);
    
} addListener('login', updateLogin);

function updateNewThread(info) {
    var names = document.getElementsByName('userName');
    var images = document.getElementsByName('userImage');
    
    if (names.length > 0 || images.length > 0) {
        function onFail(response) {
            display("(Error)\nasterisk.gif");
        };

        function display(response) {
            var N = response.split(/\n/);
            
            var userName = N[0];
            var userImage = imageURL(N[1]);
            
            for (i in names) {
                names[i].innerHTML = userName;
            }
            
            for (i in images) {
                images[i].src = userImage;
            }
        };
        
        requestLoginInfo(display, onFail);
    }
    
} addListener('login', updateNewThread);

function setPictureFormRadio(isTop) {
    var comp = document.getElementById('pictureFormRadioComputerContent');
    var web = document.getElementById('pictureFormRadioWebContent');
    
    if (isTop) {
        comp.style.display = '';
        web.style.display = 'none';
        
    } else {
        comp.style.display = 'none';
        web.style.display = '';
    }
    
    var compErr = document.getElementById('pictureFormCompErr');
    var webErr = document.getElementById('pictureFormWebErr');
    
    if (compErr) {
        compErr.innerHTML = '';
    }
    
    if (webErr) {
        webErr.innerHTML = '';
    }
}

function updateWebImage(fieldId, picId, frameId) {
    var field = document.getElementById(fieldId);
    var pic = document.getElementById(picId);
    var frame = document.getElementById(frameId);
    
    if (field == undefined || frame == undefined) {
        return;
    }
    
    if (pic) {
        pic.src = field.value;
    }
    
    setFrameContent(frame, field.value);
}

function imageURL(filepath) {
    var relative = true;
    if (filepath.search(/:/) != -1) {
        relative = false;
    }
    
    if (relative) {
        return '/images/' + encodeURIComponent(filepath);
        
    } else {
        return filepath;
    }
}

function choosePhoto(picId, frameId) {
    var imageName = document.getElementById(frameId);

    var currentPic = stripResponse(imageName.value);
    
    function whenDone(filename) {
        var relative = true;
        if (filename.search(/:/) != -1) {
            relative = false;
        }
        
        var pic = document.getElementById(picId);
        var imgName = document.getElementById(frameId);
        
        if (pic) {
            pic.onload = function() {
                // Force Safari to re-draw the page after the image has loaded,
                //     because certain pictures cause it to display weird artifacts.
                window.scrollBy(0,1);
                window.scrollBy(0,-1);
            };
        
            pic.src = imageURL(filename);
        }
        
        if (imgName) {
            imgName.value = filename;
        }
    }
    
    pictureForm(currentPic, whenDone);
}

function removePhoto(picId, filenameId, defaultPic) {
    var imageFilename = document.getElementById(filenameId);
    if (imageFilename.tagName.toLowerCase() == "iframe") {
        setFrameContent(imageFilename, defaultPic);
    } else {
        imageFilename.value = defaultPic;
    }
    
    var pic = document.getElementById(picId);
    pic.src = imageURL(defaultPic);
}

function editDetails() {
    getEditHeader();
}

function endEditDetails() {
    getHeader();
}

function addConnection(connectionId) {
    var backSpin = spinBox();

    function onFail(response) {
        backSpin();
        
        var connectErr = document.getElementById('connectErr');
        
        if (connectErr) {
            connectErr.innerHTML = "Sorry. The change could not be made.";
            
            pulse(connectErr);
        }
    };

    function update(response) {
        if (response == "BAD CALL") {
            return onFail(response);
        }
        
        backSpin();
        
        if (response == "NOP") {
            var connectErr = document.getElementById('connectErr');
            
            if (connectErr) {
                connectErr.innerHTML = "That connection already exists.";
                
                pulse(connectErr);
            }
            
            return;
        }
        
        closeLightBox('disambiguation');
        closeLightBox('create-a-new-connection');
        closeLightBox('add-a-connection');
        
        updateConnections();
                
        var relationships = document.getElementById('relationshipGroup');
        if (relationships) {
            var temp = document.createElement('div');
            temp.innerHTML = response;
            
            relationships.insertBefore(temp.firstChild, relationships.firstChild);
        }
    }
    
    requestAddConnection(PAGE_ID, connectionId, update, onFail);
}

function removeConnection(connectionId) {
    var img = document.getElementById('searchResultImage' + connectionId);
    var backSpin = ajaxWaiting(img);

    function onFail(response) {
        backSpin();
        
        removeConnectionsErr = document.getElementById('removeConnectionsErr');
        removeConnectionsErr.innerHTML = "There was an error. Please try again later.";
        pulse(removeConnectionsErr);
    };

    function update(response) {
        if (response == "BAD CALL") {
            return onFail();
        }
        
        backSpin();
        
        closeLightBox('remove-connections');
        
        updateConnections();
        
        var relationship = document.getElementById('relationship.' + connectionId);
        if (relationship) {
            relationship.parentNode.removeChild(relationship);
        }
    };
    
    requestRemoveConnection(PAGE_ID, connectionId, update, onFail);
}

function updateConnections() {
    var pageConnections = document.getElementById('pageConnections');
    
    if (pageConnections == undefined) {
        return;
    }

    function onFail(response) {
        pageConnections.innerHTML = "<div class='title'>Connections</div>" +
            "<div class='errorMessage'>" +
                "There was an error.<br>" + 
                "Please refresh the page." +
            "</div>";
    };

    function update(response) {
        pageConnections.innerHTML = response;
    };
    
    requestUpdateConnections(PAGE_ID, update, onFail);
}

function moreRelationships(offset, num) {
    var moreRelationships = document.getElementById('moreRelationships');
    var revert = ajaxWaiting(moreRelationships, "/images/tinyspin.gif");
    
    function onFail(response) {
        revert();
        
        var errDiv = document.createElement('div');
        
        replace(moreRelationships, errDiv);
        
        errDiv.className = "errorMessage";
        errDiv.innerHTML = "There was an error retrieving more connections.";
        
        pulse(errDiv);
    }
    
    function appendRelationships(response) {
        revert();
        
        replaceWithHTML(moreRelationships, response); 
    }
    
    requestMoreRelationships(PAGE_ID, offset, num, appendRelationships, onFail);
}

function getEditHeader() {
    var pageDetails = document.getElementById('pageDetails');
    
    if (pageDetails == undefined) {
        return;
    }

    function onFail(response) {
        var edit = document.getElementById('editDetails');
        
        edit.innerHTML = "<div class='errorMessage'>There was an error. " + 
            "Please refresh the page and try again later.</div>";
            
        pulse(edit);
    };

    function update(response) {
        pageDetails.innerHTML = response;
    }
    
    requestGetEditHeader(PAGE_ID, update, onFail);
}

function getHeader(onComplete) {
    var pageDetails = document.getElementById('pageDetails');
    
    if (pageDetails == undefined) {
        return;
    }

    function onFail(response) {
        var editDetailsErr = document.getElementById('editDetailsErr');
        
        editDetailsErr.innerHTML = "There was an error updating the page. Please refresh.";
        
        pulse(editDetailsErr);
    };

    function update(response) {
        pageDetails.innerHTML = response;
        
        if (onComplete != undefined && typeof(onComplete) == "function") {
            onComplete();
        }
    };
    
    requestGetHeader(PAGE_ID, update, onFail);
}



/** LinkedIn **************************************************************** */

function linkedInLogin() {
    var user = getValue('linkedInUsername', "");
    var pass = getValue('linkedInPassword', "");
    
    var backSpin = spinButton('linkedInSubmit');
    
    function onFail() {
        backSpin();
        
        var err = document.getElementById('linkedInErr');
        
        err.innerHTML = "Login was unsuccessful. Please try again.";
        
        reveal(err);
        pulse(err);
    }
    
    function onSuccess(response) {
        if (response == "OK") {
            backSpin();
            window.location.reload(true);
            
        } else {
            onFail();
        }
    }
    
    requestLinkedInLogin(user, pass, onSuccess, onFail);   
}

function linkedInCaptcha() {
    var answer = getValue('linkedInCaptchaAnswer', "");
    var secret = getValue('linkedInCaptchaSecret', "");
    var id = getValue('linkedInCaptchaId', "");
    
    var backSpin = spinButton('linkedInSubmit');
    
    function onFail(response) {
        backSpin();
        
        window.location.reload(true);
    }
    
    function onSuccess(response) {
        if (response == "OK") {
            backSpin();
        
            window.location.reload(true);
            
        } else {
            onFail(response);
        }
    }
    
    requestLinkedInCaptcha(answer, secret, id, onSuccess, onFail);
}




/** E-mail Protection ******************************************************* */

function showEmails() {
    var emails = document.getElementsByTagName('img');
    var toReplace = [];
    
    for (var i = 0; i < emails.length; i++) {
        if (emails[i].className && emails[i].className.search(/safeEmail/) != -1) {
            var mailto = document.createElement('a');
            mailto.innerHTML = emails[i].name + "@" + "biographicon.com";
            mailto.href = "mailto" + ":" + mailto.innerHTML;

            toReplace.push({
                'email': emails[i],
                'mailto': mailto
            })
        }
    }
    
    for (var i = 0; i < toReplace.length; i++) {
        var tor = toReplace[i];
        replace(tor['email'], tor['mailto']);
    }
}


/** On Load ***************************************************************** */

window.onload = function() {
    try {
        for (i in ON_LOAD) {
            ON_LOAD[i]();
        }
    } catch (e) {}
    
    document.onkeydown = keyDown;
    document.onblur = keyBlur;
    document.onkeyup = keyUp;
    
    showEmails();
}



/** EOF ********************************************************************* */
