/**
 * Możliwe opcje (* - ozn. wymagany):
 *
 * cityFormElement		 - * element select formularza przechowywujący miasta
 * streetFormElement	 - * element input formularza dla ulicy
 * bnrFormElement		 - * element input formularza dla numeru budynku
 * searchButton			 - * element input submit
 * onCreate				 - * funkcja zwrotna wywoływana gdy ktoś naciśnie przycisk "utwórz wspólnotę" (wysyłanie formularza)
 * prefixCity			 - prefix do wyświetlania przed tekstową nazwą miasta (np. "Miasto ")
 * prefixStreet			 - jw.
 * confirmView			 - czy po wysłaniu żądania wyszukiwania zakończonego nie znalezieniem wspólnoty ma być dostępny ekran na ewentualną korektę danych? (domyślnie false)
 * cityLabelHandler		 - obiekt jakiegoś znacznika (np. p lub div) przechowywujący etykietę miasta w trybie tekstowym
 * streetLabelHandler	 - jw.
 * changeButtonHandler	 - jw. (dotyczy przycisku "zmień")
 * divNoticeHandler		 - jw. (dotyczy notatki)
 * createButtonHandler	 - jw. (dotyczy przycisku "utwórz")
 * searchButtonLabel	 - domyślna etykieta dla przycisku "szukaj"
 * changeButtonLabel	 - jw. - tylko że dla linku "zmień"
 * createButtonLabel	 - jw. - tylko że dla linku "utwórz"
 * preCallback			 - funkcja zwrotna wykonywana przed żądaniem ajax, domyślnie pusta tablica
 * midCallback			 - funkcja zwrotna wykonywana w czasie żądania ajax, domyślnie pusta tablica
 * postCallback			 - funkcja zwrotna wykonywana po żądaniu ajax, domyślnie pusta tablica
 * cityLabel			 - etykieta przechowywująca nazwę miasta, domyślnie element h4
 * streetLabel			 - etykieta przechowywująca ulicę i nr budynku, domyślnie element h4
 * textModeCallback		 - funkcja zwrotna wykonywana podczas przechodzenia do trybu tekstowego
 * formModeCallback		 - funkcja zwrotna wykonywana podczas przechodzenia do trybu formularza
 * createButtonClass	 - klasa przycisku "utwórz"
 * changeButtonClass	 - jw.
 * createButtonId		 - id przycisku "utwórz"
 * changeButtonId		 - jw.
 * 
 * @param options
 */
