/**
 * Application wide JavaScript File
 *
 * Please adhere to the layout!
 *
 * This file is divided into the following sections:
 * 1) Generic code
 * 2) Module specific code
 * 3) Generic code
 * 4) jQuery plugin declarations
 *
 * The module specific code should be ordered alphabetically by module.
 *
 * Please prefix new modules with a comment block similar in style to the
 * existing ones.
 */
 
 
/**
 * Generic Code
 *
 * @author Matt
 */
$(document).ready(function () {
    jQuery.ajaxSetup({
    	cache: false,
        dataType: 'json',
        error: function () {
            alert("Request was not successful. Please try again shortly.");
        }
    });

    // This handler is automatically excuted after every AJAX response, unless
    // the specific AJAX request has disabled global events as a jQuery AJAX
    // option. For this to work as expected the AJAX response should adhere to
    // the following layout. 'action' can be either "inside", "instead", or any
    // jQuery method ("after", "before", "prepend", "append", etc)
    /*
        {
            version: 1,
            elements: [{
                target: '#a jquery > .selector',
                action: 'inside',
                data: '<h2>Some</h2><p>HTML</p>'
            },{
                target: '#another-jquery-selector',
                action: 'instead',
                data: '<h2>Some</h2><p>More HTML</p>'
            },...]
        }
    */
    $(document).ajaxSuccess(function (e, xhr, settings) {
        var response = xhr.responseText;

        // A simple check to make sure we aren't dealing with another
        // response format by accident.
        if (settings.dataType != 'json') {
            return;
        };

        // Make sure we have valid JSON
        try {
            response = jQuery.parseJSON(response);
        } catch (e) {
        	alert(e);
            return;
        }

        // Check to make sure that the response object has an elements
        // property, and that it is an array.
        if (response.elements instanceof Array) {
            // These are the required attributes for each element of the
            // array.
            var reqs = ['target', 'action'];
            var valid = true;

            // For each element we want to add, we first validate it to make
            // it contains the valid attributes, and that they are in the
            // required format (strings). If the element passes these tests
            // we add it to the DOM
            for (var i=0;i<response.elements.length;i++) {
                var cur = response.elements[i];
                var sel;

                // Check that it contains all the required attributes, and
                // that these are of the correct type.
                for (var j=0;j<reqs.length;j++) {
                    if (typeof cur[reqs[j]] !== "string") {
                        valid = false;
                        break;
                    };
                };

                if (!valid) {
                    continue;
                };
                
                sel = $(cur.target);

                // Add the element to the DOM. For the default case, we
                // first make sure jQuery supports the operation provided
                switch (cur.action) {
                    case "inside":
                        sel.html(cur.data);
                    break;
                    case "instead":
                        sel.replaceWith(cur.data);
                    break;
                    case "remove":
                        sel.remove();
                    break;
                    case "refreshPage":
                    	window.location.reload();
                   	break;
                   	case "redirect":
                    	window.location = cur.data;
                    default:
                        if (typeof sel[cur.action] === "function") {
                            sel[cur.action](cur.data);
                        }; // else continue
                    break;
                };
            };
        };
        
        // Only do all this if we actually have some notifications to add        
        if (response.notifications instanceof Array) {
            // If "type" isn't specified for a notification, assume it is this
            // type
            var defaultNotificationType = "error";
            var notificationContainer = $('#notifications');
            
            if (!notificationContainer.size()) {
                notificationContainer = $('<div id="notifications"></div>');
                notificationContainer.prependTo('#center-column');
            };
            
            for (var i=0;i<response.notifications.length;i++) {
                var cur = response.notifications[i];
                
                switch (typeof cur) {
                    case "object":
                    break;
                    case "string":
                        cur = {
                            message: cur
                        };
                    break;
                    default:
                        continue;
                    break;
                };
                
                if (!cur.hasOwnProperty("type")) {
                    cur.type = defaultNotificationType;
                };
                
                notificationContainer.append($('<div class="' + cur.type + '">' + cur.message + '</div>'));
            };
        };        
    });

    // TinyMce
    tinyMCE.init({
        mode: 'specific_textareas',
        editor_selector: 'tiny_mce',
        plugins : "paste",
        width:500,
        height:200,
        theme : "advanced",
        theme_advanced_toolbar_align : "left",
        theme_advanced_toolbar_location : 'top',
        theme_advanced_buttons1 : 'bold,underline,|,indent,outdent,|,removeformat,|,bullist,numlist,|,fontsizeselect',
        theme_advanced_buttons2: '',
        theme_advanced_buttons3: '',
        theme_advanced_font_sizes : "Small=1em,Medium=1.2em,Large=1.5em"
    });	

    // Dialog close button.
    $(".close-modal-window").live('click', function(event) {
        $(this).closest('.modal-dialog').fadeOut(100);

        event.preventDefault();
    });
    
    // Dialog close button w/o formatting attached
    $(".close-modal-window-clean").live('click', function(event) {
        $(this).closest('.modal-dialog').fadeOut(100);

        event.preventDefault();
    });

    // Add default behaviour for links that trigger dialogs
    $('.show-modal-dialog').live('click', function (event) {
        var self = $(this);
        var target = this.rel || this.href.slice(this.href.indexOf("#") + 1);

        $('#' + target).showDialog();

        event.preventDefault();
    });
    
    
    //Close modal
    $(".modal-close-window").click(function(event) {
        $(this).closest('.modal-dialog').fadeOut(100);
        
        event.preventDefault();
    });	

    // Default autoclear functionality on textareas and input fields
    // To use, set a class of "autoclear", and set the "title" attribute to the
    // default value.
    $('input:text.autoclear,textarea.autoclear').autoclear();

    // Explanations for input fields. Add a class of "has_explanation" to the
    // input field, and have a sibling with the class of "form_explanation"
    $("input.has_explanation").live('focus blur', function (event) {
        $(this).siblings('.form_explanation').toggle(event.type === 'focusin');
    });

    // Date Pickers
    Date.format = 'mm/dd/yyyy';
    $('.date-pick').datePicker();

    // AJAX submission of forms. Add a class of "ajaxify" to the form in
    // question, and ensure the form's action and method attributes are where
    // and how you want the AJAX request to be directed. The response must be
    // JSON, adhering to the generic content replacing format (version 1)
    $('form.ajaxify').ajaxify();
});

