function trim(text) {
    try {
        return text.toString().replace(/^\s*(.*)$/, "$1").replace(/(.*?)\s*$/, "$1");
    } catch (cantDoToString) {
        return null;
    }
}

if (typeof(String.trim) != "function") {
    String.prototype.trim = function() {
        return this.replace(/^\s*(.*)$/, "$1").replace(/(.*?)\s*$/, "$1");
    };
}

function createAjaxRequest() {
    try {
        return new XMLHttpRequest();
    } catch (noNativeSupport) {
        try {
            return new ActiveXObject("Msxml12.XMLHTTP");
        } catch (noIE7ActiveXSupport) {
            try {
                return new ActiveXObject("Microsoft.XMLHTTP");
            } catch (noAjaxSupport) {
                return null;
            }
        }
    }
}

function addEventHandler(element, eventName, handler) {
    if (element.addEventListener) {
        element.addEventListener(eventName, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + eventName, handler);
    }
}

function getActivatedObject(event) {
    if (event.target) {
        return event.target;
    }
    
    if (event.target) {
        return event.target;
    }

    if (window.event && window.event.srcElement) {
        return window.event.srcElement;
    }
    
    return null;
}

function isEmpty(subject) {
    if (subject == null || subject == undefined) {
        return true;
    }
    
    if (typeof(subject) == "number") {
        return !Boolean(subject);
    }
    
    if (typeof(subject) == "string") {
        return (subject.trim().length == 0);
    }
    
    if (typeof(subject.value) != "undefined") {
        var value = trim(subject.value);
        
        if (value.length == 0) {
            return true;
        }
        
        var numVal = parseFloat(value);
        
        if (isNaN(numVal)) {
            return false;
        }
        
        return (numVal == 0.0);
    }
    
    return false;
}

var dayNames   = new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
var monthNames = new Array("January","February","March","April","May","June","July","August","September","October","November","December");

var months = {
    "01": "Jan",
    "1" : "Jan",
    "02": "Feb",
    "2" : "Feb",
    "03": "Mar",
    "3" : "Mar",
    "04": "Apr",
    "4" : "Apr",
    "05": "May",
    "5" : "May",
    "06": "Jun",
    "6" : "Jun",
    "07": "Jul",
    "7" : "Jul",
    "08": "Aug",
    "8" : "Aug",
    "09": "Sep",
    "9" : "Sep",
    "10": "Oct",
    "11": "Nov",
    "12": "Dec"
};

var controllerName = "";
var actionName     = "";

var leads = ["unassigned", "returned", "expiring", "new", "active", "auto"];
var tasks = ["overdue"];

function isPositiveInt(numberValue) {
    var number = parseInt(numberValue.toString());
    
    return (!isNaN(number) && number > 0);
}

function isEmailFormat(emailAddress) {
    return /^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/.test(emailAddress);
}

function isPhoneNumberFormat(phoneNumber) {
    return /^\d{10}/.test(phoneNumber.toString().replace(/\D/g, ""));
}

function isZipCodeFormat(zipCode) {
    return /^\d{5}/.test(zipCode.toString().replace(/\D/g, ""));
}

function isMMDDYYY(dateText) {
    return (typeof(dateText) == "string" && /^\d{2}\/\d{2}\/\d{4}$/.test(dateText));
}

function formatDateTime(dateTime) {
    var rx = new RegExp("^(\\d{4})-(\\d{2})-(\\d{2})\\s+((\\d{2}):(\\d{2}))(:\\d{2})?$");
    
    var matches = rx.exec(dateTime);
    
    if (matches) {
        return matches[3] + " " + months[matches[2]] + " " + matches[1] + " " + matches[4];
    }
    
    return dateTime;
}

// Function common to Zips/Index, Zips/Cities and Zips/Zips
function getNumCheckedBoxes(formElement, groupName) {
    if (!(/\[\]$/.test(groupName))) {
        groupName += "[]";
    }
    
    var checkboxes = formElement.elements[groupName];
    
    if (checkboxes) {
        if (checkboxes.length) {
            if (checkboxes.length > 0) {
                var numCheckedBoxes = 0;
                
                for (var i = 0; i < checkboxes.length; i++) {
                    if (checkboxes[i].checked) {
                        numCheckedBoxes++;
                    }
                }
                
                return numCheckedBoxes;
            }
        } else if (checkboxes.checked) {
            return 1;
        }
    }
    
    return 0;
}

