/**
 * Core javascript functionality
 * - ApplicationHelper[Class]
 *   
 * - BaseApplicationModuleClass - base class for other modules
 */
ApplicationHelperClass = Class.extend(
{
	initialize : function( baseURL, csrfId, csrfCode )
	{
		this.baseURL = baseURL;
		this.csrfId = csrfId;
		this.csrfCode = csrfCode;
	},
	
	/** 
	 *generates url
	 */
	url : function( relativePart )
	{
		return this.baseURL + relativePart.replace( /,/g, "/" );
	},
	
	processUrl : function( relativePart )
	{
		return this.url( relativePart ); 
	},
	
	getCSRFID : function()
	{
		return this.csrfId;
	},
	
	getCSRFCode : function()
	{
		return this.csrfCode;
	},
	
	selectAllCheckboxes : function( selector )
	{
		var sel = selector + " :checkbox";
		$( selector + " :checkbox" ).attr( "checked", "checked" );
	},
	
	deselectAllCheckboxes : function( selector )
	{
		$( selector + " :checkbox" ).attr( "checked", false );
	},

	/**
	 * Toggles visibility of $(selector) upon checked state of $(checbox)
	 * if 'invert' is false = then $(selector)  is shown when $(checbox) is checked
	 * if 'invert' is true = then $(selector)  is shown when $(checbox) is UNchecked
	 */
	toggleOtherCheckboxes : function( controlCheckbox, checkboxSelector )
	{
		var checkbox = $(controlCheckbox);
		var isSelected = checkbox.attr('checked');
		if ( isSelected )
		{
			$( checkboxSelector ).attr( "checked", "checked" );
		}
		else
		{
			$( checkboxSelector ).attr( "checked", false );
		}
	},

	/**
	 * Toggles visibility of $(selector) upon checked state of $(checbox)
	 * if 'invert' is false = then $(selector)  is shown when $(checbox) is checked
	 * if 'invert' is true = then $(selector)  is shown when $(checbox) is UNchecked
	 */
	toggleOtherOnCheck : function( checkbox, selector, invert )
	{
		var animate = true;
		if ( $(selector).is('tr') || $(selector).is('td') || $(selector).is('table') )
		{
			animate = false;
		}
		
		var checkbox = $(checkbox);
		var isSelected = checkbox.is(':checked');
		var shouldShow = ( invert ? (! isSelected) : (isSelected) );
		
		if (shouldShow)
		{
			if ( animate ) 
			{
				$(selector).slideDown();
			}
			else
			{
				$(selector).show();
			}
		}
		else
		{
			if ( animate ) 
			{
				$(selector).slideUp();
			}
			else
			{
				$(selector).hide();
			}
		}
	},

	/**
	 * 
	 * 
	 * @param Element linkElement 
	 * @param string lang - language code ('pl', 'en', 'de', etc.)
	 */
	changeLanguage : function( linkElement, lang, global )
	{
		$('.langSwitcher').removeClass('currentLang');
		var form = global ? $(document) : $($(linkElement).parents('form').get(0));
		var multilangFields = form.find('.multilang');

		multilangFields.hide(); // hide all fields

		// show only the selected one
		multilangFields.each( function()
		{
			var el = $(this);
			if ( el.attr( 'lang' ) == lang )
			{
				el.show();
			}
		});
		
		$(linkElement).addClass('currentLang');
		
		return false;
	},
	
	changeApplicationLanguage : function( linkElement, lang )
	{
	
		$.post(
			$(linkElement).attr('href'),
			null,
			function (data)
			{
				window.location.href = window.location.href; 
			}
		);
		
		return false;
	},
	
	attachValueCopier : function( sourceSelector, destinationSelector )
	{
		$(sourceSelector).keyup( function(event)
		{
			$(destinationSelector).val($(event.target).val());
		});
	},
	
	attachDatepickerTo : function( selector )
	{
		$(selector).attachDatepicker({ 
			dateFormat: 'dd.mm.yy',
			showAnim: 'slideDown'
		});
	}
});