/**
 * Job Posting System: Application Requirements
 *
 * @author Matt
 */
$(document).ready(function () {
    // Helper function which returns all the input fields which are used
    // to insert requirements
    function getRequirementInputs () {
        return $('#reqs_row > input:text');
    };

    // Hide all the inputs which do not have a value at the start, excluding the
    // first input. We use a function as the filter instead of the selector
    // "[value=]" because we use autoclear, and the helper text doesn't match
    // the selector.
    getRequirementInputs().filter(function (i) {
        return (i > 0 && $(this).val() == "");
    }).hide();

    // Used to add a new requirement. Find the first hidden one, and show it.
    $('#pnj_add_requirement').bind('click', function (event) {
        getRequirementInputs().filter(':hidden').
                               first().
                               css('display', 'block');
       
        getRequirementInputs().filter(':visible').last().focus();

        event.preventDefault();
    });
    
    $("input[name*='req']").keydown(function(event) {
    	  if (event.keyCode == '13') {
     	     event.preventDefault();
    	        
    	     getRequirementInputs().filter(':hidden').
             first().
             css('display', 'block');
    	     
    	     getRequirementInputs().filter(':visible').last().focus();

    	   }
    	});

    
    
    

    // Used to remove a requirement. Find the last visible one and hide it, but
    // only if it isn't the first one.
    $('#pnj_remove_requirement').bind('click', function (event) {
        getRequirementInputs().filter(':gt(0):visible').
                               last().
                               val('').
                               hide();

        event.preventDefault();
    });
});

/**
 * Job Posting System: College Targeting System
 *
 * @author Matt
 */