function setLabelAndCount(element, label, count) {
    var divs = element.getElementsByTagName("div");
    
    for (var i = 0; i < divs.length; i++) {
        if (divs[i].className == "label") {
            divs[i].appendChild(document.createTextNode(label));
        } else if (divs[i].className == "count") {
            divs[i].appendChild(document.createTextNode(count));
        }
    }
}

function checkEmailIsTaken(element) {
    var newEmail = trim(element.value);

    if (newEmail.length > 0) {
        // Make sure there really is a change going on here. If the input e-mail is only different from the original in case
        // or beginning or ending white space, don't do the AJAX check because it -WILL- report that it's taken. This is, of 
        // course, something we already know and, in this case, it is -NOT- an error.
        var rx = new RegExp("^\\s*" + original + "\\s*$", "i");
    
        // REMEMBER: If the input e-mail does NOT match the original e-mail, ONLY THEN do we want to do the AJAX test.
        if (!rx.test(newEmail)) {
            // Verify that the value for "email" is actually in proper e-mail address format. If it isn't, don't bother doing 
            // the AJAX test. Just give an error alert and quit here.
            if (!isEmailFormat(newEmail)) {
                alert("The entered e-mail address is not in proper format. Please re-enter.");
                return;
            }
    
            if (ajax = createAjaxRequest()) {
                ajax.open("GET", "/index/email-is-taken/email/" + newEmail, true);
    
                ajax.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        // The AJAX page returns a string containing either "true" or "false". If it is "true", then the
                        // e-mail address in question is already in use. So, display an error and clear the entry.
                        if (this.responseText == "true") {
                            alert("ERROR: This e-mail address is already in use on our system.");
    
                            if (original.length > 0) {
                                element.value = original;
                            } else {
                                element.value = "";
                            }
    
                            // Oh, and put the cursor back inside the e-mail input, for convenience (or spite, whichever).
                            element.focus();
                        }
                    }
                }
    
                ajax.send(null);
            }
        }
    }
}

function verifyLoginForm(form) {
    if (!isEmailFormat(form.elements["email"].value)) {
        form.elements["email"].value = "";
        form.elements["email"].focus();
        return false;
    }
    
    if (isEmpty(form.elements["password"])) {
        form.elements["password"].value = "";
        form.elements["password"].focus();
        return false;
    }
    
    return true;
}

function sendPassword() {
    var ajax = createAjaxRequest();
    
    if (ajax) {
        var userEmail = prompt("Please enter your e-mail address. (Must match the one we have on record...)");
        
        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                alert(this.responseText);
            }
        };
        
        ajax.open("GET", "/index/send-password/email/" + userEmail, true);
        
        ajax.send(null);
    }
}

function reschedule(checkbox, taskId, leadId) {
    if (!isNaN(parseInt(leadId))) {
        window.location.href = "/leads/edit/id/" + leadId + "/task_id/" + taskId;
        return;
    }

    window.location.href = "/index/task/id/" + taskId;
}

function markCompleted(checkbox, taskId, leadId) {
    if (!isNaN(parseInt(leadId))) {
        window.location.href = "/leads/edit/id/" + leadId + "/task_id/" + taskId;
        return;
    }

    if (checkbox.checked) {
        var ajax = createAjaxRequest();

        if (ajax && confirm("Mark task completed?")) {
            ajax.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    if (this.responseText == "false") {
                        alert("ERROR. Failed to write to database.");
                    } else {
                        window.location.reload(true);
                    }
                }
            }

            ajax.open("GET", "/index/mark-completed/id/" + taskId, true);

            ajax.send(null);
        }
    }

    checkbox.checked = false;
}

function markCancelled(checkbox, taskId) {
    if (checkbox.checked) {
        var ajax = createAjaxRequest();

        if (ajax && confirm("Mark task cancelled?")) {
            ajax.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    if (this.responseText == "false") {
                        alert("ERROR. Failed to write to database.");
                    } else {
                        window.location.reload(true);
                    }
                }
            }

            ajax.open("GET", "/index/mark-cancelled/id/" + taskId, true);

            ajax.send(null);
        }
    }

    checkbox.checked = false;
}

function moveCalendar(numUnits) {
    var calendar = document.getElementById("calendar");

    var left   = -3570;
    var leftPx = parseInt(calendar.style.left);

    if (!isNaN(leftPx)) {
        left = leftPx;
    }

    calendar.style.left = (left - (numUnits * 162)) + "px";
}

function moveRight(numDays) {
    moveCalendar(numDays);
}

function moveLeft(numDays) {
    moveCalendar(-1 * numDays);
}