BaseApplicationModuleClass = Class.extend( {

	// data: [], -- will be shared with other instances of this class
	// initialize this.data in initialize() function!!! 
	initialize : function()
	{
	},
	
	/**
	 * This makes clicks on regular GET links behave as POST request,
	 * by adding hidden form of POST type.
	 * Additionally adds CSRF automatically data.
	 * 	
	 * @param DOMElement linkElement <a> elemnt: <a ...onclick="xModule.fakePostRequest( this );"> so, 'this' is the object you pass 	
	 * @param string confirmationMessage
	 * @return boolean always false to prevent default action
	 */
	fakePostRequest : function( linkElement, confirmationMessage )
	{
		if ( confirmationMessage )
		{
	    	if ( ! confirm( confirmationMessage ) )
	    	{
	    		return false;
	    	}
		}
		
		var link = $(linkElement);
		var formHTML = '<form action="' + link.attr('href') + '" style="display: none;" method="post">';
		
		formHTML += '<input type="hidden" name="csrf[id]" value="' + ApplicationHelper.getCSRFID() + '"/>';
		formHTML += '<input type="hidden" name="csrf[code]" value="' + ApplicationHelper.getCSRFCode() + '"/>';
		formHTML += '</form>';
		link.append( formHTML );
		link.children('form').hide();
		link.children('form').get(0).submit();
		return false;
	},
	
	/**
	 * For simple deleting and goind to default site (pointed to by delete action)
	 * @param DOMElement link <a> object
	 * @param string message Message that will be displayed in confirmation window; 
	 *	on confirm the action will be executed
	 *	on cancel - action aborted 
	 * @return boolean always false
 	 */
	deleteObject : function(link, message )
	{
		return this.fakePostRequest( link, message );
	},
	
	ajaxDeleteObject : function(link, message)
	{
    	if ( ! confirm( message ) )
    	{
   			return false;
    	}
	
		
		// send delete reques
		// and then show current page again
		// 		this is done by clicking on current page number!! - so this must be valid "A"
		$.ajax(
		{
			type : "POST",
			url : 	$(link).attr('href'), // delete URL
			dataType : "html",
			data : null,
			success : function()
			{
				var currentPageLink = $(link).parents( '#search_results:first').find('.navigation a.current');
				var currentPageLinkExists = (currentPageLink.length > 0); 
				if ( currentPageLinkExists )
				{
					currentPageLink.click(); // nice refresh
				}
				else
				{
					$('#finderSearcher button.search').click(); // slides up and down...
				}
			},
			error : function()
			{
				$(link).parents('tr:first').highlightFade('red');
			}
		});
		
		return false;
	}
});