$(document).ready(function () {
    // Keep a reference to an open AJAX requests, so that if the user initiates
    // another one whilst it is in progress, it can be cancelled
    // (using abortOpenAjaxRequests())
    var ajaxRequest;
    // Cache the responses received from the server, to prevent useless lookups
    var cache = {

        };

    /**
     * Used to abort any AJAX requests that were opened by the college targeting
     * system. It is intented that this function is called by the autocomplete
     * functionality before another AJAX request is opened by it.
     *
     * @author Matt
     */
    function abortOpenAjaxRequests () {
        if (ajaxRequest instanceof Object
            && typeof ajaxRequest.abort === "function") {

            ajaxRequest.abort();
            ajaxRequest = undefined;
        };
    };

    /**
     * Appends the details of parameter to the college targeting list. The
     * provided item can be a city, state, region or "all".
     *
     * @author Matt
     * @param sel   Object  type:   college/ city/ state/ all
     *                      label:  college name/ city name/ state name etc
     *                      id:     identifer that is unique to the item within
     *                              that type
     */
    function appendToCollegeList (sel) {
        var id = sel.type + '_' + sel.id;
        var desc = sel.label;

        switch (sel.type) {
            case "city":
                desc = 'All colleges in the city of ' + '<strong>' + sel.label + '</strong>';
            break;
            case "state":
                desc = 'All colleges in the state of ' + '<strong>' + sel.label + '</strong>';
            break;
            case "all":
                desc = 'All colleges on Jobzle';
            break;
            case "college":
                desc =  '<strong>' + sel.label + '</strong>';
            break;
        };

        var checkbox = '<input type="checkbox" name="targets[' + sel.type + '][]" id="' + id + '" value="' + sel.id + '" checked/>';
        var label = '<span for="' + id + '">' + desc + '</span>';
        var remove = '<a class="delete_button">(remove)</a>';

        $('#target_colleges_list').append('<div>' + checkbox + ' ' + label + ' ' + remove + '</div>');
        $('#no_colleges_yet_label').hide();
        $('#colleges_targeted_label').show();
        $('#default_all_target_holder').html("");
        $('#college_counter').val(parseInt($('#college_counter').val()) + 1);
    };

    // Actual autocomplete functionality for the text input
    $('#target_colleges_input').autocomplete({
        minLength: 2,
        // source is called with input equalling the user input. source should
        // pass an array to the callback parameter, with the array containing
        // relevant suggestions to the user input
        source: function (input, callback) {
            input = input.term;

            // input variable is now the exact string that is contained with the
            // text box.

            var type = $('#target_colleges_select').val();
            var cacheKey = type + '_' + input;

            // We must prefix the input with the type to cache it, because
            // otherwise we'll be mixing responses with cities, colleges, etc.

            // Cancel any existing AJAX requests.
            abortOpenAjaxRequests();

            // If the cacheKey exists, we have already got a response for this
            // request, so no need to make another AJAX request.
            //TODO: Caching isn't actually implemented here, just some theoretical code from matt
            //if (cache.hasOwnProperty(cacheKey)) {
              //  response(cache[cacheKey]);
            //} else {
                ajaxRequest = jQuery.ajax({
                    url: '/index.php/search/' + type + '_ajax/',
                    dataType: 'json',
                    type: 'post',
                    data: {
                        q: input
                    },
                    success: function (data) {
                        cache[cacheKey] = data;

                        // We need to store the type of the item within each
                        // item so that the appendToCollegeList function can
                        // read it
                        for (var i=0;i<data.length;i++) {
                            data[i].type = type;
                        };

                        callback(data);
                    },
                    error: function () {
                        callback([]);
                    }
                });
            //};
        },
        // select is called when the user selects an suggestion from the drop
        // down list. event is the event, and ui (or more specifically ui.item),
        // is a reference to the items corresponding array key that we
        // originally passed in the source function
        select: function (event, ui) {
            appendToCollegeList(ui.item);

            $('#target_colleges_input').val('');
            $('#target_colleges_input').focus();

            event.preventDefault();
        }
    });

    // When the user changes the select drop down, cancel any existing AJAX
    // requests and set the input field blank. Toggle the visiblity of the user
    // input depending on whether "all" is now selected. If all is now selected,
    // we immediately add the "All colleges" text to the #target_colleges_list.
    $('#target_colleges_select').bind('change', function () {
        var isAll = $(this).val() == "all";

        abortOpenAjaxRequests();

        $('#target_colleges_input').toggle(!isAll).val('');

        if (isAll) {
            appendToCollegeList({
                type: 'all',
                id: 'all',
                label: 'All Colleges'
            });
        };
    });

    // Listen for any clicks of the "delete" images, and delete the relevant
    // option
    $('#target_colleges_list').delegate('.delete_button', 'click', function () {
        $(this).parent().remove();
        
        //Decrement the college counter, and if it has reached zero, switch back to the "no colleges choosen" view
        $('#college_counter').val(parseInt($('#college_counter').val()) - 1);
        if($('#college_counter').val() == 0) {
        	$('#no_colleges_yet_label').show();
        	$('#colleges_targeted_label').hide();
        	$('#default_all_target_holder').html('<input type="hidden" name="targets[all][]" id="all" value="all" />');
        }
    });
});

/**
 * Job Posting System: Date picking functionality
 *
 * @author Matt
 */
$(document).ready(function () {
    // The datepicker plugin we use does not use val() to set the input value
    // when a new date is set. Because of this, the autoclear plugin does not
    // update the classes and data automatically. We therefore reset the value
    // using val when a date is selected, so autoclear can do its thing.
    $('#date').bind('dateSelected', function (event, date, td, status) {
        // This is not a noop. I promise you.
        $(this).val(this.value);
    });
    
    //This one is for the jobhistory creator in the profile view
    $('#history_enddate').bind('dateSelected', function (event, date, td, status) {
        // This is not a noop. I promise you.
        $(this).val(this.value);
    });
});

/**
 * Job Posting System: Login functionality
 *
 * @author Evan
 */
 /*
function loginPostNewJob(name, email) {
	//This function gets called when a user logs in, and if possible should be make specific to the case that they are viewing the post new job view
	$('#pnj-sign-in-div').hide();
	$('#pnj-password-div').hide();
	$('#pnj-contact-name').val(name);
	$('#pnj-contact-email').val(email);
}*/

/**
 * Job Posting System: Map functionality
 *
 * @author Matt
 */