function verifyTaskForm(form) {
    var msg = "A required field has been skipped. Please double-check you entries and try again.";

    if (isEmpty(form.elements["title"])) {
        form.elements["title"].value = "";
        form.elements["title"].focus();
        alert(msg);
        return false;
    }

    if (isEmpty(form.elements["due"])) {
        form.elements["due"].value = "";
        form.elements["due"].focus();
        alert(msg);
        return false;
    }

    form.elements["title"].value = trim(form.elements["title"].value);
    form.elements["due"].value   = trim(form.elements["due"].value);

    if (!isMMDDYYY(form.elements["due"].value)) {
        form.elements["due"].focus();
        alert("The entered due date is not in proper date format. Please re-enter.");
        return false;
    }

    return true;
}

function reopenTask(taskID) {
    var ajax = createAjaxRequest();

    if (ajax && confirm("Reopen this task?")) {
        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "false") {
                    alert("ERROR. Failed to write to database.");
                } else {
                    window.location.reload(true);
                }
            }
        }

        ajax.open("GET", "/index/reopen-task/id/" + taskID, true);

        ajax.send(null);
    }
}

function assignLeadsToUser(selectElement) {
    if (selectElement.selectedIndex > 0) {
        var checkboxes = selectElement.form.elements["lead_id"];

        var leadIDs = new Array();

        // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
        if (checkboxes.length != undefined) {
            // There are multiple checkboxes in the form, so it is a NodeList.
            for (var i = 0; i < checkboxes.length; i++) {
                if (checkboxes[i].checked) {
                    leadIDs.push(checkboxes[i].value);
                }
            }
        } else {
            // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
            if (checkboxes.checked) {
                leadIDs.push(checkboxes.value);
            }
        }

        var ajax = createAjaxRequest();

        // Was anything checked?
        if (ajax && leadIDs.length > 0) {
            // Apparently this call to "open" must come BEFORE setting the content type header...
            ajax.open("POST", "/leads/assign-leads-to-user", true);

            ajax.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    if (this.responseText == "success") {
                        alert("SUCCESS: Assignments made.");

                        window.location.reload(true);
                    } else {
                        alert("ERROR: Assignments failed.");
                    }
                }
            };

            // IMPORTANT: It won't go without this header...
            ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            ajax.send(
                "user_id=" + selectElement.options[selectElement.selectedIndex].value
                + "&lead_ids=" + leadIDs.toString()
            );
        }
    }
}

function changeLeadStatus(select, leadID) {
    var statusID = parseInt(select.options[select.selectedIndex].value);

    leadID = parseInt(leadID);

    var ajax = createAjaxRequest();

    if (ajax && !isNaN(statusID) && !isNaN(leadID)) {
        ajax.open("GET", "/leads/change-lead-status/lead_id/" + leadID + "/status_id/" + statusID, true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("SUCCESS: Status updated.");
                } else {
                    alert("ERROR: Failed to write.");
                }
            }
        };

        ajax.send(null);
    }
}

function toggleNewNote(divID) {
    var div = document.getElementById(divID);

    if (/active/.test(div.className)) {
        div.className = "newNote";
    } else {
        div.className = "newNote active";
    }
}