function Community(options){
	var oThis = this;
	try{
		//poszczególne elementy formularza
		this.cityFormElement = this.setRequiredParameter(options.cityFormElement);
		this.streetFormElement = this.setRequiredParameter(options.streetFormElement);
		this.bnrFormElement = this.setRequiredParameter(options.bnrFormElement);
		this.searchButton = this.setRequiredParameter(options.searchButton);
		
		//funkcja zwrotna wykonywana po kliknięciu w przycisk "utwórz" gdy wspólnota nie została znaleziona
		this.onCreate = this.setRequiredParameter(options.onCreate);
	}catch(e){
		alert("Błąd: "+e.message);
	}

	
	//prefiksy oraz suffiksy miasta i ulicy w trybie tekstowym
	this.prefixCity = this.setParameter(options.prefixCity, "");
	this.prefixStreet = this.setParameter(options.prefixStreet, "");	
	this.suffixCity = this.setParameter(options.suffixCity, "");
	this.suffixStreet = this.setParameter(options.suffixStreet, "");
	

	this.bnrAutocomplete = this.setParameter(options.bnrAutocomplete, false);
	if(this.bnrAutocomplete){
		this.bnrAutocompleteUrl = this.setRequiredParameter(options.bnrAutocompleteUrl);
		this.bnrAutocompleteIgnoreStreet = this.setParameter(options.bnrAutocompleteIgnoreStreet, "");
		this.bnrAutocompleteIgnoreCity = this.setParameter(options.bnrAutocompleteIgnoreCity, "");
		
		this.initAutocomplete();		
	}
	
	//czy widok potwierdzenia danych wspólnoty ma być aktywny?
	this.confirmView = this.setParameter(options.confirmView, false);
	
	//obecny adres (id miasta, nazwa ulicy i nr budynku)
	this.city_id = this.setParameter(options.city_id, "");
	this.street = this.setParameter(options.street, "");
	this.bnr = this.setParameter(options.bnr, "");
	
	//handlery dla różnych etykiet, przycisków itp.
	this.cityLabelHandler = this.setParameter(options.cityLabelHandler, this.cityFormElement.parent());
	this.streetLabelHandler = this.setParameter(options.streetLabelHandler, this.streetFormElement.parent());
	this.changeButtonHandler = this.setParameter(options.changeButtonHandler);
	this.divNoticeHandler = this.setParameter(options.divNoticeHandler);
	this.createButtonHandler = this.setParameter(options.createButtonHandler);
	
	//etykieta dla przycisków
	this.searchButtonLabel = this.setParameter(options.searchButtonLabel, "szukaj");
	this.changeButtonLabel = this.setParameter(options.changeButtonLabel, "zmień");
	this.createButtonLabel = this.setParameter(options.createButtonLabel, "utwórz wspólnotę");
		
	//tryb: 0 - formularz, 1 - tekstowy
	this.mode = this.setParameter(options.mode, 0);
	
	this.aPreCallbacks = new Array();
	this.aPostCallbacks = new Array();
	this.aMidCallbacks = new Array();
	
	//dodanie funkcji zwrotnych, pre/post/midCallback są tablicami, więc można ustawić wiele f. zwrotnych
	options.preCallback ? this.aPreCallbacks.push(options.preCallback) : null;
	options.postCallback ? this.aPostCallbacks.push(options.postCallback) : null;
	options.midCallback ? this.aMidCallbacks.push(options.midCallback) : null;
	this.textModeCallback = this.setParameter(options.textModeCallback);
	this.formModeCallback = this.setParameter(options.formModeCallback);
	
	//id elementów formularza
	this.cityId = this.cityFormElement.attr("id");
	this.streetId = this.streetFormElement.attr("id");
	this.bnrId = this.bnrFormElement.attr("id");

	//etykiety dla trybu tekstowego
	this.cityLabel = options.cityLabel ? options.cityLabel : $("<h4 id='text_"+this.cityId+"'></h4>").appendTo(this.cityLabelHandler);
	this.streetLabel = options.streetLabel ? options.streetLabel : $("<h4 id='text_"+this.streetId+"'></h4>").appendTo(this.streetLabelHandler);
	
	this.noticeHandler = null;
	
	//możliwe wysłanie żądanie?
	this.sendable = false;	

	this.first = true;

	//elementy przechowywujące błędy
	this.cityError = this.setParameter(options.cityError, $("#error_"+this.cityId));
	this.streetError = this.setParameter(options.streetError, $("#error_"+this.streetId));
	this.bnrError = this.setParameter(options.bnrError, $("#error_"+this.bnrId));
	this.globalError = this.setParameter(options.globalError, $("#error_community_global"));
	
	//id oraz klasy przycisków
	this.createButtonId = this.setParameter(options.createButtonId, "createButton");
	this.changeButtonId = this.setParameter(options.changeButtonId, "changeButton");
	this.createButtonClass = this.setParameter(options.createButtonClass, "Button Strong");
	this.changeButtonClass = this.setParameter(options.changeButtonClass, "");
	
	this.changeButton = $("<a id='"+this.changeButtonId+"' class='"+this.changeButtonClass+"'>"+this.changeButtonLabel+"</a>").appendTo(this.changeButtonHandler == null ? this.searchButton.parent() : this.changeButtonHandler).click(function(e){
		oThis.formMode();
		e.preventDefault();
	});
	
	this.changeButton = this.setParameter(this.changeButtonHandler, this.changeButton);
	this.changeButton.hide();
	
	var isDefNoticeHandler = options.noticeHandler ? false : true;
	this.noticeHandler = this.setParameter(options.noticeHandler, $("<p>Wspólnota nie została zarejestrowana. Bądź pierwszy i załóż wspólnotę!</p>"));
	this.noticeHandler.hide();
	if(isDefNoticeHandler)
		this.noticeHandler.appendTo(this.divNoticeHandler == null ? this.searchButton.parent() : this.divNoticeHandler);
	
	this.createButton = $("<a class='"+this.createButtonClass+"' id='"+this.createButtonId+"'><span>"+this.createButtonLabel+"</span></a>").appendTo(this.searchButton.parent()).hide().click(function(e){
		e.preventDefault();
		oThis.onCreate.call();
	});
}