$(document).ready(function () {
    
    
    /**
     * Show the loading screen within the modal dialog
     *
     * @author Matt
     * @param input String  The location that is currently being searched for
     */
    function showMapLoading (input) {
        $('#location-form-modal-window').showDialog();
        $('#location_form_loading').show();
        $('#location_modal_input').val(input);
    };

    /**
     * Show an error within the modal dialog
     *
     * @author Matt
     * @param input String  The location that is currently being searched for
     * @param msg   String  The error message that should be displayed
     */
    function showMapError (input, msg) {
        $('#location-form-modal-window').showDialog();
        $('#location_form_errorReport').show().text(msg);
        $('#location_modal_input').val(input);
        $('#map').hide();
    };

    /**
     * Show a map in the modal dialog
     *
     * @author Matt
     * @param input String  The location that is currently being searched for
     * @param results Array An array of results that should be pinned onto the
     *                      map
     */
    function showMapResult (input, results) {
        $('#location-form-modal-window').showDialog();
        $('#location_modal_input').val(input);
        $('#map').show();

        var map = new google.maps.Map(document.getElementById('map'), {
                zoom: 14,
                center: results[0].geometry.location,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });

        for (var i=0; i<results.length; i++) {
            new google.maps.Marker({
                map: map,
                position: results[i].geometry.location
            });
        };
    };
    
    /**
     * Helper function to set the latitude and longitude inputs with the 
     * new values.
     *
     * @author Matt
     * @param lat   Number  Latitude value
     * @param lng   Number  Longitude value
     */    
    function setLatLng (lat, lng) {
        $('#png_location_lat').val(lat);
        $('#png_location_lng').val(lng);    
    };
    
    /**
     * Function which is bound to the update buttons click events.
     *
     * @author Matt
     * @param event Object  Event object
     */     
    function updateMap (event) {
        // Cache
        var self = $(this);
        // The text input which contains the value to update is the previous
        // element
        var input = self.prev().val();

        // If there is no input, don't bother updating the location
        if (!input.length) {
            return;
        };

        showMapLoading(input);
        getLocation(input, function (success, results) {
            if (success) {
                var firstRes = results[0];
                var addressComponents = firstRes.address_components;
                var cityComponent;
                var stateComponent;
                var i=0;
                for(i=0; i<addressComponents.length; i++) {
                	if(addressComponents[i].types[0] == "administrative_area_level_1") {
                		stateComponent = addressComponents[i].short_name;
                	}
                	if(addressComponents[i].types[0] == "locality") {
                		cityComponent = addressComponents[i].short_name;
                	}
                }
                var resultLocation = 0;
                if(cityComponent && stateComponent) {
                	resultLocation = cityComponent + ", " + stateComponent;
                }
                if(stateComponent && !cityComponent) {
                	resultLocation = stateComponent;
                }
                $('#rev_geolocation').val(resultLocation);
                var firstResLoc = firstRes.geometry.location;
                
                showMapResult(input, [firstRes]);
                setLatLng(firstResLoc.lat(), firstResLoc.lng());
            } else {
                showMapError(input, "The location you entered cannot be mapped");
				
                setLatLng(0, 0);
            };
        });

        $('#pnj_location_field').val(input);

        event.preventDefault();
    };
    
    // Inside the modal window, when the user clicks the update button, refresh
    // the map.
    $('#location_update_button').bind('click', updateMap);
    
    // We have a blur event bound to the input field so that if the user blurs
    // the input without clicking Map it, we can still retrieve the latlng for
    // the entered value. However, if the user blurs the input to click Map it,
    // we now get two requests firing off. So we delay the blur event slightly,
    // and then cancel it here if the user did indeed click Map It. Hacky, but
    // the only way.
    $('#location_check_button').bind('click', function (event) {
        var input = $('#pnj_location_field');
        var data = input.data('timeout');
        
        $('#location_hidden_field').val($('#pnj_location_field').val());

        if (data) {
            clearTimeout(data);
            input.removeData('timeout');
        };
    }).bind('click', updateMap);
    
    $('.location-check-cancel').bind('click', function (event) {
    	$('#pnj_location_field').val($('#location_hidden_field').val());
    });

    // We have a blur event bound to the input field so that if the user blurs
    // the input without clicking Map it, we can still retrieve the latlng for
    // the entered value. However, if the user blurs the input to click Map it,
    // we now get two requests firing off. So we delay the blur event slightly,
    // and then cancel it in the Map it click handler if the user did indeed 
    // click Map It. Hacky, but the only way.
    $('#pnj_location_field').bind('blur', function () {
        var input = this.value;
        
        $(this).data('timeout', setTimeout(function () {
            if (!input.length) {
                return;
            };
            
            getLocation(input, function (success, results) {
                if (success) {
                    var firstRes = results[0];
					var addressComponents = firstRes.address_components;
					var cityComponent;
					var stateComponent;
					var i=0;
					for(i=0; i<addressComponents.length; i++) {
						if(addressComponents[i].types[0] == "administrative_area_level_1") {
							stateComponent = addressComponents[i].short_name;
						}
						if(addressComponents[i].types[0] == "locality") {
							cityComponent = addressComponents[i].short_name;
						}
					}
					var resultLocation = 0;
					if(cityComponent && stateComponent) {
						resultLocation = cityComponent + ", " + stateComponent;
					}
					if(stateComponent && !cityComponent) {
						resultLocation = stateComponent;
					}
					$('#rev_geolocation').val(resultLocation);
					var firstResLoc = firstRes.geometry.location;
					
					setLatLng(firstResLoc.lat(), firstResLoc.lng());
                } else {
                    setLatLng(0, 0);
                };
            });        
        }, 100));
    });
});

function allOrNone(type){
	if(type == 1) 
	{
		$('input[name*="industrytype"]').attr('checked', true);
 	}
 	else
 	{
 		$('input[name*="industrytype"]').attr('checked', false);
 		event.preventDefault();
 	}

}


/**
 * Messaging System
 *
 * @author Matt
 */