function writeNewNote(textareaID, leadID) {
    var note = trim(document.getElementById(textareaID).value);

    leadID = parseInt(leadID);

    var ajax = createAjaxRequest();

    if (ajax && note.length > 0 && !isNaN(leadID)) {
        ajax.open("POST", "/leads/save-new-note", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var data = eval("(" + this.responseText + ")");

                if (data.length && data.length > 0) {
                    alert("SUCCESS: Note written.");

                    window.location.reload(true);
                } else {
                    alert("ERROR: Failed to write note.");
                }
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        ajax.send("lead_id=" + leadID + "&note=" + escape(note));
    }
}

function showLeadNotes(leadID) {
    var wrapper = jQuery("#notes_" + leadID);
    var target  = jQuery("#notes_" + leadID + "_target");

    wrapper.addClass("active");

    jQuery.getJSON(
        "/leads/fetch-lead-notes",
        { "id" : leadID },
        function(notes) {
            if (notes.length && notes.length > 0) {
                target.empty();

                for (var i = 0; i < notes.length; i++) {
                    target.append("<div class=\"note\"><div class=\"date\">" + notes[i].recorded + "</div><div class=\"text\">" + notes[i].note + "</div></div>");
                }
            } else {
                target.text("(No notes found...)");
            }
        }
    );
}

function hideLeadNotes(leadID) {
    var wrapper = jQuery("#notes_" + leadID);
    var target  = jQuery("#notes_" + leadID + "_target");

    wrapper.removeClass("active");

    target.empty();
    target.text("(Please wait...)");
}

function deleteSelectedLeads(form) {
    var checkboxes = form.elements["lead_id"];

    var leadIDs = new Array();

    // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
    if (checkboxes.length != undefined) {
        // There are multiple checkboxes in the form, so it is a NodeList.
        for (var i = 0; i < checkboxes.length; i++) {
            if (checkboxes[i].checked) {
                leadIDs.push(checkboxes[i].value);
            }
        }
    } else {
        // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
        if (checkboxes.checked) {
            leadIDs.push(checkboxes.value);
        }
    }

    var ajax = createAjaxRequest();

    if (ajax && leadIDs.length > 0 && confirm("Do you really want to PERMANENTLY DELETE " + (leadIDs.length == 1 ? "this lead" : "these leads") + "?")) {
        // Apparently this call to "open" must come BEFORE setting the content type header...
        ajax.open("POST", "/leads/delete-selected-leads", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("SUCCESS: Deletions made.");

                    return window.location.reload(true);
                }
                
                alert("ERROR: Deletions failed.");
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        ajax.send("lead_ids=" + leadIDs.toString());
    }
}

function leadEditSaveCallback(button) {
    var form = button.form;

    var due = form.elements["due"].value;

    if (!isMMDDYYY(due)) {
        alert("ERROR: Call Back Date must be in appropriate date format. Please double-check your entries and try again.");
        form.elements["due"].focus();
        return;
    }

    var ajax = createAjaxRequest();

    // Make sure that the "due" date is in proper format.
    if (ajax) {
        // Apparently this call to "open" must come BEFORE setting the content type header...
        ajax.open("POST", "/leads/save-callback", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("Call back info saved...");

                    window.location.reload(true);
                } else {
                    alert("ERROR: A problem occured...");
                }
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        var postData = "id="           + form.elements["id"].value
                     + "&title="       + escape(form.elements["title"].value)
                     + "&lead_id="     + form.elements["lead_id"].value
                     + "&isCallback="  + form.elements["isCallback"].value
                     + "&due="         + escape(due)
                     + "&dueHours="    + form.elements["dueHours"].value
                     + "&dueMinutes="  + form.elements["dueMinutes"].value
                     + "&dueAM="       + (form.elements["dueAM"][0].checked ? "AM" : "PM")
                     + "&description=" + escape(trim(form.elements["description"].value))
                     + "&completed="   + (form.elements["completed"] && form.elements["completed"].checked ? form.elements["completed"].value : "")
                     + "&cancelled="   + (form.elements["cancelled"] && form.elements["cancelled"].checked ? form.elements["cancelled"].value : "");
        
        ajax.send(postData);
    }
}

function leadEditSaveAppointment(button) {
    var form = button.form;

    var due = form.elements["due"].value;

    if (!isMMDDYYY(due)) {
        alert("ERROR: Appointment Date must be in appropriate date format. Please double-check your entries and try again.");
        form.elements["due"].focus();
        return;
    }

    var ajax = createAjaxRequest();

    // Make sure that the "due" date is in proper format.
    if (ajax) {
        // Apparently this call to "open" must come BEFORE setting the content type header...
        ajax.open("POST", "/leads/save-appointment", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("Appointment info saved...");

                    window.location.reload(true);
                } else {
                    alert("ERROR: A problem occured...");
                }
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        var postData = "id="             + form.elements["id"].value
                     + "&title="         + escape(form.elements["title"].value)
                     + "&lead_id="       + form.elements["lead_id"].value
                     + "&isAppointment=" + form.elements["isAppointment"].value
                     + "&due="           + escape(due)
                     + "&dueHours="      + form.elements["dueHours"].value
                     + "&dueMinutes="    + form.elements["dueMinutes"].value
                     + "&dueAM="         + (form.elements["dueAM"][0].checked ? "AM" : "PM")
                     + "&description="   + escape(trim(form.elements["description"].value))
                     + "&completed="     + (form.elements["completed"] && form.elements["completed"].checked ? form.elements["completed"].value : "")
                     + "&cancelled="     + (form.elements["cancelled"] && form.elements["cancelled"].checked ? form.elements["cancelled"].value : "");

        ajax.send(postData);
    }
}

function leadEditOrderSample(leadID) {
    var ajax = createAjaxRequest();

    if (ajax && confirm("Order a sample for this customer?")) {
        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("Sample has been ordered.");

                    window.location.reload(true);
                } else {
                    alert("ERROR: A problem occured...");
                }
            }
        };

        ajax.open("GET", "/leads/order-sample/lead_id/" + leadID, true);

        ajax.send(null);
    }
}