/**
 * Metoda inicjalizująca widok widgetu
 */
Community.prototype.initialize = function(){
	if(this.city_id != "" && this.street != "" && this.bnr != ""){
		this.cityFormElement.val(this.city_id);
		this.streetFormElement.val(this.street);
		this.bnrFormElement.val(this.bnr);
		
		this.textMode();
	}else{
		this.formMode();
	}
};

/**
 * Inicjacja autocomplete dla numeru(/ów) wspólnoty
 */
Community.prototype.initAutocomplete = function(){
	if(this.bnrAutocomplete){
		var oThis = this;
		var autocomplete = this.bnrFormElement.autocomplete(this.bnrAutocompleteUrl, {
			extraParams: {
				city_id: function(){ return oThis.cityFormElement.val(); },
				street: function(){ return oThis.streetFormElement.val(); }
			},
			max: 20,
			delay: 10,
			hideOnNoRequest: false,
			//możliwość "anulowania" żądania dla niektórych danych
			formatWord: function(word) {
				if(oThis.streetFormElement.val() == oThis.bnrAutocompleteIgnoreStreet
					|| oThis.cityFormElement.val() == "" || oThis.cityFormElement.val() == oThis.bnrAutocompleteIgnoreCity
					|| oThis.streetFormElement.val() == ""){
					
					return "";
				}
				var lastChar = word.substr(word.length - 1);
				return (lastChar == ',' || lastChar == '-') ? word : "";
			},
			highlight: function(value, term) {
				return value;
			},
			width: "300px",
			minChars: 2			
		});
	}
}

/**
 * Ustaw funkcję zwrotną wykonywaną po żądaniu ajax
 */
Community.prototype.setPostCallback = function(callback){
	this.aPostCallbacks.push(callback);
};

/**
 * Ustaw funkcję zwrotną wykonywaną przed żądaniem ajax
 */
Community.prototype.setPreCallback = function(callback){
	this.aPreCallbacks.push(callback);
};

/**
 * Ustaw funkcję zwrotną wykonywaną gdy istnieje już wspólnota
 * o podanych danych
 */
Community.prototype.setMidCallback = function(callback){
	this.aMidCallbacks.push(callback);
};

/**
 * Czy formularz może wysłać żądanie? Zwraca true jeśli
 * dane są poprawne i nie istnieje jeszcze podana wspólnota
 */
Community.prototype.isSendable = function(){
	return this.sendable;
};

/**
 * Pobiera nazwę miasta
 */
Community.prototype.getCityName = function(cityId){
	if(cityId != null)	$("#"+this.cityId).val(cityId);
	return $("#" + this.cityId + " :selected").text();
};

/**
 * Zmienia zaznaczone miasto
 */
Community.prototype.setCityName = function(name){
	$("#" + this.cityId + " :selected").attr("selected", "");
	$("#" + this.cityId + " :contains("+name+")").attr("selected", "selected");
};

/**
 * Pobiera nazwę ulicy z doklejonym numerem budynku
 */
Community.prototype.getStreetName = function(street, bnr){
	if(street != null) this.streetFormElement.val(street);
	if(bnr != null) this.bnrFormElement.val(bnr);
	return this.streetFormElement.val()+" "+this.bnrFormElement.val();
};

/**
 * Włącza tryb tekstowy. Wywoływać tylko gdy dane są zweryfikowane
 */
Community.prototype.textMode = function(params){
	if(this.textModeCallback != null) this.textModeCallback.call();
	
	this.sendable = true;
	this.cityFormElement.hide();
	this.streetFormElement.hide();
	this.bnrFormElement.hide();
	this.searchButton.hide();
	this.errorsHide();
	var cityName = this.getCityName(params != null ? params.city_id : null);
	var streetName = this.getStreetName(params != null ? params.street : null, params != null ? params.bnr : null);
	this.cityLabel.show().html(this.prefixCity+cityName+this.suffixCity);
	this.streetLabel.show().html(this.prefixStreet+streetName+this.suffixStreet);

	if(this.mode){
		this.createButton.hide();
	}else{
		this.createButton.show();
		this.noticeHandler.show();
	}
	this.changeButton.show();
};