$(document).ready(function () {
    function checkAllThreads() {
        $('input[name=threads\[\]]').attr('checked', true);
    };

    function uncheckAllThreads() {
        $('input[name=threads\[\]]').attr('checked', false);
    };

    $('#check_all_threads').bind('click', function (event) {
        checkAllThreads();

        event.preventDefault();
    });

    $('#uncheck_all_threads').bind('click', function (event) {
        uncheckAllThreads();

        event.preventDefault();
    });

    $('#check_all_read_threads').bind('click', function (event) {
        uncheckAllThreads();

        $('.thread-read').find('input[name=threads\[\]]').
                             attr('checked', true);

        event.preventDefault();
    });

    $('#check_all_unread_threads').bind('click', function (event) {
        uncheckAllThreads();

        $('.thread-unread').find('input[name=threads\[\]]').
                               attr('checked', true);

        event.preventDefault();
    });
});

/**
 * Profile System
 *
 * @author Evan
 */ 
$(document).ready(function () {
	Date.format = 'mm/dd/yyyy';
	$('.profile-date-pick').datePicker(
		{
			startDate: '01/01/1970',
			endDate: (new Date()).asString()
		}
	);

	$('#current_job_check').bind('click', function (event) {
		if($('#current_job_check').attr('checked')) {
			$('#history_ending_div').hide();
			$('#to_present').show();
			$('#history_enddate').val('');
			$('#no_end_date').val('1');
		}
		else {
			$('#history_ending_div').show();
			$('#to_present').hide();
			$('#no_end_date').val('0');
		}
	});

});

function moveOnMax(field,nextFieldID){
  if(field.value.length >= field.maxLength){
	document.getElementById(nextFieldID).focus();
  }
}
	
/**
 * Search System
 *
 * @author Evan
 */ 

$(document).ready(function () {

 	var ajaxRequest;
    // Cache the responses received from the server, to prevent useless lookups
    var cache = {

        };

    /**
     * Used to abort any AJAX requests that were opened by the college targeting
     * system. It is intented that this function is called by the autocomplete
     * functionality before another AJAX request is opened by it.
     *
     * @author Matt
     */
    function abortOpenAjaxRequests () {
        if (ajaxRequest instanceof Object
            && typeof ajaxRequest.abort === "function") {

            ajaxRequest.abort();
            ajaxRequest = undefined;
        };
    };

	//This handles the autocomplete case for the trial college picker in the search_sign_in_view
	$('#trial_college_select').autocomplete({
        minLength: 3,
        // source is called with input equalling the user input. source should
        // pass an array to the callback parameter, with the array containing
        // relevant suggestions to the user input
        source: function (input, callback) {
            input = input.term;

            //Type is just college, since this is only the trial college picker

            var type = 'college';
            var cacheKey = 'college_' + input;
            
            // Cancel any existing AJAX requests.
            abortOpenAjaxRequests();

            // If the cacheKey exists, we have already got a response for this
            // request, so no need to make another AJAX request.
            if (cache.hasOwnProperty(cacheKey)) {
                response(cache[cacheKey]);
            } else {
                ajaxRequest = jQuery.ajax({
                    url: '/index.php/search/' + type + '_ajax/',
                    dataType: 'json',
                    type: 'post',
                    data: {
                        q: input
                    },
                    success: function (data) {
                        cache[cacheKey] = data;

                        // We need to store the type of the item within each
                        // item so that the appendToCollegeList function can
                        // read it
                        for (var i=0;i<data.length;i++) {
                            data[i].type = type;
                        };

                        callback(data);
                    },
                    error: function () {
                        callback([]);
                    }
                });
            };
        },
        // select is called when the user selects an suggestion from the drop
        // down list. event is the event, and ui (or more specifically ui.item),
        // is a reference to the items corresponding array key that we
        // originally passed in the source function
        select: function (event, ui) {
        	setTrialCollege(ui.item);
        	
            event.preventDefault();
        }
    });
    
    function setTrialCollege(sel) {
    	$('#trial_college_select').val(sel.label);
    }

});

//These functions had to be moved out of the onready chunk since they are to be called externally, by register.js

//This helper function is used to convert from the radians in the db to degrees used by google maps API
function radToDeg(radians) {
	var degrees = (radians/(Math.PI*2))*360;
	return degrees;
}