function writeNotesToNotesTable(notes, leadID) {
    var notesList = document.getElementById("notesList");

    var table = document.getElementById("notesListTable");

    if (table) {
        notesList.removeChild(table);
    }

    if (notes.length > 0) {
        // Create a table and tbody to add table rows to.
        var table = document.createElement("table");

        table.setAttribute("id", "notesListTable");
        table.setAttribute("border", 0);
        table.setAttribute("cellspacing", 0);
        table.setAttribute("cellpadding", 0);

        var tbody = document.createElement("tbody");

        var tr, th, td, a;

        // Create and append the header row.
        tr = document.createElement("tr");
        tr.className = "header";
        th = document.createElement("th");
        th.appendChild(document.createTextNode("date"));
        tr.appendChild(th);
        th = document.createElement("th");
        th.appendChild(document.createTextNode("by"));
        tr.appendChild(th);
        th = document.createElement("th");
        th.appendChild(document.createTextNode("note"));
        tr.appendChild(th);
        th = document.createElement("th");
        tr.appendChild(th);
        tbody.appendChild(tr);

        // Create and append the notes.
        for (var i = 0; i < notes.length; i++) {
            tr = document.createElement("tr");

            if (i % 2 == 1) {
                tr.className = "shaded";
            }

            td = document.createElement("td");
            td.appendChild(document.createTextNode(formatDateTime(notes[i].recorded)));
            tr.appendChild(td);
            td = document.createElement("td");
            td.appendChild(document.createTextNode(notes[i].userName));
            tr.appendChild(td);
            td = document.createElement("td");
            td.appendChild(document.createTextNode(notes[i].note));
            tr.appendChild(td);
            td = document.createElement("td");
            a = document.createElement("a");
            a.setAttribute("href", "javascript:leadEditDeleteNote(" + notes[i].id + ", " + leadID + ")");
            a.appendChild(document.createTextNode("Delete"));
            td.appendChild(a);
            tr.appendChild(td);
            tbody.appendChild(tr);
        }

        // Append the tbody to the table and the table to the container..
        table.appendChild(tbody);

        notesList.insertBefore(table, document.getElementById("newNoteFormWrapper"));
    }
}

function leadEditSaveNewNote(button) {
    var note   = button.form.elements["note"];
    var leadID = button.form.elements["lead_id"].value;

    note.value = trim(note.value);

    var ajax = createAjaxRequest();

    if (ajax && note.value.length > 0) {
        // Apparently this call to "open" must come BEFORE setting the content type header...
        ajax.open("POST", "/leads/save-new-note", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var data = eval("(" + this.responseText + ")");

                writeNotesToNotesTable(data, leadID);

                note.value = "";
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        ajax.send("lead_id=" + leadID + "&note=" + escape(note.value));
    }
}

function leadEditDeleteNote(noteID, leadID) {
    var ajax = createAjaxRequest();

    if (ajax && confirm("Are you sure you want to delete this note?")) {
        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var data = eval("(" + this.responseText + ")");

                writeNotesToNotesTable(data, leadID);
            }
        };

        ajax.open("GET", "/leads/delete-note/note_id/" + noteID + "/lead_id/" + leadID, true);

        ajax.send(null);
    }
}

function toggleCompletedCancelled(checkbox) {
    if (checkbox.checked) {
        if (checkbox.form.elements["completed"] !== checkbox) { checkbox.form.elements["completed"].checked = false; }
        if (checkbox.form.elements["cancelled"] !== checkbox) { checkbox.form.elements["cancelled"].checked = false; }
    }
}

function verifyLeadForm(form) {
    var msg = "A required field has been skipped. Please double-check you entries and try again.";

    var required = [
        "name",
        "name_last",
        "address",
        "city",
        "zip",
        "phone",
        "email"
    ];

    for (var i = 0; i < required.length; i++) {
        if (isEmpty(form.elements[required[i]])) {
            form.elements[required[i]].value = "";
            form.elements[required[i]].focus();
            alert(msg);
            return false;
        }
    }

    form.elements["name"].value      = trim(form.elements["name"].value);
    form.elements["name_last"].value = trim(form.elements["name_last"].value);
    form.elements["address"].value   = trim(form.elements["address"].value);
    form.elements["city"].value      = trim(form.elements["city"].value);
    form.elements["zip"].value       = trim(form.elements["zip"].value);
    form.elements["phone"].value     = trim(form.elements["phone"].value);
    form.elements["email"].value     = trim(form.elements["email"].value);

    if (!isZipCodeFormat(form.elements["zip"].value)) {
        form.elements["zip"].focus();
        alert("The entered ZIP code is not in proper format. Please re-enter.");
        return false;
    }

    if (!isPhoneNumberFormat(form.elements["phone"].value)) {
        form.elements["phone"].focus();
        alert("The entered phone number is not in proper format. Please re-enter.");
        return false;
    }
    
    if (form.elements["phone2"].value.length > 0 && !isPhoneNumberFormat(form.elements["phone2"].value)) {
        form.elements["phone2"].focus();
        alert("The entered alternate phone number is not in proper format. Please re-enter (or remove).");
        return false;        
    }

    if (!isEmailFormat(form.elements["email"].value)) {
        form.elements["email"].focus();
        alert("The entered e-mail address is not in proper format. Please re-enter.");
        return false;
    }

    return true;
}