/* move to /public/javascript/modules/ */
FinderSearcherClass = Class.extend(
{
	initialize : function()
	{
		this.lastSearchName = "";
	},
	
	newSearch : function()
	{
		this.lastSearchName = null;
		$('#searcher_fields').slideUp("normal", function()
		{
			$('#searcher_fields form').get(0).reset();
			$('#searcher_fields #choosenFields').children().remove();
			$('#search_results').slideUp();
			$('#searcher_fields').slideDown();
		});
		
		return false;
	},
	
	saveSearch : function(buttonElement, actionURL, message)
	{
		var name = prompt( message+':' , this.lastSearchName );
		if ( ! name )
		{
			return false;
		}
		
		this.lastSearchName = name;
		$('#search_save_name').val( name );
		
		
		var form = $(buttonElement).parents('form:first');
		var url = actionURL;
		// hide default fields
		$('#availableFields input').attr('disabled', true);
		$('#availableFields select').attr('disabled', true);
		
		
		$.post(
			url,
			form.serialize(),
			function (data)
			{
				form.highlightFade();
				$('#saved_searches').html(data);
			}
		);
		
		$('#availableFields input').attr('disabled', false);
		$('#availableFields select').attr('disabled', false);
		return false;
	},
	
	loadSavedSearch : function( linkElement )
	{
		var dys = this;
		$('#search_results').hide();
		$('#searcher_fields').slideUp("normal", function()
		{
			$('#choosenFields').html("");
			var url = $(linkElement).attr('href');
			$.getJSON( url, null, function(json)
			{
				$('#search_save_name').val( json.name );
				$.each( json.data, function (key, item)
				{
					if ( key == "sort_field" )
					{
						$('#search_sort_field').val(item);
					}
					else if ( key == "sort_direction" )
					{
						$('#search_sort_direction').val(item);
					}
					else if ( key == "per_page" )
					{
						$('#search_per_page').val(item);
					}
					else
					{
						$.each( item, function( i, value )
						{
							var name = 'search_field__' + key;
							dys.addFieldNamed( name, value );
						});
						
					}
				});
				
				dys.lastSearchName = $(linkElement).text(); // search name == text on saved search button
				$('#searcher_fields').slideDown();
				dys.performSearch( $('#searcher_fields form').get(0));
			});
		});
		
		return false;
	},
	
	addFieldNamed : function( name, value )
	{
		var field = $('#availableFields li.' + name ).clone();
	 	if ( value )
	 	{
	 		// ie. { from: 10, fo: 20 }
	 		// each property comes to separate input/select
	 		// in order that they appear
	 		if ( typeof(value) == "object") 
	 		{
	 			// replace object with array indexed from 0
	 			var vv = new Array();
	 			for ( p in value )
	 			{
	 				vv.push( value[p] );
	 			}
	 			
	 			
	 			// find next input/select and set its value
	 			var k = 0;
	 			field.children().each( function( i, item )
	 			{
	 				if ( item.tagName.toLowerCase() == "input" || item.tagName.toLowerCase() == "select" )
	 				{
	 					$(item).val(vv[k]);
	 					k++;
	 				}
	 			});
	 		}
	 		else
	 		{
	 			// simple value (string/integer)
				field.find('input').val( value );
				field.find('select').val( value ); // brute forcish - but it will work
	 		}
		}
		
 		this.injectAutocompletor( field );
		
		// if there are other fields with this name, add it after them
		if ( $('#choosenFields li.' + name).length > 0 )
		{
			$('#choosenFields li.' + name + ':last').after( field );
		}
		else
		{
			field.appendTo( $('#choosenFields') );
		}
		
		// select fist input|select field within the <LI>
		var firstChild = field.children('input').add(field.children('select')).get(0);
		
		// add datepicker if needed to newly created field
		field.find('.datepicker').removeClass('hasDatepicker')
		ApplicationHelper.attachDatepickerTo(field.find('.datepicker'));
		
		firstChild.focus();
	},
	
	injectAutocompletor : function( field )
	{
		field.find('input.autocomplete').each( function( i, item )
		{ 
			var input = $(item);
			
			// process configuration
			// delegate:TicketAdmin;field:customer_id
			var autocompleteDefinition = input.attr('rel');
			
			// [ delegate:TicketAdmin, field:customer_id ]
			var params =  autocompleteDefinition.split(';');
			var vals = {};
			for ( var i = 0; i < params.length; i++ )
			{
				// [ delegate, TicketAdmin ]
				var x = params[i].split(":");
				if ( x.length != 2 )
				{
					continue;
				}
				// { delegate : TicketAdmin }
				vals[x[0]] = x[1];
			}
			
			var module = vals.delegate;
			var fieldName = vals.field;
			eval( module + '.installAutocomplete( input, "' + fieldName + '");' ); 
		});
	},
	
	deleteSavedSearch : function( linkElement, message )
	{
		if ( ! confirm( message ) )
		{
			return false;
		}
		
		$.post(
			$(linkElement).attr('href'),
			null,
			function (data)
			{
				$('#saved_searches').highlightFade();
				$('#saved_searches').html(data);
			}
		);
		
		return false;
	},
	
	deleteSearchField : function( linkElement )
	{
		$(linkElement).parents('li').remove();
		return false;
	},
	
	addNewField : function( selectElement )
	{
		var select = $(selectElement);
		var val = select.val();
		select.val(""); // clear selection
		
		// copy field to choosenFields
		this.addFieldNamed( val );
		
		return false;
	},
	
	
	/**
	 * 
	 * @param formElement DOM element for <form>
	 * @param url String will overwrite form's action attribute - if specified 
	 */
	performSearch : function( formElement, url, skipAnimation )
	{
		var form = $(formElement);
		if ( ! url )
		{
			url = form.attr('action');
		}
		// hide default fields
		$('#availableFields input').attr('disabled', true);
		$('#availableFields select').attr('disabled', true);
		
		if ( skipAnimation )
		{
			$.post(
				url,
				form.serialize(),
				function (data)
				{
					$('#search_results').html(data);
				}
			);
		}
		else
		{
			$('#search_results').slideUp( 'normal', function() 
			{
				$.post(
					url,
					form.serialize(),
					function (data)
					{
						$('#finderSearcher #searchPageNumber').remove(); // delete page number from the search form
						form.highlightFade();
						$('#search_results').html(data);
						$('#search_results').slideDown();
					}
				);
				
				$('#availableFields input').attr('disabled', false);
				$('#availableFields select').attr('disabled', false);
			});
		}
		return false;
	},
	
	nextSearchPage : function( url )
	{
		var formElement = $('#searcher #searcher_fields form').get(0);
		return this.performSearch( formElement, url, true );
	},
	
	hideSearcher : function()
	{
		$('#searcher_fields').slideUp();
		return false;
	},
	
	buildFieldSelector : function()
	{
		var fieldAdder = $('#addField select');
		$('#availableFields li').each( function(i, item) 
		{
			var value = $(item).attr('class');
			var label = $(item).attr('rel');
			var html = '<option value="' + value + '">' + label + '</option>';
			fieldAdder.append(html);
		});
	}
	
});