//This function is called after refine search to update the map.
function makeResultsMap(resultJobs){
		deleteOverlays();
		var firstInc = -1;
		var i=0;
		
		for(i=0; i<resultJobs.length; i++) {
			if(resultJobs[i].locationlat != 0 && resultJobs[i].locationlng != 0) {
				firstInc = i;
				break;
			}
		}
		if (firstInc == -1) {
			$("#results_map").hide();
		} 
		else {
			var latlng = new google.maps.LatLng(radToDeg(resultJobs[firstInc].locationlat),radToDeg(resultJobs[firstInc].locationlng));
			
			var latlngbounds = new google.maps.LatLngBounds(latlng, latlng);
			
			var mappableResults = 0;
			
			if(resultJobs.length > 1) {
			for(i=0; i<resultJobs.length; i++) {
				if (resultJobs[i].locationlat != 0 && resultJobs[i].locationlng != 0)	{
					//The point of adding the smallishRand is to enlarge the field of view when nearby jobs are selected.
					var smallishRand = 0.0008;
					var thislatlng = new google.maps.LatLng(parseFloat(radToDeg(resultJobs[i].locationlat))+smallishRand, parseFloat(radToDeg(resultJobs[i].locationlng))+smallishRand);
					latlngbounds.extend(thislatlng);
					mappableResults++;
				} 
			}
			}
			
			var myOptions = {
			  zoom: 15,
			  center: latlng,
			  mapTypeId: google.maps.MapTypeId.ROADMAP,
			  mapTypeControl: false
			}
			var map = new google.maps.Map(document.getElementById("results_map"),myOptions);
			if(resultJobs.length > 1 && mappableResults > 1) {
			map.fitBounds(latlngbounds);
			}
			
			var letters = Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'); 
			var inc = 0;
			var i = 0;
			var innerCount = 0;
			for(i=0; i<resultJobs.length; i++) { 
				if (resultJobs[i].locationlat != 0 && resultJobs[i].locationlng != 0)	{
					var smallRand = Math.random() * 0.0005;
					var marker = new google.maps.Marker({
					  map: map,
					  position: new google.maps.LatLng(parseFloat(radToDeg(resultJobs[i].locationlat))+smallRand, parseFloat(radToDeg(resultJobs[i].locationlng))+smallRand),
					  icon: 'http://www.google.com/mapfiles/marker'+letters[innerCount]+'.png'
					});
					markersArray.push(marker);
					innerCount++;
					//alert(resultJobs[i].id);
					addPreview(resultJobs[i].id,marker);

				} 
			}
		}
}

function addPreview(id,marker){
	google.maps.event.addListener ( marker, 'mouseover', function() 
	{	
		//alert('hello' + '<?php echo $letters[$temp]; ?>' );
		createPreviewDiv(id);
	});
	
	google.maps.event.addListener ( marker, 'mouseout', function() 
	{	
		//alert('hello' + '<?php echo $letters[$temp]; ?>' );
		removePreviewDiv();
	});
	
	google.maps.event.addListener ( marker, 'click', function() 
	{	
		gotoJob(id);
	});
}



function deleteOverlays() {
  if (markersArray) {
    for (i in markersArray) {
      markersArray[i].setMap(null);
    }
    markersArray.length = 0;
  }
}

//Called externally by register.js
function getLatLngFromLocation(dataObj) {
	var input = dataObj['distanceCenter'];
	
	getLocationRefineSearch(dataObj, input, function (success, results) {
		if (success) {
			var firstRes = results[0];
			var firstResLoc = firstRes.geometry.location;
			
			dataObj['distanceCenterLat'] = firstResLoc.lat(); 
			dataObj['distanceCenterLng'] = firstResLoc.lng();
			//return latlng;
			
			doLatLngRefineAjax(dataObj);
		} else {
			//error achieved!
			latlng = 0;
		};
	});
}

function doLatLngRefineAjax(dataObj) {
	
   $.ajax({
     type: "POST",
     url: "/index.php/search/ajaxRefineSearch",
     dataType: "json",
     data: dataObj,
     success: function (result, stat, xhr) {
        //$("#result").html("Success: " + stat + ", result text is: " + result.text + " heading to: " + result.destination);
         if (result.success) {
		   	document.getElementById('results_section').innerHTML = result.resultsview;
		   	makeResultsMap(result.resultjobs);
		 }
       },
     error: function (xhr, stat, err) {
	 alert("error! " + stat + " Error: " + err + " xhr: " + xhr);
       },
     complete: function (xhr, stat) {
      }
     });
}


/**
 * Function to change job close question fields
 *
 */
function showField(){

	if($('#reason').val() == 1){
		$('#who').show();
		$('#why').hide();
		}
	else if($('#reason').val() == 4){
		$('#who').hide();
		$('#why').show();
		}
	else{
		$('#who').hide();
		$('#why').hide();
	}
		
	
}


// open send message modal widow and load receiver
function sendNewMessage () {
	//TODO: check why the value needs to be changed twice in order for it to work.
	$('input#receiver').val($('#user_id').val());	
	$('#send-message-modal-window').showDialog();
	$('input#receiver').val($('#user_id').val());
}

//Function to make tr's 
$(document).ready(function () {
	$('tr.item').bind('click', function() {
	window.location = $(this).attr('rel');
	});
	
	$("input[name=threads\\[\\]]").click(function(e) {
	        e.stopPropagation();
	   });
	   
	$(".stop-prop").click(function(e) {
	        e.stopPropagation();
	   });
	
	//Walker's code for Zebra striped tables
	$(".zebra-list tr:nth-child(odd)").addClass("zebra-color");

	//Walker's code for layering job analytics
	$(".job-analytics-list div:nth-child(odd)").addClass("right-align-child");

});


///Message sorting functions
$(document).ready(function () {
    $(".sort-arrow").hide();
});

$(document).ready(setupSorting);