function reportsDeleteSelectedLeads(form) {
    var checkboxes = form.elements["lead_id"];

    var leadIDs = new Array();

    // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
    if (checkboxes.length != undefined) {
        // There are multiple checkboxes in the form, so it is a NodeList.
        for (var i = 0; i < checkboxes.length; i++) {
            if (checkboxes[i].checked) {
                leadIDs.push(checkboxes[i].value);
            }
        }
    } else {
        // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
        if (checkboxes.checked) {
            leadIDs.push(checkboxes.value);
        }
    }

    var ajax = createAjaxRequest();

    if (ajax && leadIDs.length > 0 && confirm("Do you really want to PERMANENTLY DELETE " + (leadIDs.length == 1 ? "this lead" : "these leads") + "?")) {
        // Apparently this call to "open" must come BEFORE setting the content type header...
        ajax.open("POST", "/downline/delete-selected-leads", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("SUCCESS: Deletions made.");

                    window.location.reload(true);
                } else {
                    alert("ERROR: Deletions failed.");
                }
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        ajax.send("lead_ids=" + leadIDs.toString());
    }
}

function reportsAssignLeadsToUser(selectElement) {
    if (selectElement.selectedIndex > 0) {
        var checkboxes = selectElement.form.elements["lead_id"];

        var leadIDs = new Array();

        // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
        if (checkboxes.length != undefined) {
            // There are multiple checkboxes in the form, so it is a NodeList.
            for (var i = 0; i < checkboxes.length; i++) {
                if (checkboxes[i].checked) {
                    leadIDs.push(checkboxes[i].value);
                }
            }
        } else {
            // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
            if (checkboxes.checked) {
                leadIDs.push(checkboxes.value);
            }
        }

        var ajax = createAjaxRequest();

        // Was anything checked?
        if (ajax && leadIDs.length > 0) {
            // Apparently this call to "open" must come BEFORE setting the content type header...
            ajax.open("POST", "/leads/assign-leads-to-user", true);

            ajax.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    if (this.responseText == "success") {
                        alert("SUCCESS: Assignments made.");

                        window.location.reload(true);
                    } else {
                        alert("ERROR: Assignments failed.");
                    }
                }
            };

            // IMPORTANT: It won't go without this header...
            ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            ajax.send(
                "user_id=" + selectElement.options[selectElement.selectedIndex].value
                + "&lead_ids=" + leadIDs.toString()
            );
        }
    }
}

function reportsChangeStatusOfLeads(selectElement) {
    if (selectElement.selectedIndex > 0) {
        var checkboxes = selectElement.form.elements["lead_id"];

        var leadIDs = new Array();

        // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
        if (checkboxes.length != undefined) {
            // There are multiple checkboxes in the form, so it is a NodeList.
            for (var i = 0; i < checkboxes.length; i++) {
                if (checkboxes[i].checked) {
                    leadIDs.push(checkboxes[i].value);
                }
            }
        } else {
            // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
            if (checkboxes.checked) {
                leadIDs.push(checkboxes.value);
            }
        }

        var ajax = createAjaxRequest();

        // Was anything checked?
        if (ajax && leadIDs.length > 0) {
            // Apparently this call to "open" must come BEFORE setting the content type header...
            ajax.open("POST", "/leads/change-lead-statuses", true);

            ajax.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    if (this.responseText == "success") {
                        alert("SUCCESS: Status changes made.");

                        window.location.reload(true);
                    } else {
                        alert("ERROR: Status changes failed.");
                    }
                }
            };

            // IMPORTANT: It won't go without this header...
            ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            ajax.send(
                "status_id=" + selectElement.options[selectElement.selectedIndex].value
                + "&lead_ids=" + leadIDs.toString()
            );
        }
    }
}

