/**
 * ListingsSearch JQuery Plugin
 *	usage: called for the featured listings module.
 *  Copyright (c) 2011, RealPageMaker
 *	This plugin attempts to implement all best practices as described here:
 *		http://docs.jquery.com/Plugins/Authoring
 */
(function( $ ){

	/**
	 * Plugin Definition (Listings Search).
	 *
	 * Plugin Flow / Structure (target element refers to the modletWrapper that we have been called on):
	 *  - check if the target element has data (aka if it has been initialized) if so do nothing otherwise initialize settings.
	 *  - Define all of our internal helper functions.
	 *  - If methodToCall is null or init - run the modlet intialization routine "init()".
	 *  - If methodToCall is something else try to run that routine.
	 *  - return "this" to maintain chainability.
	 *
	 * NOTE: in the context of this function "this" refers to the object that we call it on that's why it's used frequently as context.
	 * NOTE: in the context of this function we can use "this" in callbacks but we have to use $(this) -- where it refers to the element the call back is on NOT the modletWrapper
	 * 
	 * Options:
	 * - all defined in the "defaultSettings" can be passed in (although modletId is filled out for you).
	 * - If you need to update these options please use the reconfigure method.
	 */
	$.fn.listingsSearch = function(methodToCall, options){

		// Listings Search Settings (With defaults where applicable)
		var defaultSettings = { 
			'modletId'	:	'',		// The id of the modlet wrapper div taken at runtime off from "this"
			'pathway'	:	'1',		// The pathway for the featured listings module in the controller.
			'brokAgentId'	:	'',		// If showing the featured listings module on a brokerage agent's page this will have the brokerage agent's id.
			'ajaxTarget'	:	'listings',	// Ajax target, either 'listings' controller or the wp plugin ajax target php page.
			'plugin'		: false,
			'fullAjaxMode'	:  1,		// If set to 1 all will be done via ajax, if 0 Status sections (Active / Sold etc..) and pagination are done via links (Links which are provided by the view).
			'city'		:	'',		// The city and neighbourhood, used when we're displaying the listings for a communities section modlet.
			'neigh'		:	'',
			'currentView' : 0,
			'sortBy' : 0,
			'sortSoldBy' : 0,
			'sortBSSoldsBy' : 0,
			'totalResults' : 0,
			'resultsPerPage' : 0,
			'page' : -1
		};
		
		/******************************************************************************************/
		/*                                    Instance METHODS                                    */
		/******************************************************************************************/
		
		var methods = {
			/**
			 * Initializes the correct event handlers for the elements of the module.
			 * 
			 * NOTE: Called at the bottom of this ($.fn.listingsSearch) function if no method to call given.
			 */
			initModlet : function (options) {
				var self = this;
				return this.each(function(){

					var $this = $(this);
					var settings = {};

					if($this.data("settings") == null) {
						if(options) $.extend(settings, defaultSettings, options); 
						
						// modletId - we can grab it from the "this" object as that is the object that we have been called on. Note: this is above the options handling so we can force the modletId if we want to.
						settings.modletId = $this.attr('id');
					
						settings.listingsSearchAjaxRequest = null; // The actual request as it's running (used to abort it if necessary).
					}else{
						settings = $this.data("settings");
						if(options) $.extend(settings, defaultSettings, options);
					}

					// Store the settings in the data element of the modletWrapper so they are available everywhere we have a reference to the modletWrapper.
					$this.data("settings", settings);

					
					// add rollover event to the left container to show the photo navigation
					$(".cs-listings-results-result-left-container", $this).live("mouseover", function(){
						$('.cs-photo-nav-small-right, .cs-photo-nav-small-left', this).show();
					}).live("mouseout", function(){
						$('.cs-photo-nav-small-right, .cs-photo-nav-small-left', this).hide();
					});

					//Check the hash and load - only searches in full ajax mode should ba able to access this!!!
					if(settings.fullAjaxMode == 1 && window.location.hash != null && window.location.hash != ""){
						//Check the hash's modletId value to see if if it is valid for this view
						var qs = window.location.hash;						
						var mId = qs.slice(qs.indexOf("modletId=") + "modletId=".length).split("&")[0];
						
						//alert("modletId: ~" + mId + "~");						
						if(mId === settings.modletId.slice("modletWrapper_".length)) methods['getListingsSearchResults'].call(self, { 'hash' : true });
					}
				});
			},
			/**
			 *  Initializes the drop down / 
			 */
			initPageEvents : function(){
				var self = this;
				return this.each(function(){
					var $this = $(this);
					var settings = $this.data("settings");
					
					/** Config the on click events of the status (Active / Sold / BSSold) tabs. **/
					$('#propType, #listingsView, #sortBy', $this).unbind("change").bind("change", function(){
						if(settings.fullAjaxMode == 1){
							methods['getListingsSearchResults'].call(self, {'changed' : this });
							return false;
						}else{
							var path = location.pathname;
							
							if(path == "/"){ //non-permalink
								path = location.href.split("&listingsView=")[0] + "&";
							}else{ //permalink
								if(path.indexOf("/list-view") == -1) {
									if((location.href).lastIndexOf("/") != (location.href).length - 1) path += "/list-view?"; 
									else path += "list-view?"; 
								}else{
									path += "?";
								}
							}
							
							//Set the default sortBy value based on current listings view
							var sortBy = $("#sortBy", $this).val();
							switch($("#listingsView", $this).val()){
								case "2" :
									sortBy = settings.sortSoldBy;
									break;
								case "3" :
									sortBy = settings.sortBSSoldsBy;
									break;
							}
						
							var searchForm = $(this).parents("form");
							
							if($(this).attr("id") == "propType"){
								window.location.href = path + "listingsView=" + searchForm.find("#listingsView").val() + "&propType=" + $(this).val() + "&sortBy=" + sortBy + "&page=0";
							}else if($(this).attr("id") == "listingsView"){
								window.location.href = path + "listingsView=" + $(this).val() + "&propType=" + searchForm.find("#propType").val() + "&sortBy=" + sortBy + "&page=0";
							}else{
								window.location.href = path + "listingsView=" + searchForm.find("#listingsView").val() + "&propType=" + searchForm.find("#propType").val() + "&sortBy=" + $(this).val() + "&page=0";
							}	
						}
						return true;
					});
								
					// If we are NOT doing everything via ajax.
					if(settings.fullAjaxMode == 0) { 
						helpers["disableFullAjaxMode"].call($this);
					}
					
					//Save the loaded view's sort selection as it may differ from the default i.e. custom url
					settings.currentView = $("#listingsView", $this).val();
					
					switch($("#listingsView", $this).val()){
						case "0" :
						case "1" :
							settings.sortBy = $("#sortBy", $this).val();
							break;
						case "2" :
							settings.sortSoldBy = $("#sortBy", $this).val();
							break;
						case "3" :
							settings.sortBSSoldsBy = $("#sortBy", $this).val();
							break;
					}
					
					// add rollover event to the left container to show the photo navigation
					$(".cs-listings-results-result-left-container", $this).mouseover(function(){
						$('.cs-photo-nav-small-right, .cs-photo-nav-small-left', this).show();
					}).mouseout(function(){
						$('.cs-photo-nav-small-right, .cs-photo-nav-small-left', this).hide();
					});

					// store the settings for later use
					$this.data("settings", settings);
				});
			},
			/**
			 * This function refreshes the entire results section for the listings search and
			 * is called whenever there is a change in one of the input elements in the form.
			 *
			 * @param options {pageNumber : value } number from whence to begin the results
			 */
			getListingsSearchResults : function(options){
				return this.each(function(){
					var $this = $(this);
					var settings = $this.data("settings");
					
					// Handle any options.
					var defaultOptions = {'pageNumber' : '', 'changed' : null, 'hash' : false};
					var myOptions = {};
					$.extend( myOptions, defaultOptions, options );
					
					var useDefaultSort = false;
					
					$("#listingSearchLoadingMessage", $this).show();
					
					var urlData = "";
					
					if(settings.listingsSearchAjaxRequest) settings.listingsSearchAjaxRequest.abort();
					
					if(myOptions.hash == true && settings.fullAjaxMode == 1){
						//alert("Hash is true: " + myOptions.hash);
						
						// remove the hashbang
						urlData = window.location.hash.slice(2);
						//myOptions.hash = false;
					}else{
						// generate applicable paging variable
						var page = "";
						if(myOptions.pageNumber != null && myOptions.pageNumber != ''){
							page = '&page=' + myOptions.pageNumber;
							settings.page = myOptions.pageNumber;
						}
						
						// get URL data
						// check if we're only searching office listings (listingsView won't be present)
						urlData  = "pathway=" + settings.pathway + "&results=true"+page;
						
						var listingsView = "";
						if(myOptions.pageNumber == ''){
							var sortSection = $(myOptions.changed).parents('form');
							listingsView = sortSection.find("#listingsView").val();
							if(listingsView == settings.currentView){
								urlData += "&" + sortSection.formSerialize();
								useDefaultSort = false;
							}else{
								urlData += "&" + sortSection.find('[name="propType"], [name="listingsView"]').fieldSerialize();
								useDefaultSort = true;
							}
						}else{
							var sortSection = $(myOptions.changed).siblings(".cs-pagination-bar-sort");
							listingsView = sortSection.find('form').find("#listingsView").val();
							if(listingsView == settings.currentView){
								urlData += "&" + sortSection.find('form').formSerialize();
								useDefaultSort = false;
							}else{
								urlData += "&" + sortSection.find('form').find('[name="propType"], [name="listingsView"]').fieldSerialize();
								useDefaultSort = true;
							}
						}
						
						if(useDefaultSort === true){
							switch(listingsView){
								case "0" :
								case "1" :
									urlData += "&sortBy=" + settings.sortBy;
									break;
								case "2" :
									urlData += "&sortBy=" + settings.sortSoldBy;
									break;
								case "3" :
									urlData += "&sortBy=" + settings.sortBSSoldsBy;
									break;
								default:
									break;
							}
						}
						
						if(settings.brokAgentId != "") urlData += "&brokerageAgentId=" + settings.brokAgentId;

						/**** IF We're sending url data for a communities modlet request we hijack it here. ****/
						if(settings.city != '' && settings.neigh != '') {
							urlData = "pathway=" + settings.pathway + "&city=" + settings.city + "&neigh=" + settings.neigh + "&" + page;
						}

						// Make sure to keep track of the fullAjaxMode
						urlData += "&fullAjaxMode=" + settings.fullAjaxMode;
						
						// Send the modlet id # along too, if this ajax needs to generate calls that access our modletWrapper it will know how if we send the id number.
						if(settings.modletId) {
							urlData += "&modletId=" + settings.modletId.substring('modletWrapper'.length + 1);
						}
						
					}
						
					// make the AJAX call to retrieve listings
					listingsSearchAjaxRequest = $.ajax({
						type: "GET",
						url: settings.ajaxTarget,
						data: urlData,
						dataType: "html",
						error: function(data, error){
							alert("Error: getResults(): " + error + " " + data);
						},
						success: function(data){
							$("#listingSearchLoadingMessage", $this).hide();
							
							/** For the communities modlet we replace the whole modlet wrapper div, however for the Featured Listings modlet we only replace the results. **/
							if(settings.city != '' && settings.neigh != '') {
								$this.html(data);
								
							} else {
								$("#listingResultsModule", $this).html(data);
							}
							
							// If we are NOT doing everything via ajax.
							if(settings.fullAjaxMode == 0) { 
								disableFullAjaxMode();
							}

						},
						complete: function (XMLHttpRequest, textStatus) {
							if(settings.fullAjaxMode == 1) location.replace(location.href.replace(location.hash, "") + "#!" + urlData);
						}
					});
					
					$this.data("settings", settings);
				});
			},
			/**
			 * This function displays a slide show for a specified listing
			 *
			 * @param options {} of ...
			 * - listingCounter - the number of the listing (0-n) in this modlet's list of listing summaries.
			 * - listNum - listing to grab slideshow for
			 */
			loadListingPictures : function( options ){
				return this.each(function(){
					var $this = $(this);
					var settings = $this.data("settings");

					$.clickSoldUtils('toSourceCode', settings);
					
					// Handle any options.
					var myOptions = {'listNum' : '', 'clicked' : null}; // Define some defaults.
					if ( options ) $.extend( myOptions, options );
					
					if(myOptions.clicked != null){
						var clicked = myOptions.clicked;
						var picCnt = $(clicked).siblings(".cs-photo-container");
						var next = true;
						
						if($(clicked).hasClass("cs-photo-nav-small-left")){
							next = false;
						}
						
						if($(clicked).siblings("input[name='picsLoaded']").attr("value") == "false"){
							//Get Search Options here & construct query string
							$.ajax({
								type: "GET",
								url: settings.ajaxTarget,
								data: "pathway=6&listingNumber="+myOptions.listNum+"&slideshow=true&summary=true",
								dataType: "json",
								beforeSend: function(){
									$(clicked).parent(".cs-listings-results-result-left-container").block({
										message: "Loading..."
									});
								},
								error: function(data, error){
									alert("Error: displayListingSummarySlideshow(): " + error + " " + data);
									return false;
								},
								success: function(data){
									if(data.images.length > 1){
										var img = new Image();
										var imgIndex = 1;
										if(next == false) imgIndex = data.images.length - 1;
										for(var i=0;i<data.images.length;i++){
											if(i == imgIndex){
												img.src = data.images[i].path;
												img.onload = function(){ 
													picCnt.children("img").first().remove(); 
													picCnt.children().eq(imgIndex).css("display", "inline");
													$(clicked).parent(".cs-listings-results-result-left-container").unblock({fadeOut:500});
												}
												picCnt.append('<img class="cs-photo-container-wrap" border="0" style="display:none;" src="' + img.src + '" alt="' + data.images[i].desc + '">');
											}else{
												picCnt.append('<img class="cs-photo-container-wrap" border="0" style="display:none;" src="' + data.images[i].path + '" alt="' + data.images[i].desc + '">');
											}
										}
										$(clicked).siblings("input[name='picsLoaded']").attr("value", "true");
									}
								},
								complete: function(jqXHR, textStatus){
									if(textStatus != "success") $(clicked).parent(".cs-listings-results-result-left-container").unblock({fadeOut:500});
								}
							});
						}else if($(clicked).siblings("input[name='picsLoaded']").attr("value") == "true" && picCnt.children().length > 1){
							var current = picCnt.children(":visible");
							if($(clicked).hasClass("cs-photo-nav-small-left")){
								if(current.prev().length == 0){
									picCnt.children().last().css("display", "inline");
								}else{
									current.prev().css("display", "inline");
								}
							}else if($(clicked).hasClass("cs-photo-nav-small-right")){
								if(current.next().length == 0){
									picCnt.children().first().css("display", "inline");
								}else{
									current.next().css("display", "inline");
								}
							}
							current.css("display", "none");
						}
					}
				});
			},
			/**
			 * This function displays the listing media for a specified listing
			 *
			 * @param options {} of ...
			 * - listingCounter - the number of the listing (0-n) in this modlet's list of listing summaries.
			 * - listNum - listing to grab media for
			 */
			displayListingSummaryMedia : function( options ){
				return this.each(function(){
					var $this = $(this);
					var settings = $this.data("settings");
				
					// Handle any options.
					var myOptions = {'listingCounter' : '', 'listNum' : ''}; // Define some defaults.
					if ( options ) $.extend( myOptions, options );

					// abort any pending requests
					if(settings.listingsSearchAjaxRequest) settings.listingsSearchAjaxRequest.abort();
				
					settings.listingsSearchAjaxRequest = $.ajax({
						type: "GET",
						url: settings.ajaxTarget,
						data: "pathway=6&type=results&listingNumber=" + myOptions.listNum + "&media=true&summary=true",
						dataType: "html",
						error: function(data, error){
							alert("Error: runSearch(): " + error + " " + data);
						},
						success: function(data){
							$("#right_view_content_" + myOptions.listingCounter, $this).html(data);
						},
						complete: function (XMLHttpRequest, textStatus) {
							$("#listingSummaryVTours_" + myOptions.listNum, $this).RPMSlideShow({virtualTour:true});
						}
					});
				});
			},
			/**
			 * Updates the pagination links on page load
			 */
			loadPagination : function( totalResults, resultsPerPage, page ){
				var self = this;		
				return this.each(function(){
					
					// Handle any options.
					var $this = $(this);
					var settings = $this.data("settings");
					
					settings['totalResults'] = totalResults;
					settings['resultsPerPage'] = resultsPerPage;
					settings['page'] = page;
					
					$this.data("settings", settings);
										
					if(page != -1) {
						var minResult = ((settings['page'] - 1) * settings['resultsPerPage']) + 1;
						var maxResult = (minResult + settings['resultsPerPage']) - 1;
						if( maxResult > settings['totalResults'] ) { maxResult = settings['totalResults']; }
					
						//Show text display
						$(".cs-pagination-bar-displaying", $this).html( minResult + " - " + maxResult + " of " + settings['totalResults'] );

						var totalPages = settings['totalResults'] / settings['resultsPerPage'];
						var pageLink = "#";
						
						if(settings['fullAjaxMode'] == 0){
							var path = window.location.pathname;
														
							// Detect if permalinks are being used as the paths need to be diff in that case.
							var wpPermalinks = true;
							if(window.location.search.indexOf("page_id=") != -1) { wpPermalinks = false; }
														
							if(settings["city"] == "" && settings["neigh"] == "") { // Featured listings / MLS Search??? results view.
								if(path.indexOf("/list-view") == -1) { path += "/list-view"; }
								
								if(wpPermalinks) {
									pageLink = path + "?listingsView=" + $("#listingsView", $this).val() + "&propType=" + $("#propType", $this).val() + "&sortBy=" + $("#sortBy", $this).val() + "&page=__id__";
								} else {
									// Extract the page_id parameter from the query string.
									var pattern = /page_id=\d+/;
									var page_id = pattern.exec(window.location.search);

									pageLink = "?" + page_id + "&listingsView=" + $("#listingsView", $this).val() + "&propType=" + $("#propType", $this).val() + "&sortBy=" + $("#sortBy", $this).val() + "&page=__id__";
								}
							} else { // City + Neighbourhood search results.
								if(wpPermalinks) {
									//Check if there's a page number in the url - remove it
									if(path.length + " == " + (path.lastIndexOf("/") + 1)) path = path.substr(0, path.lastIndexOf("/"));
									var num = path.substr(path.lastIndexOf("/") + 1);
									if( !isNaN(num) ) path = path.substr(0, path.lastIndexOf("/"));
									pageLink = path + "/__id__";
								} else {
									// Check if there's a page number in the url - remove it (Xept removing this one is diff than the permalink case)
									var oldQueryStr = window.location.search;
									if(oldQueryStr.lastIndexOf("&page=") != -1) { // If it has the parameter we cut it off (by definition it's always the last one.
										pageLink = oldQueryStr.substr(oldQueryStr.lastIndexOf("&page="), oldQueryStr.length);
									}
									pageLink = oldQueryStr + "&page=__id__";
								}
							}
						}
						
						//Initialize paging
						$(".cs-pagination-bar-paging", $this).pagination(totalPages, {
							callback: function(pageIndex, paginationContainer){
								if(settings.fullAjaxMode == true || settings.fullAjaxMode == "true"){
									methods['getListingsSearchResults'].call(self, {'pageNumber' : pageIndex + 1 , 'changed' : paginationContainer });
									return false;
								}
								return true;
							},
							next_text: '&nbsp;&gt;&nbsp;',
							prev_text: '&nbsp;&lt;&nbsp;',
							num_display_entries: '3',
							num_edge_entries: '1',
							current_page: settings.page - 1,
							items_per_page: 1, // Show only one item per page
							link_to: pageLink
						});
					}
				});
			}
		};
		
		/**
		 *  Private functions
		 */
		var helpers = {
			/**
			 * This function disables the onClick events when we are not using full ajax mode.
			 * In NON full ajax mode the on click events are removed and it's left to the view
			 * to have filled out the correct links. The listing type tabs (Active / Sold / BSSold)
			 * as well as the pagination are the two items that then will work via links and not ajax.
			 */
			disableFullAjaxMode : function() {
				return this.each(function(){
					var $this = $(this);
					/** Find all of the pagination and header tabs and get rid of their on click events. For the non ajax mode these will have actual links */
					$(".paginationRight", $this).find("a").each(function(){
						$(this).attr("onclick", "");
					});
				});
			}
		};
		
		/******************************************************************************************/
		/*                               Function Calling logic.                                  */
		/******************************************************************************************/
				
		// If we do have a requested method that we should call do so now.
		if ( methods[ methodToCall ] ) { // Make sure it exists.
			if ( typeof this.data("settings") == "undefined" ) {
				var methodQueue = new Array();
				if( typeof this.data("methodQueue") != "undefined" ) methodQueue = this.data("methodQueue");
				methodQueue.push([methodToCall, Array.prototype.slice.call( arguments, 1 )]);				
				this.data("methodQueue", methodQueue);
				return false;
			} else {
				return methods[ methodToCall ].apply( this, Array.prototype.slice.call( arguments, 1 ));
			}
		} else if(typeof methodToCall === 'object') {
			 // This initializes the entire modlet setting events and such.
			var init =  methods['initModlet'].apply( this, arguments );
			
			//Run queued method calls
			if( typeof this.data("methodQueue") != "undefined" ) {
				var methodQueue = this.data("methodQueue");
				while(methodQueue.length > 0){
					var m = methodQueue.shift();
					methods[m[0]].apply(this, m[1]);
				}
			}
			
			return init;
		} else {
			//Do Nothing
			//alert( 'Method ' +  methodToCall + ' does not exist on jQuery.listingsSearch' );
		}
		
		return this; //maintain chainability (jQuery specification)
	};
	
})( jQuery );