function sort(by,url){
	
	if($('#sort-by').val() == by)
	{
		if($('#sort-order').val() == 'desc'){
			$('#sort-order').val('asc');
		}
		else
		{
			$('#sort-order').val('desc');
		}
			
	}
	
	newURL = window.location.protocol + "//" + window.location.host + "/";
	newURL = newURL.replace(/www./i, '');
	window.location= newURL + url + $('#sort-order').val();
	
}

//function run on load 

function setupSorting() {
	var currentUrl = window.location.toString();
	var defaults = currentUrl.split('/');

	var bySegment = defaults.length -2;
	var	orderSegment = defaults.length -1;
	
	//alert(defaults[bySegment]);
	//alert(defaults[orderSegment]);
	
	$('#sort-order').val(defaults[orderSegment]);
	$('#sort-by').val(defaults[bySegment]);
	
	if($('#sort-order').val() != 'desc' && $('#sort-order').val() != 'asc')
	{
		$('#sort-order').val('asc');
		//$('#sort-by').val('');
	}
	
	var sortString = defaults[bySegment];
	
	sortString = sortString + '-sort' ;
	
	if(defaults[orderSegment] == 'desc')
	{
		$('.'+sortString+'.sort-arrow.up').show(); 
	}
	else
	{
		$('.'+sortString+'.sort-arrow.down').show(); 
	}
}


/*
$(document).ready(function () {
	$('th#date').bind('click', function() {
		window.location = "http://172.16.242.128:12355/message/sentMessages/date/asc";
	});
});
*/
/**
 * Uses the Google Maps API to search for location.
 *
 * @author Matt
 * @param location   String     The string to search fro
 * @param onComplete Function   Function to be called on completion. Gets 
 *                              passed two parameters; success (boolean), 
 *                              and an array of locations
 */
function getLocation (location, onComplete) {
	return new google.maps.Geocoder().geocode({
			'address': location
		}, function (results, status) {
			onComplete(status == google.maps.GeocoderStatus.OK, results);
		}
	);
};

function getLocationRefineSearch (dataObj, location, onComplete) {
	return new google.maps.Geocoder().geocode({
			'address': location
		}, function (results, status) {
			onComplete(status == google.maps.GeocoderStatus.OK, results, dataObj);
		}
	);
};

/**
 * Generic Code
 *
 * @author Matt
 */
$(document).ready(function () {
    // Used to create dialogs. Must be called last, otherwise any events or
    // data bound to the dialog elements after this is called will not be
    // saved
    $('div.modal-dialog').makeDialog();
});

/**
 * Plugins
 *
 * @author Matt
 */
/**
 * Dialog Plugin
 *
 * @author Matt
 */
(function ($) {
    /**
     * Initializes the dialogs by centering them, and storing a clone of the DOM
     * nodes in a data object so that the dialog can be reset.
     *
     * @author Matt
     * @return self
     */
    jQuery.fn.makeDialog = function () {
        return this.each(function () {
            var self = $(this);

            self.css('marginLeft', function (i, curr) {
                return -1 * (self.outerWidth() / 2);
            }).data('dialog.originalState', self.children().clone(true));
        });
    };

    /**
     * Shows the dialog. Will also hide any dialogs that are currently being
     * shown
     *
     * @author Matt
     * @return self
     */	
    jQuery.fn.showDialog = function () {
        $('div.modal-dialog').hide();

        var first = this.first();

        return first.empty().
                     prepend(first.data('dialog.originalState').
                     clone(true)).
                     show();
    };

    /**
     * Shows the dialog. Will also hide any dialogs that are currently being
     * shown
     *
     * @author Matt
     * @param selector	string	CSS selector to match the dialog to show
     * @param selector	jQuery	jQuery representation of the dialog to show
     * @return self
     */	
    jQuery.showDialog = function (selector) {
        if (typeof selector == "string") {
            selector = $(selector);
        };

        return selector.showDialog();
    };

}(jQuery));

/**
 * Form AJAX Plugin
 *
 * @author Matt
 */