function verifyLeadsSearchForm(form) {
    if (form.elements["user_id[]"].selectedIndex < 0) {
        form.elements["user_id[]"].focus();
        alert("You must select at least one user to submit this form.");
        return false;
    }

    form.elements["starting"].value = trim(form.elements["starting"].value);
    form.elements["ending"].value   = trim(form.elements["ending"].value);
    form.elements["customer"].value = trim(form.elements["customer"].value);

    if (form.elements["starting"].value.length > 0 && !isMMDDYYY(form.elements["starting"].value)) {
        form.elements["starting"].focus();
        alert("The entered date is not in proper date format. Please re-enter.");
        return false;
    }

    if (form.elements["ending"].value.length > 0 && !isMMDDYYY(form.elements["ending"].value)) {
        form.elements["ending"].focus();
        alert("The entered date is not in proper date format. Please re-enter.");
        return false;
    }

    return true;
}

function selectAllUsers(checkbox) {
    var options = checkbox.form.elements["user_id[]"].options;

    for (var i = 0; i < options.length; i++) {
        options[i].selected = checkbox.checked;
    }
}

function leadsDeleteSelectedLeads(form) {
    var checkboxes = form.elements["lead_id"];

    var leadIDs = new Array();

    // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
    if (checkboxes.length != undefined) {
        // There are multiple checkboxes in the form, so it is a NodeList.
        for (var i = 0; i < checkboxes.length; i++) {
            if (checkboxes[i].checked) {
                leadIDs.push(checkboxes[i].value);
            }
        }
    } else {
        // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
        if (checkboxes.checked) {
            leadIDs.push(checkboxes.value);
        }
    }

    var ajax = createAjaxRequest();

    if (ajax && leadIDs.length > 0 && confirm("Do you really want to PERMANENTLY DELETE " + (leadIDs.length == 1 ? "this lead" : "these leads") + "?")) {
        // Apparently this call to "open" must come BEFORE setting the content type header...
        ajax.open("POST", "/downline/delete-selected-leads", true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("SUCCESS: Deletions made.");

                    window.location.reload(true);
                } else {
                    alert("ERROR: Deletions failed.");
                }
            }
        };

        // IMPORTANT: It won't go without this header...
        ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        ajax.send("lead_ids=" + leadIDs.toString());
    }
}

function leadsAssignLeadsToUser(selectElement) {
    if (selectElement.selectedIndex > 0) {
        var checkboxes = selectElement.form.elements["lead_id"];

        var leadIDs = new Array();

        // Is "checkboxes" a NodeList or just a single Element. (NOTE: Single Elements do NOT have a length...)
        if (checkboxes.length != undefined) {
            // There are multiple checkboxes in the form, so it is a NodeList.
            for (var i = 0; i < checkboxes.length; i++) {
                if (checkboxes[i].checked) {
                    leadIDs.push(checkboxes[i].value);
                }
            }
        } else {
            // There is only ONE checkbox in the form, so it is NOT a NodeList. It's just an Element.
            if (checkboxes.checked) {
                leadIDs.push(checkboxes.value);
            }
        }

        var ajax = createAjaxRequest();

        // Was anything checked?
        if (ajax && leadIDs.length > 0) {
            // Apparently this call to "open" must come BEFORE setting the content type header...
            ajax.open("POST", "/leads/assign-leads-to-user", true);

            ajax.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    if (this.responseText == "success") {
                        alert("SUCCESS: Assignments made.");

                        window.location.reload(true);
                    } else {
                        alert("ERROR: Assignments failed.");
                    }
                }
            };

            // IMPORTANT: It won't go without this header...
            ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            ajax.send(
                "user_id=" + selectElement.options[selectElement.selectedIndex].value
                + "&lead_ids=" + leadIDs.toString()
            );
        }
    }
}

function leadsShowLeadNotes(leadID) {
    var wrapper = jQuery("#notes_" + leadID);
    var target  = jQuery("#notes_" + leadID + "_target");

    wrapper.addClass("active");

    jQuery.getJSON(
        "/downline/fetch-lead-notes",
        { "id" : leadID },
        function(notes) {
            if (notes.length && notes.length > 0) {
                target.empty();

                for (var i = 0; i < notes.length; i++) {
                    target.append("<div class=\"note\"><div class=\"date\">" + notes[i].recorded + "</div><div class=\"text\">" + notes[i].note + "</div></div>");
                }
            } else {
                target.text("(No notes found...)");
            }
        }
    );
}

