/**
 *	@fileoverview This file contains the markOphoto Class
 *
 *	@author Marco Todtenhaupt
*/

/**	Things you might wanna do:
 *	
 *	Edit the detailbox: @see gotDetails (line 247)
 *	Edit the form for marking persons: @see showMarkForm (line 322)
 *	Edit the personlist: @see markSaved (line 444)
 *
 */
 
/**
 *	Construct this class via {@link #getInstance}, for it should be used only one time.
 *	This implies the singleton design pattern, which is partly possible in JavaScript.
 *	@class This is the class which manages to mark specific persons in a photo.
 *	Please see database-structure for further information
 *	@constructor
 *	@param {String} photoId The id of the photo, where people should be marked in
 *	@param {String} photoCd The unique code of the current image identifiying it in the database
 *	@return a new markOphoto instance
 */

 
function markOphoto ( photoId , photoCd ) { 


	/**	
	 *	The path to the image that should be used for the marker
	 *	@private
	 *	@const
	 *	@type String
	 */
	var MARKERIMG = 'http://www.wo-war-ich-schon.de/images/marker-big.gif';

	/**	
	 *	Different variables that store often used HTML-Elements
	 *	@private
	 *	@type HTMLDomNode
	 */
	var photo = null;
	var marker = null;
	var markable = null;
	var markbtn = null;
	var details = null;

	/**	
	 *	Keeps hold of the pulsating effect on marker in order to cancel it asychronically
	 *	@private
	 *	@type Effect
	 */
	var pulsation = null;
	
	/**	
	 *	Tells wether a marking process is ongoing in order to prevent details shoing up
	 *	@private
	 *	@type Boolean
	 */
	var markInProgress = false;

	/**	
	 *	Stores the code of the photo, @see photoCd
	 *	@private
	 *	@type String
	 */
	var photoCode = null;
	
	/**	
	 *	The dimensions of the current photo where the marker could be placed
	 *	@private
	 *	@type Integer
	 */
	this.rMinX = 0;
	this.rMaxX = 0;
	this.rMinY = 0;
	this.rMaxY = 0;

	/**
	 *	By convention, we make a private that parameter. 
	 *	This is used to make the object available to the private methods. 
	 *	This is a workaround for an error in the ECMAScript Language Specification 
	 *	which causes this to be set incorrectly for inner functions.
	 * 	@private
	 *	@type markOphoto
	 */

	var that = this;


	/**
	 *	Returns the current horizontal position of an HTML-element
	 *	@param {DOMNode} elem The element, which position should be returned
	 *		if not set, the marker element would be used as default
	 *	@return the horizontal position in pixels
	 */	
	this.getX = function ( elem ) {
	 	if( !elem ) elem = marker; 
	 	var left = Prototype.Browser.Opera ? elem.style.left : elem.getStyle( "left" );
		return Math.floor( (Number)( left.substr( 0 , left.length - 2 ) ) + elem.getWidth()/2 );
	}

	/**
	 *	Returns the current vertical position of an HTML-element
	 *	@param {DOMNode} elem The element, which position should be returned
	 *		if not set, the marker element would be used as default
	 *	@return the vertical position in pixels
	 */	
	this.getY = function ( elem ) {
	 	if( !elem ) elem = marker; 
	 	var top = Prototype.Browser.Opera ? elem.style.top : elem.getStyle( "top" );;
		return Math.floor( (Number)( top.substr( 0 , top.length - 2 ) ) + elem.getHeight()/2 );
	}

	/**
	 *	Sets the horizontal position of the marker
	 *	@param {Integer} x The horizontal position in pixels
	 */	
	this.setX = function ( x ) {
	 	marker.setStyle( { left :  ( x - marker.getWidth()/2 ) + "px" } );
	}

	/**
	 *	Sets the vertical position of the marker
	 *	@param {Integer} y The vertical position in pixels
	 */	
	this.setY = function ( y ) {
	 	marker.setStyle( { top  :  ( y - marker.getHeight()/2 ) + "px" } );
	}

	/**
	 *	Checks, wether the marker is still in its constraints.
	 *	If not, puts it back in place
	 */	
	this.restrict = function() {

		if( that.getX() > that.rMaxX ) that.setX( that.rMaxX );
		if( that.getX() < that.rMinX ) that.setX( that.rMinX );
		if( that.getY() > that.rMaxY ) that.setY( that.rMaxY );
		if( that.getY() < that.rMinY ) that.setY( that.rMinX );
		
	}

	/**
	 *	Puts the marker to the center of the current picture
	 */	
	this.center = function() {

		that.setX( that.rMaxX / 2 );
		that.setY( that.rMaxY / 2 );
		
	}
	
	/**
	 *	Fades in the marker and lets it pulsate
	 */	
	this.showMe = function() {
	 	markInProgress = true;
	 	marker.show();
	 	marker.setOpacity( 1 );
		pulsation = Effect.Pulsate( marker.id , { pulses: 3, duration: 1 } );
	}

	/**
	 *	Fades out the marker
	 */	
	this.hideMe = function() {
	 	markInProgress = false;
		marker.hide();
	}

	/**
	 *	Initialises the GUI.
	 *	Calculates the constraints for the marker and hides it.
	 *	Afterwards shows the marking form, so that only users with JavaScript enabled will see it.
	 *	Also collects all markable Persons.
	 */	
	this.initNow = function ( ) {

		that.rMinX = 0;
		that.rMaxX = photo.width - 1;
		that.rMinY = 0;
		that.rMaxY = photo.height - 1;
		that.hideMe();
		that.showMarkForm();
		that.getMarkables();

	}

	/**
	 *	Hides the marker and waits for the photo to be loaded,
	 *	so the real initializing progress can be done.
	 *	@see initNow
	 */	
	this.init = function ( ) {
		
		that.hideMe();
		photo.observe( 'load' , that.initNow );
	}

	/**
	 *	Is called when an AJAX request removed the selected person from the database.
	 *	Removes the selected person from the screen.
	 *	@param {AJAXResponse} transport Is sent via AJAX-Request
	 */	
	this.markDeleted = function( transport ) {

	 	var result = transport.responseXML.getElementsByTagName( 'result' )[0];
		if( result.getAttribute('value') == 'false' ) {
			alert( 'Es ist ein Fehler aufgetreten.' );
		} else {
		 	
			$( 'mmOpUser-' + result.getAttribute('code') ).up('li').remove();
			$( 'mOpUser-' + result.getAttribute('code') ).remove();
			
			that.getMarkables();
			that.detailsOff();
		}

	}

	/**
	 *	Calls an AJAX request to delete the selecvted user from the database.
	 *	@param {Event} event The event that initiated the deleting process.
	 *	@see markDeleted
	 */	
	this.deleteMarked = function( event ) {
		
		/* Get the id of the person to be deleted */
		var element = event.element();
		var ids = element.id.split('-');
		if( ids[0] == 'mOpDelete' ) {
		 
			var jetzt = new Date();
			var url = 'http://www.wo-war-ich-schon.de/mark_delete.php?imagecode='  + encodeURIComponent( photoCode ) + '&user=' + encodeURIComponent( ids[1] ) + '&time=' + jetzt.getTime();
			new Ajax.Request( url, { method: 'get' , onSuccess: that.markDeleted } );
		}
	}
	
	/**
	 *	Is called when an AJAX request got the demanded details
	 *	Displays the detail box and fills it with information.
	 *	Here you can edit the HTML of the detailbox
	 *	@param {AJAXResponse} transport Is sent via AJAX-Request
	 */	
	this.gotDetails = function( transport ) {
	 
		var del = transport.responseXML.getElementsByTagName( 'users' )[0].getAttribute( 'delete' ) == 'yes';
		var users = transport.responseXML.getElementsByTagName( 'users' )[0].getElementsByTagName( 'user' );
		var markedcode = users[2].getAttribute('code');
		
		// Empty the detailsbox
		for( var i = that.details.childNodes.length ; i > 0 ; i-- )
			that.details.childNodes[0].remove();

		/* --- Here the HTML-Nodes are built -- */
		
		// Close-cross to hide the detailsbox
		var close = that.details.appendChild( new Element( 'img' , { 'src' : 'http://www.wo-war-ich-schon.de/images/close_mark.gif' , 'class' : 'close' } ) );
		close.observe( 'click' , that.detailsOff );
		
		// If the current user may delete the mark, the supposed image for this is displayed here
		if( del ) {

			var delet = that.details.appendChild( new Element( 'img' , { 'src' : 'http://www.wo-war-ich-schon.de/images/delete.gif' , 'class' : 'delete' , 'id' : 'mOpDelete-' + markedcode } ) );
			delet.observe( 'click' , that.deleteMarked );
			
		}
		
		var userpic = that.details.appendChild( new Element( 'img' , { 'src' : users[0].getAttribute('code'), 'height' : '60', 'width' : '40'} ) );
		// The name and the profilelink of the selected person
		var a = that.details.appendChild( new Element( 'a' , { 'href' : 'http://www.wo-war-ich-schon.de/'+users[2].getAttribute('name') , 'class' : 'mOpMarkedName' } ) );
		a.appendChild( new Element( 'strong' , {  } ) ).update( users[2].getAttribute('name') );	

		// The marker of the current person and a link to its profile
		var amarker = that.details.appendChild( new Element( 'div' , { 'class' : 'mOpMarkerName' } ) ).update( 'Markierer:' );
		var a = amarker.appendChild( new Element( 'a' , { 'href' : 'http://www.wo-war-ich-schon.de/'+users[1].getAttribute('name') } ) ).update( users[1].getAttribute('name') );	
		
		new Effect.Appear( that.details );
		
		// Position of the detailsbox
		var px = that.getX( $( 'mOpUser-' + markedcode ).down('.marker') ) - Math.floor( that.details.getWidth() / 2 );
		var py = that.getY( $( 'mOpUser-' + markedcode ).down('.marker') ) + 10;
		new Effect.Move( that.details , { x : px , y : py , duration: 0 , mode: 'absolute' } );

	}
	
	
	/**
	 *	Calls an AJAX request to fetch the details of a selected person.
	 *	@param {Event} event The event that initiated the detail process.
	 *	@see gotDetails
	 */	
	this.detailsOn = function ( event ) { 

		if( !markInProgress ) {
			var element = event.element();
			// if( element.nodeName == 'DIV' ) 
			element = element.parentNode;
			
			var ids = element.id.split('-');
			if( ids[0] == 'mOpUser' ) {
				var jetzt = new Date();
				var url = 'http://www.wo-war-ich-schon.de/mark_details.php?imagecode='  + encodeURIComponent( photoCode ) + '&user=' + encodeURIComponent( ids[1] ) + '&time=' + jetzt.getTime();
				new Ajax.Request( url, { method: 'get' , onSuccess: that.gotDetails } );
			}
		}
	}
	
	/**
	/* Modi Benni  */
	
	this.detailsOnStart = function ( event ) { 

		if( !markInProgress ) {
			var element = event.element();
			// if( element.nodeName == 'DIV' ) 
			// element = element.parentNode;
			var ids = element.id.split('-');
			if( ids[0] == 'mmOpUser' ) {
				var jetzt = new Date();
				var url = 'http://www.wo-war-ich-schon.de/mark_details.php?imagecode='  + encodeURIComponent( photoCode ) + '&user=' + encodeURIComponent( ids[1] ) + '&time=' + jetzt.getTime();
				new Ajax.Request( url, { method: 'get' , onSuccess: that.gotDetails } );
			}
		}
	}
	
	/**
	 *	Hides the detailbox
	 *	@param {Event} event The event that initiated the hiding process.
	 */	
	this.detailsOff = function ( event ) { 

		new Effect.Fade( that.details , { duration : 0.5 } );

	}
		
	/**
	 *	Shows the form, where the user can select a person and mark it.
	 */	
	this.showMarkForm = function() {
		
		/* --- Here the HTML-Nodes are built -- */

		// Append new li and form 
		$('mOpMarkedFriends').appendChild( new Element( 'li' , { 'class' : 'heading margin' } ) ).update('Freund markieren:');
		var frm = $('mOpMarkedFriends').appendChild( new Element( 'form' , { 'action' : 'http://www.wo-war-ich-schon.de/index.html' , 'method' : 'post' , id : 'mOpForm' } ) );
		// The combobox with the persons
		that.markable = frm.appendChild( new Element( 'select' , { 'disabled' : 'disabled' , 'name' : 'mOpSelectFriend' , id : 'mOpSelectFriend' } ) );
		// The button
		that.markbtn = frm.appendChild( new Element( 'input' , { 'disabled' : 'disabled' , 'type' : 'submit' , 'value' : 'Lade Personen...' , id : 'mOpMark' } ) );
		
		// The detailbox, just an empty box, for its content @see gotDetails
		that.details = $("mOpPhotoFrame").appendChild( new Element( "div" , { "id" : "mOpDetails" } ) );
		that.details.setStyle({ display: 'none' });
		
		// Observe the mouseovers on each person in the list.
		// Observe FotoFrame
		var markedfriends 		= $$( '.mOpMarkedFriend' );
		var markedfriendsStart 	= $$( '.mOpMarkedFriendStart' );
		
		for( var i = 0 ; i < markedfriends.length ; i++ ){
			var ids = markedfriends[i].id.split('-');
			if( ids[0] == 'mOpUser' ) {	
				markedfriends[i].observe( 'mouseover' , that.detailsOn );
				markedfriendsStart[i].observe( 'mouseover' , that.detailsOnStart );
			}
		}
			
	}
	
	/**
	 *	Calls an AJAX request to fetch the markable persons on the current photo.
	 *	@see gotMarkables
	 */	
		this.getMarkables = function() {
		
		that.markbtn.setAttribute( 'value' , 'Lade Personen...' );
		var jetzt = new Date();
		var url = 'http://www.wo-war-ich-schon.de/mark_marker.php?imagecode='  + encodeURIComponent( photoCode ) + '&time=' + jetzt.getTime();
		new Ajax.Request( url, { method: 'get' , onSuccess: that.gotMarkables } );
		
		/* MOD: SPEICHERN F�R ONMOUSE OVER */
		hed = $$('div.marker');
		hed.each(function(element) 
					{
						element.addClassName('markerShow');
					});
	 
	}

	/**
	 *	Is called when an AJAX request got the demanded markable persons
	 *	Displays them in the combobox
	 *	@param {AJAXResponse} transport Is sent via AJAX-Request
	 */	
	this.gotMarkables = function( transport ) {
	
		var users = transport.responseXML.getElementsByTagName( 'users' )[0].getElementsByTagName( 'user' );

		// Remove all persons from combobox
		for( var i = that.markable.childNodes.length ; i > 0 ; i-- )
			that.markable.childNodes[0].remove();
		
		// Add the new fetched persons
		for( var i = 0 ; i < users.length ; i++ ){
			that.markable.appendChild( new Element( 'option' , { 'value' : users[i].getAttribute('code') } ) ).update( users[i].getAttribute('name') + '&nbsp;' );	
		}

		// If there are persons left to be marked, enable the box
		if( i > 0 ) {
			that.markable.removeAttribute( 'disabled' );
			that.markbtn.removeAttribute( 'disabled' );
			that.markbtn.setAttribute( 'value' , 'Person markieren' );
			$('mOpMark').observe('click', that.startMark );
		} else {
			
			that.markbtn.setAttribute( 'value' , 'Keine Personen gefunden' );
			
		}
	
	}
		
	/**
	 *	Starts the marking-process, e.g. show the marker and stop the personselection
	 *	@param {Event} event The event that initiated the marking process.
	 */	
	this.startMark = function ( event ) {
		
		that.center();
		that.showMe();
		that.detailsOff();
		that.markbtn.setAttribute( 'value' , 'Person speichern' );
		that.markable.setAttribute( 'disabled' , 'disabled' );
		$('mOpMark').stopObserving('click', that.startMark );
		$('mOpMark').observe('click', that.saveMark );
		Event.stop( event );
		return false;
		
	}

	/**
	 *	Calls an AJAX request to save the mark that has be done
	 *	@param {Event} event The event that initiated the saving process.
	 *	@see markSaved
	 */	
	this.saveMark = function ( event ) {
		
		that.hideMe();
		that.markbtn.setAttribute( 'value' , 'Speichere Position...' );
		that.markbtn.setAttribute( 'disabled' , 'disabled' );
		var jetzt = new Date();
		var url = 	'http://www.wo-war-ich-schon.de/mark_save.php?imagecode=' + encodeURIComponent( photoCode ) + 
					'&person='  + encodeURIComponent( that.markable.value ) + 
					'&x='  + encodeURIComponent( that.getX() ) + 
					'&y='  + encodeURIComponent( that.getY() ) + 
					'&time=' + jetzt.getTime();

		$('mOpMark').stopObserving('click', that.saveMark );
				
		new Ajax.Request( url, { method: 'get' , onSuccess: that.markSaved } );
		
		Event.stop( event );
		return false;
		
	}	

	/**
	 *	Is called when an AJAX request saved the mark
	 *	Displays it in the personlist and adds a marker on the picture for it
	 *	Here you can edit the HTML of the detailbox
	 *	@param {AJAXResponse} transport Is sent via AJAX-Request
	 */	
	this.markSaved = function( transport ) {

	 	var result = transport.responseXML.getElementsByTagName( 'result' )[0];
		if( result.getAttribute('value') == 'false' ) {
			alert( 'Es ist ein Fehler aufgetreten.' );
		} else {

			/* --- Here the HTML-Nodes are built -- */

			// A new li for the person
		 	var newPerson = new Element( 'li' );
			 Element.insert( $('mOpForm').previous('li', 1) , { 'after' : newPerson } );
			var person = that.markable[that.markable.selectedIndex].text.strip();			
			// A link with the markerimg in it, according to the real HTML
			var a = newPerson.appendChild( new Element( 'a' , { 'class' : 'mOpMarkedFriendStart' , 'id' : 'mmOpUser-' + result.getAttribute('code') , 'href' : 'http://www.wo-war-ich-schon.de/user_profil.php?user_code='+ result.getAttribute('code') , 'title' : person } ) ).update( person );

			// Observe the mouseover for the detailbox
			a.observe( 'mouseover' , that.detailsOnStart );
			
			var adiv = new Element( 'a' , { 'class' : 'mOpMarkedFriend' , 'id' : 'mOpUser-' + result.getAttribute('code') , 'href' : 'http://www.wo-war-ich-schon.de/user_profil.php?user_code='+ result.getAttribute('code') , 'title' : person } );
			Element.insert( $('mOpPicture'), { 'after' : adiv } );
			adiv.observe( 'mouseover' , that.detailsOn );
			// Observe the mouseover for the detailbox
			/* a.observe( 'mouseover' , that.detailsOnStart );
			var div = new Element( 'div' , { 'class' : 'marker' } );
			Element.insert( $('mOpPhotoFrame'), { 'after' : div } ); */
			
			var div = adiv.appendChild( new Element( 'div' , { 'class' : 'marker' } ) );
			// Set the position of the marker according to the database
			div.setStyle( { 'left' : result.getAttribute('x') + 'px' , 'top' : result.getAttribute('y') + 'px' } );
			
			// Refresh the markable persons
			that.getMarkables();
		}

	}

	/**
	 *	Cancel the pulsation effect on the marker, for example when its dragged
	 */	
	this.cancelPulsation = function () {
		
		if( pulsation != null ) pulsation.cancel();
		marker.setOpacity( 1 );	
		
	}
	
	// Save the infromation about the photo
	photoCode = photoCd;	
	photo = $(photoId);

	// Add the marker and make it draggable
	marker = $("mOpPhotoFrame").appendChild( new Element( "img" , { "id" : "mOpMarker" , "src" : "http://www.wo-war-ich-schon.de/images/marker-big.gif" } ) );
	new Draggable( 'mOpMarker' , { revert: false , onStart: that.cancelPulsation , change: that.restrict } );		
//
	// Initialize the markOphoto script	
	that.init( photo );

}

/**
 *	Holds the single instance of markOphoto.
 *	Belongs to the singleton design pattern.
 *	See {@link #getInstance}
 *	@member markOphoto
 *	@type markOphoto
 */
markOphoto.instance = null;

/**
 *	Returns the one and only instance of markOphoto.
 *	Use this as a constructor.
 *	Belongs to the singleton design pattern.
 *	@param {String} photoId The id of the photo, where people should be marked in
 *	@param {String} photoCd The unique code of the current image identifiying it in the database
 *	@return The markOphoto instance
 */
markOphoto.getInstance = function ( photoId , photoCode ) {
	if( this.instance == null )
		this.instance = new markOphoto( photoId , photoCode );
	return this.instance;		
}