(function ($) {
    /**
     * Used to cancel any AJAX requests that were initiated by ajaxify. Call it
     * on the form you want to cancel the AJAX request for:
     * $('#theForm').ajaxifyCancel()
     *
     * @author Matt
     * @return self
     */
    jQuery.fn.ajaxifyCancel = function () {
        var self = $(this);
        var data = self.data('ajaxify.xhr');

        if (data instanceof Object && typeof data.abort === "function") {
            data.abort();
        };

        self.removeData('ajaxify.xhr');

        return this;
    };

    /**
     * Ajaxify functionality. This simple plugin allows you to easily submit
     * forms using AJAX, instead of as a standard HTTP request. To use the
     * plugin, simply call $('your-form-selector').ajaxify(). Ajaxify accepts
     * some simple configuration options as parameters:
     *
     * @author Matt
     * @param settings  Function    Function executed on successful completion
     *                              of the AJAX request. It receives:
     *                              (data, textStatus, XMLHttpRequest)
     * @param settings  Object      KVPs of settings: see the options variable
     *                              for all possbilities
     * @return self
     */
    jQuery.fn.ajaxify = function (settings) {
        // All possible configuration options. These can be overridden by
        // passing an Object as the optional parameter, whose KVPs override
        // the options you want to change
        var options = {
                // Whether we want to disable the form submit button whilst the
                // AJAX request is in progress, to prevent multiple form
                // submissions
                disableSubmit: true,
                // Whether we want to show an loading spinner whilst the AJAX
                // request is in progress.
                showSpinner: true,
                // Expected response type from the server
                dataType: 'json',
                // Function which places the spinner whereever it is desired
                // in the page. Inside the function 'this' is the form that is
                // currently being AJAXed. The only parameter is a jQuery object
                // of the spinner that is to be added. The default behaviour is
                // to place the spinner after the first submit button
                appendSpinner: function (spinner) {
                    return $(this).find(':submit').first().after(spinner);
                },
                // Function which builds a spinner and returns it in a jQuery
                // object. Default behaviour is to return a simple spinning
                // image. Inside the function, this references the form that is
                // being AJAXed
                buildSpinner: function () {
                    return $('<img src="/images/loading.gif" alt="Loading"/>');
                },
                // A function that is executed before the form is submitted.
                // This is your last chance to add, edit, or remove form fields.
                // Inside the function, this references the form being AJAXed.
                // If a jQuery object is returned by the function, it is this
                // object that is sent as data to the server, and not the form
                // fields
                beforeSubmit: jQuery.noop,
                // A function that is executed when the request completes
                // successfully. The function receives 3 parameters; data,
                // textStatus and the XMLHttpRequest Object. Inside the
                // function, this points to the form being AJAXed
                onSuccess: jQuery.noop,
                // A function that is executed when the request fails. The
                // function receives 3 parameters; XMLHttpRequest, textStatus
                // and the errorThrown. Inside the function, this points to the
                // form being AJAXed
                onError: jQuery.noop,
                // A function that is executed when the request completes
                // either successfully or with errors. This function is executed
                // after the onSuccess or onError handler has being executed.
                // The function receives 2 parameters; XMLHttpRequest and
                // textStatus. The response can be retrieved using
                // XMLHttpRequest.reponseText. Inside the function, this points
                // to the form being AJAXed
                onComplete: jQuery.noop
            };
        
        switch (typeof settings) {
            case "function":
                options.onSuccess = settings;
            break;
            case "object":
                options = jQuery.extend(options, settings);
            break;
        };

        return this.live('click.ajaxify', function (event) {
        	if($("#login_hack").val() == '0') {
        		return;
        	}
        	$("#login_hack").val(0);
            var that = this;
            var self = $(this);
            var existingXhr = self.data('ajaxify.xhr');
            var existingSpinner = self.data('ajaxify.spinner');

            // Restore the page to how it was before we added all of our
            // spinners, and disabled all the submit buttons
            function cleanup () {
                var spinnerToRemove = self.data('ajaxify.spinner');

                self.removeData('ajaxify.xhr');
                self.find(':submit').attr('disabled', false);

                if (spinnerToRemove && spinnerToRemove.remove) {
                    spinnerToRemove.remove();

                    self.removeData('ajaxify.spinner');
                };
            };

            // Abort any existing XHR request that is in progress for the form
            if (existingXhr instanceof Object
                && typeof existingXhr.abort === "function") {
            	
                existingXhr.abort();
                self.removeData('ajaxify.xhr');
            };

            // Remove any existing spinners
            if (existingSpinner instanceof Object
                && typeof existingSpinner.remove === "function") {

                existingSpinner.remove();
                self.removeData('ajaxify.spinner');
            };

            // Disabled all submit buttons, if that option is set.
            if (options.disableSubmit) {
                self.find(':submit').attr('disabled', true);
            };
            
            // Build and add the loading spinner, if that option is set.
            if (options.showSpinner) {
                var builtSpinner = options.buildSpinner.call(this);

                options.appendSpinner.call(this, builtSpinner);
                self.data('ajaxify.spinner', builtSpinner);
            };

            // Call the beforeSubmit handler. Detect whether it returned a
            // jQuery object. If it did, it is this object that is serialized
            // and set as data, instead of the form elements
            var beforeSubmitResult = options.beforeSubmit.call(this);
            var beforeSubmitIsJquery = (beforeSubmitResult instanceof Object
                                        && beforeSubmitResult.selector);

            if (beforeSubmitResult === false) {
                return;
            };
            
            // Dispatch the AJAX request, and save it to the data object so that
            // is can be referenced and cancelled if need be.

            self.data('ajaxify.xhr', jQuery.ajax({
                url: this.action,
                type: 'post',
                dataType: options.dataType,
                data: (beforeSubmitIsJquery ? beforeSubmitResult.serialize()
                                            : self.serialize()),
                success: function (/**/) {
                    cleanup();
                    
                    options.onSuccess.apply(that, arguments);
                },
                error: function (/**/) {
                    cleanup();

                    options.onError.apply(that, arguments);
                },
                complete: function (/**/) {
                    options.onComplete.apply(that, arguments);
                }
            }));

            
            if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; }


        });
    };
}(jQuery));