function leadsHideLeadNotes(leadID) {
    var wrapper = jQuery("#notes_" + leadID);
    var target  = jQuery("#notes_" + leadID + "_target");

    wrapper.removeClass("active");

    target.empty();
    target.text("(Please wait...)");
}

function collapseAll(parentID) {
    var parent = document.getElementById(parentID);

    var divs = parent.getElementsByTagName("div");

    for (var i = 0; i < divs.length; i++) {
        if (/depth_\d active/.test(divs[i].className)) {
            divs[i].className = divs[i].className.replace(/\s*active/, "");
        }
    }
}

function toggleChildren(parentID) {
    var parent = document.getElementById(parentID);

    var parentDepth = parseInt(parent.className.replace(/^depth_(\d).*$/, "$1"));

    var rx = new RegExp("depth_" + (parentDepth + 1));

    var divs = parent.getElementsByTagName("div");

    for (var i = 0; i < divs.length; i++) {
        if (rx.test(divs[i].className)) {
            if (/active/.test(divs[i].className)) {
                collapseAll(parentID);

                break;
            } else {
                divs[i].className = "depth_" + (parentDepth + 1) + " active";
            }
        }
    }
}

function deactivateUser(userID) {
    var ajax = createAjaxRequest();

    if (
        ajax
            &&
        confirm("Are you sure you want to delete this user?")
            &&
        confirm("Have you re-assigned any downline this user may have to new managers?")
    ) {
        ajax.open("GET", "/hierarchy/deactivate/id/" + userID, true);

        ajax.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                if (this.responseText == "success") {
                    alert("User has been de-activated.");

                    window.location.reload(true);

                    return;
                }

                alert("ERROR. Failed to write to database.");
            }
        }

        ajax.send(null);
    }
}

function sourceDelete(sourceID) {
    if (confirm("Are you sure you want to delete this advertising source entry?")) {
        jQuery.get(
            "/ads/source-delete",
            { "id" : sourceID },
            function() {
                window.location.reload(true);
            }
        );
    }
}

function verifySourceForm(form) {
    form.elements["name"].value = trim(form.elements["name"].value);

    if (form.elements["name"].value.length == 0) {
        alert("\"Name\" is a required field. Please double check your entries and try again.");
        form.elements["name"].focus();
        return false;
    }

    form.elements["label"].value = trim(form.elements["label"].value);

    if (form.elements["label"].value.length == 0) {
        alert("\"Label\" is a required field. Please double check your entries and try again.");
        form.elements["label"].focus();
        return false;
    }

    return true;
}

function isUniqueSourceName(textInput, originalName) {
    var newName = trim(textInput.value);

    if (newName.toLowerCase() != originalName.toLowerCase()) {
        jQuery.getJSON(
            "/ads/is-unique-source-name",
            { "name" : newName },
            function(isInUse) {
                if (isInUse == "true") {
                    alert("ERROR: Name already in use. Please choose a different name.");

                    textInput.value = originalName;

                    textInput.focus();
                }
            }
        );
    }
}

function inactivityTimeout() {
    // Redirects the browser to the "logout" page. (Logs the user out and displays a message.)
    window.location.href = "/index/logout/message/timeout";
}

jQuery(document).ready(function() {
    // Start the "timeout" counter. (Times out in 12 hours.)
    /**
     * Commented out by --Geo, 18 Jan 2012
     */
    // window.setTimeout(inactivityTimeout, 12 * 60 * 60 * 1000);
    
    var currentDate = jQuery("#currentDate");
    
    if (currentDate.length > 0) {
        var now = new Date();
        
        currentDate.text(dayNames[now.getDay()] + ", " + monthNames[now.getMonth()] + " " + now.getDate() + ", " + now.getFullYear());
        
        currentDate.removeClass("none");
    }
    
    var dueDatepicker         = jQuery("#dueDatepicker");
    var callbackDatepicker    = jQuery("#callbackDatepicker");
    var appointmentDatepicker = jQuery("#appointmentDatepicker");
    var startingDatepicker    = jQuery("#startingDatepicker");
    var endingDatepicker      = jQuery("#endingDatepicker");
    
    if (dueDatepicker.length > 0)         { dueDatepicker.datepicker();         }
    if (callbackDatepicker.length > 0)    { callbackDatepicker.datepicker();    }
    if (appointmentDatepicker.length > 0) { appointmentDatepicker.datepicker(); }
    if (startingDatepicker.length > 0)    { startingDatepicker.datepicker();    }
    if (endingDatepicker.length > 0)      { endingDatepicker.datepicker();      }
});