Community.prototype.setTextModeCallback = function(callback){
	this.textModeCallback = callback;
};

Community.prototype.setFormModeCallback = function(callback){
	this.formModeCallback = callback;
};

/**
 * Przełącza w tryb formularza, możliwa edycja danych
 */
Community.prototype.formMode = function(){
	if(this.formModeCallback != null) this.formModeCallback.call();
	this.sendable = false;
	this.cityLabel.hide();
	this.streetLabel.hide();
	this.changeButton.hide();
	this.createButton.hide();
	this.cityFormElement.show();
	this.streetFormElement.show();
	this.bnrFormElement.show();
	this.searchButton.show();
	this.noticeHandler.hide();
};

/**
 * Wywołuje żądanie ajax i odpowiednio na nie reaguje
 */
Community.prototype.process = function(url){
	for(var i=0; i< this.aPreCallbacks.length; i++){
		(this.aPreCallbacks[i]).call();
	}

	this.freeze();
	
	var query = "community[city_id]="+encodeURIComponent(this.cityFormElement.val());
	query += "&community[street]="+encodeURIComponent(this.streetFormElement.val());
	query += "&community[bnr]="+encodeURIComponent(this.bnrFormElement.val());
	
	var first = true;
	var oThis = this;

	$.getJSON(url, query, function(json){
		if(json.hasError == 1){
			for(key in json.error){
				oThis.error(key, json.error[key], json);
			}
			
			if(json.global == 1){
				oThis.error(0, json.error[0]);
				for(var i=0; i<oThis.aMidCallbacks.length; i++){
					oThis.aMidCallbacks[i].call(null, json);
				}
			}
		}else{
			if(oThis.confirmView){
				oThis.textMode(json.params);
			}else{
				oThis.freeze();
				oThis.sendable = true;
				//walkaround - gdy wywoływało się bezpośredion onCreate
				//wysyłany był pusty formularz
				setTimeout(oThis.onCreate, 100);
			}
		}
		oThis.restore();

		for(var i=0; i< oThis.aPostCallbacks.length; i++){
			oThis.aPostCallbacks[i].call();
		}
	});	

};

/**
 * Obsługa błędów. Jeżli błąd ma inny indeks jak odpowiednie pola
 * to znaczy że jest to błąd globalny i że wspólnota o podanych danych
 * już istnieje
 */
Community.prototype.error = function(field, content){
	if(field == "bnr") this.bnrError.html(content).show();
	else if(field == "street") this.streetError.html(content).show();
	else if(field == "city_id") this.cityError.html(content).show();
	else this.globalError.html(content).show();
};


/**
 * Zamra�a formularz (wszystkie pola są niedostępne)
 */
Community.prototype.freeze = function(){
	this.cityFormElement.attr("disabled", "disabled");
	this.streetFormElement.attr("disabled", "disabled");
	this.bnrFormElement.attr("disabled", "disabled");
	this.searchButton.attr("disabled", "disabled");
	this.errorsHide();
};

/**
 * Działanie odwrotne do Community.freeze()
 */
Community.prototype.restore = function(){
	this.cityFormElement.attr("disabled", "");
	this.streetFormElement.attr("disabled", "");
	this.bnrFormElement.attr("disabled", "");
	this.searchButton.attr("disabled", "");
};

/**
 * Chowa etykiety błędów
 */
Community.prototype.errorsHide = function(){
	this.cityError.hide();
	this.streetError.hide();
	this.bnrError.hide();
	this.globalError.hide();
};

Community.prototype.setParameter = function(value, def){
	if(def == undefined)
		def = null;
	
	return (value != undefined ? value : def);
};

Community.prototype.setRequiredParameter = function(value){
	if(!value)
		throw new myException("Nie ustawiono jednego z wymaganych parametrów klasy 'Community'.");
	
	return value;
};

function myException(message){
	this.message = message;
}