var FinderSearcher = new FinderSearcherClass();


// AUTOCOMPLETE

AutocompleteHelperClass = Class.extend( 
{
	initialize : function()
	{
	},
	
	/**
	 * Binds autocomplete to dual-input value. 
	 * Your form is:
	 * [ DESCRIPTION (visible to user) |text] [ ID |hidden]
	 * !!! assumes ID is the first sibliding of description !!!
	 * 
	 * Then you supply HTML with results
	 * 		<span class="autocompleteRecord"><span class="autocompleteDescription"><span class="customerName autocompleteValueLabel">Jako Walski</span> <span class="companyName autocompleteValueLabel">Northslope.pl</span><span class="nip">NIP: 1865193297</span><span class="regon">REGON: 86398146627670</span></span><span class="autocompleteValue">1</span></span> 
	 * 		<span class="autocompleteRecord"><span class="autocompleteDescription"><span class="customerName autocompleteValueLabel">Sklep Itrzyowski</span> <span class="companyName autocompleteValueLabel">Isklepowo potrojne</span><span class="nip">NIP: 2016394860</span><span class="regon">REGON: 33633353342460</span></span><span class="autocompleteValue">4</span></span> 
	 * One record per line, wrapped in span.autocompleteRecord
	 *
	 * DESCRIPTION gets 'span.autocompleteValueLabel'
	 * ID gets 'span.autocompleteValue'
	 *
	 * Search results are build from span.autocompleteDescription - this span is inserted into LI of the result list
	 */
	bindTo : function( selector, resultsURL, afterResultHook, width, resultClass )
	{
		var acHelper = this;
		$(selector).autocomplete(
		ApplicationHelper.url( resultsURL ),
		{
			resultsClass : 'ac_results' + (resultClass ? ' ac_for_'+resultClass : ''),
			multiple: false, // only one value
			mustMatch: false, // will remove not matching text from input - as the inserted value will not be the same as entered
			autoFill: false, // as I enter nip, name, company but get only customer name 
			matchCase: false, // case insensitive
			matchContains: false,
			max: 25,
			minChars: 1,
			scrollHeight: 200,
			selectFirst: true, // will select first option on TAB/ENTER
			width: width ? width : 400,
			highlight: false,
			formatItem : function ( c, a, b, currentItem )
			{
				var html = acHelper.extractDescription( currentItem )
				return html;
			},
			
			formatResult : function( data, currentItem ) // FIXME remove bo to to samo
			{
				var html = acHelper.extractDescription( currentItem )
				return html;
			}
		});
		
		// after insert hook
		$(selector).bind( "result", afterResultHook );
	},
	
	
	defaultAfterResultHook : function( src, params, currentItem ) 
	{
		// [ object description visible to user ] [ object id ]
		//    ^^ description							^^ id
		var record = $(currentItem);
		var values = new Array();
		record.find('.autocompleteValueLabel').each( function( i, item ) 
		{
			values.push( $(item).text() ); // FIXME ?????????????
		});
		
		var description = values.join( " / " );
		var idr = record.find('.autocompleteValue');
		var id = idr.text();
		
		var descriptionInput = $(src.target);
		descriptionInput.val(description);
		descriptionInput.next('input').val(id);
	},
	
	extractDescription : function(currentItem)
	{
		var record = $(currentItem);
		var description = record.find('.autocompleteDescription'); // first span
		var html = description.html();
		return html;
	}
});


AutocompleteHelper = new AutocompleteHelperClass();


$(document).ready( function()
{
	$("body").ajaxError(function(event, xhr, ajaxOptions, thrownError) 
	{
		// redirect:/application/public/module/action/....
		var parts = xhr.responseText.split(/:/);
		if ( parts.length == 2 && parts[0] == "redirect" )
		{
			location.href = parts[1];
		}
	});
	
	// run default FinderSearcher search
	
	// put page=$_GET['page'] into FS form - it will be sent to 
	// it will be deleted after first search (performSearch())
	// with: $('#finderSearcher #searchPageNumber').remove(); // delete page number from the search form
	var GET = {};
	document.location.search.replace(/\??(?:([^=]+)=([^&]*)&?)/g, function () 
	{
    	function decode(s) 
    	{
        	return decodeURIComponent(s.split("+").join(" "));
    	}
	    GET[decode(arguments[1])] = decode(arguments[2]);
    });
    
    if ( GET['page'] )
    {
		$('#finderSearcher').prepend('<input type="hidden" id="searchPageNumber" name="page" value="' + $_GET['page'] + '" />');
	}
	$('#finderSearcher .search').click();
});