var tracker_entry = function ( tracker, form )
{
	
	this.tracker = tracker ;
	this.form = form ;
	
	this.operation_on_entry_start = function ( message )
	{
		this.tracker.stop_update_timeout () ;
		this.form.find ( '#actions td button' ) . attr ( 'disabled', true ) ;
		this.form.find ( 'td *' ) . attr ( 'disabled', true ) ;
		this.form.find ( '#actions' ) . hide () ;
		this.form.find ( 'tr#status td:eq(1)' ) . html ( message ) ;
		this.form.find ( 'tr#status' ) . show () ;
	}

	this.operation_on_entry_failed = function ( message )
	{
		var $this = this ;
		
		this.form.find ( '#actions td button' ) . attr ( 'disabled', false ) ;
		this.form.find ( 'td *' ) . attr ( 'disabled', false ) ;
		this.form.find ( 'tr#status td:eq(1)' ) . html ( message ) ;
		setTimeout ( function(){
			$this.form.find ( 'tr#status' ) . fadeOut ( 'slow', function(){
				$this.form.find ( '#actions' ) . show () ;
				$this.tracker.start_update_timeout () ;
			}) ;
		}, 1000 ) ;
	}

	this.destroy_entry = function ( id )
	{
		var $this = this ;
		
		$.ajax ({

			url: _self + '/' + id + '/destroy',
			dataType: 'json',

			beforeSend: function () {
				$this.operation_on_entry_start ( _( 'destroying_entry' ) ) ;
			},

			success: function ( id ) {
				if ( id )
				{
					$this.form.find ( 'tr#status td:eq(1)' ) . html ( _( 'destroying_entry_success' ) ) ;

					$this.form.find ( 'tr#status' ) . fadeOut ( 'slow', function(){
						tb_remove () ;
						$this.tracker.start_update_timeout () ;

						$this.tracker.entry_list_remove ( id ) ;
					})
				}
				else
					$this.operation_on_entry_failed ( _( 'destroying_entry_failed' ) ) ;
			},

			error: function () {
				$this.operation_on_entry_failed ( _( 'destroying_entry_failed' ) ) ;
			}

		}) ;
	}

	this.construct = function ()
	{

		var $this = this ;

		this.form.find ( 'tr#status' ).hide () ;
		this.form.find ( '#subject' ).focus () ;
		this.form.find ( '#actions .delete' ).click (function(){
			$this.destroy_entry ( parseInt ( this.id ) ) ;
		}) ;

		$( this.form ) . ajaxForm ({

			dataType: 'json',

			beforeSubmit: function () {
				$this.operation_on_entry_start ( _( 'saving_entry' ) ) ;
			},

			success: function ( data ) {
				$this.tracker.start_update_timeout () ;
				
				if ( data.html )
					$this.form.find ( 'tr#status td:eq(1)' ) . html ( _( 'saving_entry_success' ) ) ;
				else if ( data.id )
					$this.form.find ( 'tr#status td:eq(1)' ) . html ( _( 'saving_entry_success' ) ) ;
				else
					return $this.operation_on_entry_failed ( _( 'saving_entry_failed' ) ) ;

				$this.form.find ( 'tr#status' ) . fadeOut ( 'slow', function(){
					tb_remove () ;

					if ( data.html )
						$this.tracker.entry_list_append ( data.html, data.timestamp ) ;
					else if ( data.id )
						$this.tracker.entry_list_change ( data.id, data, data.timestamp ) ;
				})
			},

			onError: function () {
				$this.operation_on_entry_failed ( _( 'saving_entry_failed' ) ) ;
			}

		}) ;
		
		return this ;

	} ;
	
	return this.construct () ;
	
}

