/*
 * Funkcje pomocnicze do zarządzania zdarzeniami -- nie są częścią interfejsu publicznego.
 * Propozycje związane z wieloma pomysłami obecnymi w bibliotece addEvent Deana Edwardsa.
 */
jQuery.event = {
	add: function( elem, types, handler, data, selector ) {

		var handleObjIn, eventHandle, tmp,
			events, t, handleObj,
			special, handlers, type, namespaces, origType,
			elemData = dataPriv.get( elem );

		// Zdarzenia nie mogą być kojarzone z węzłami bez danych lub węzłami tekstu/komentarza 
		// (zwykłe obiekty są jednak dozwolone)
		if ( !elemData ) {
			return;
		}

		// Element wywołujący może przekazać obiekt danych niestandardowych zamiast procedury obsługi
		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
			selector = handleObjIn.selector;
		}

		// Sprawdzenie, czy procedura obsługi ma unikatowy identyfikator 
    // używany później do znalezienia/usunięcia procedury
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Inicjowanie struktury zdarzeń i głównej procedury obsługi elementu, 
    // jeśli jest on pierwszym elementem
		if ( !( events = elemData.events ) ) {
			events = elemData.events = {};
		}
		if ( !( eventHandle = elemData.handle ) ) {
			eventHandle = elemData.handle = function( e ) {

				// Odrzucenie drugiego zdarzenia metody jQuery.event.trigger(),
				// gdy zdarzenie jest wywoływane po usunięciu strony z pamięci
				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
			};
		}

		// Obsługa wielu zdarzeń oddzielonych spacją
		types = ( types || "" ).match( rnotwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// *Musi* istnieć typ type. Nie są dołączane procedury obsługi tylko przestrzeni nazw
			if ( !type ) {
				continue;
			}

			// W wypadku zmiany typu zdarzenia należy użyć specjalnych procedur obsługi tego typu
			special = jQuery.event.special[ type ] || {};

			// Jeśli zdefiniowano selektor, należy określić specjalny typ interfejsu API zdarzeń
			// W przeciwnym razie jest to podany typ
			type = ( selector ? special.delegateType : special.bindType ) || type;

			// Aktualizowanie obiektu special na podstawie nowo zresetowanego typu
			special = jQuery.event.special[ type ] || {};

			// Obiekt handleObj jest przekazywany wszystkim procedurom obsługi zdarzeń
			handleObj = jQuery.extend( {
				type: type,
				origType: origType,
				data: data,
				handler: handler,
				guid: handler.guid,
				selector: selector,
				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
				namespace: namespaces.join( "." )
			}, handleObjIn );

			// Inicjowanie kolejki procedury obsługi zdarzeń, jeśli element jest pierwszym elementem
			if ( !( handlers = events[ type ] ) ) {
				handlers = events[ type ] = [];
				handlers.delegateCount = 0;

				// Użycie metody addEventListener tylko wtedy, gdy specjalna procedura obsługi zdarzeń
        // zwraca wartość false
				if ( !special.setup ||
					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {

					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Dodanie do listy procedur obsługi elementu (delegaty znajdują się na jej początku)
			if ( selector ) {
				handlers.splice( handlers.delegateCount++, 0, handleObj );
			} else {
				handlers.push( handleObj );
			}

			// Śledzenie na potrzeby optymalizacji zdarzeń tego, jakie zdarzenia były wcześniej używane
			jQuery.event.global[ type ] = true;
		}

	}
};