var tracker = function ( entry_list, pager, entry_list_timestamp )
{
	
	this.entry_list_timestamp = entry_list_timestamp ;
	this.entry_list_timeout = null ; // timer for periodic ajax call
	this.entry_list_errors = 0 ; // connection error counter
	this.entry_list_update_interval = 60000 ;
	this.entry_list = entry_list ;
	this.pager = pager ;

	this.entry_init_form = function ( form )
	{
		new tracker_entry ( this, form ) ;
	}

	this.entry_edit = function ( row )
	{
		var id = parseInt ( row.id ) ;
		var subject = $( row ).find ( '#subject' ).html () ;
		tb_show ( '#' + id + ': ' + subject, _self + '/' + id + '/view?width=700&amp;height=500' ) ;
	}

	this.flash_list_entry = function ( id )
	{
		var id = id ;
		var obj = $( '#' + id + ' td' ) ;
		var bg = obj.css ( 'backgroundColor' ) ;
		var $this = this ;
		var flash_offset = config.size - this.entry_list.find ( 'tbody tr' ).index ( $( '#' + id ).get(0) ) ;
		obj.css ( 'backgroundColor', 'rgb(245,230,200)' ) ;
		setTimeout ( function(){
			obj.animate ({
				backgroundColor: bg == 'transparent' ? 'rgb(255,255,255)' : bg
			}, 'slow', 'swing', function(){
				obj.css ( 'backgroundColor', '' ) ;
			} ) ;
		}, 1000 + flash_offset*200 ) ;
	}

	this.entry_list_change = function ( id, data, new_timestamp )
	{
		if ( typeof new_timestamp != 'undefined' )
			this.entry_list_timestamp = Math.max ( this.entry_list_timestamp, new_timestamp ) ;

		var page_size = config.size, cur_page = config.page, pos_fixed = config.positionFixed ;
		this.entry_list.tablesorterPager ({ size: config.totalRows, page: 0, positionFixed: pos_fixed }) ;
		var field, fields = $( '#' + data.id + ' > td' ) ;
		for ( field in fields )
		{
			field = fields [ field ] ;
			field.innerHTML = data [ field.id ] ;
		}
		this.entry_list.trigger ( 'update' ) ;
		this.entry_list.trigger ( 'sorton', [ config.sortList ]) ;
		this.entry_list.tablesorterPager ({ size: page_size, page: cur_page, positionFixed: pos_fixed }) ;

		this.flash_list_entry ( id ) ;
	}

	this.entry_list_remove = function ( id )
	{
		var $this = this ;
		
		$( '#' + id ).fadeOut ( 'slow', function(){
			var page_size = config.size, cur_page = config.page, pos_fixed = config.positionFixed ;
			$this.entry_list.tablesorterPager ({ size: config.totalRows, page: 0, positionFixed: pos_fixed }) ;
			$( '#' + id ).remove () ;
			$this.entry_list.trigger ( 'update' ) ;
			$this.entry_list.trigger ( 'sorton', [ config.sortList ]) ;
			$this.entry_list.tablesorterPager ({ size: page_size, page: cur_page, positionFixed: pos_fixed }) ;

			if ( config.totalPages < cur_page+1 )
				$this.entry_list.tablesorterPager ({ size: page_size, page: Math.max ( 0, config.totalPages-1 ), positionFixed: pos_fixed }) ;
		}) ;
	}

	this.entry_list_append = function ( items, new_timestamp )
	{
		var item, id, $this = this ;

		if ( typeof new_timestamp != 'undefined' )
			this.entry_list_timestamp = Math.max ( this.entry_list_timestamp, new_timestamp ) ;

		if ( typeof items != 'Array' )
			items = $( items ).get () ;

		var page_size = config.size, cur_page = config.page, pos_fixed = config.positionFixed ;
		this.entry_list.tablesorterPager ({ size: config.totalRows, page: 0, positionFixed: pos_fixed }) ;
		for ( item in items )
		{
			item = items [ item ] ;
			id = $(item).attr ( 'id' ) ;
			if ( id )
			{
				$( '#' + id ).remove () ;
				$( item ).click (function(){ $this.entry_edit ( this ) ; }) ;
				this.entry_list.find ( 'tbody' ).append ( item ) ;
			}
		}
		this.entry_list.trigger ( 'update' ) ;
		this.entry_list.trigger ( 'sorton', [ config.sortList ]) ;
		this.entry_list.tablesorterPager ({ size: page_size, page: cur_page, positionFixed: pos_fixed }) ;

		for ( item in items )
		{
			item = items [ item ] ;
			id = $(item).attr ( 'id' ) ;
			if ( id ) this.flash_list_entry ( id ) ;
		}
	}

	this.start_update_timeout = function ()
	{
		var $this = this ;
		
		this.stop_update_timeout () ;

		this.entry_list_timeout = setTimeout (
			function () { $this.update_entry_list ( $this.entry_list_timestamp ) ; },
			this.entry_list_update_interval
		) ;
	}

	this.stop_update_timeout = function ()
	{
		clearTimeout ( this.entry_list_timeout ) ;
		this.entry_list_timeout = null ;
	}

	// ajax table-data updater
	// http://tablesorter.com/docs/example-ajax.html
	this.update_entry_list = function ( timestamp )
	{
		clearTimeout ( this.entry_list_timeout ) ;
		this.entry_list_timeout = null ;
		var $this = this ;

		$.ajax ({

			url: _self + '/entry_list/' + timestamp,
			type: 'GET',
			dataType: 'json',
			timeout: 4000,

			error: function () {
				$this.entry_list_errors++ ; // increase error counter

				if ( $this.entry_list_errors == 3 )
					alert ( 'error loading entry list 3 times.\nperiodic list-update halted.\nreload page to try again.' ) ;
				else
					$this.start_update_timeout () ;
			},

			success: function ( data ) {
				$this.entry_list_errors = 0 ; // reset error counter

				if ( data )
				{
					if ( data.html && data.html.length )
						$this.entry_list_append ( data.html ) ;

					$this.entry_list_timestamp = data.timestamp ;
				}

				$this.start_update_timeout () ;
			}

		}) ;
	}
	
	this.construct = function ()
	{
		var $this = this ;
		
		this.entry_list.find ( 'tbody tr' ).click (function(){
			$this.entry_edit ( this ) ;
		}) ;
		
		this.entry_list
			.tablesorter ({ widgets: ['zebra'], sortList: [[4,1], [0,1]] })
			.tablesorterPager ({ container: this.pager, positionFixed: false }) ;

		this.start_update_timeout () ;
		
		return this ;
	}
	
	return this.construct () ;
	
}

// init everything
$(function(){
	
	tracker = new tracker ( $( '#entry_list' ), $( '#pager' ), entry_list_timestamp ) ;
	
}) ;
