/**
 * FOX View
 *
 * @package FOX
 * @subpackage JavaScript Library
 */
Fox.Control.View = Class.create(Fox.Control, {
	initialize: function(options) {
		this.viewInitialize(options);
	},
	
	viewInitialize: function(options) {
		this.viewOptions = $H({cp: 1, rpp: 10});
		this.indexedItems = {};
		this.retryAttempts = 0;
		this.footer = [];
		this.retryAttemptsCount = 2;
		this.retryAttemptsTimeout = 2000;
		this.map = {
			row: 'row', 
			emptyView: 'emptyView', 
			errorView: 'errorView' 
		};
		
		['cp', 'rpp', 'limit', 'offset', 'dbcPrefix', 'count'].each(function(param){
			if (options[param]) {
				this.viewOptions.set(param, options[param]);
				delete options[param];
			}
		}.bind(this));
		
		this.decode = true;
				
		this.defaultNavigatorParams = $H({
			prefix: 'view',
			filterPrefix: 'view_f'
		});
		this.controlInitialize(options);
		return this;
	},
	
	limit: function(value) {
		return this.toggleViewOption('limit', value);
	},
	
	offset: function(value) {
		return this.toggleViewOption('offset', value);
	},
	
	rowsPerPage: function(value) {
		return this.toggleViewOption('rpp', value);
	},
	
	currentPage: function(value) {
		return this.toggleViewOption('cp', value);
	},
	
	sort: function(value) {
		return this.toggleViewOption('sort', value);
	},
	
	dbcPrefix: function(value) {
		this.options.dbcPrefix = value;
		return this.toggleViewOption('dbcPrefix', value);
	},
	
	match: function(value) {
		this.viewOptions.set('cp', 1);
		return this.toggleViewOption('match', value);
	},
	
	toggleViewOption: function(name, value) {
		if (typeof value != 'undefined') {
			this.viewOptions.set(name, value);
			return this;
		} else {
			if (!value.length) {
				this.viewOptions.unset(name);
				return this;
			}
		}
		
		return this.viewOptions.get(name);
	},
	
	active: function(state) {
		this.options.active = state;
		return this;
	},
	
	canRedraw: function(state) {
		this.options.canRedraw = state;
		return this;
	},
	
	nextPage: function() {
		if (!this.loadData) {
			return false;
		}
		
		var cp = this.viewOptions.get('cp');
		
		if (!cp) {
			cp = 1;
		}
		
		if (cp >= this.loadData.pc) {
			return false;
		}
		
		this.viewOptions.set('cp', parseInt(cp) + 1);
		this.load();
		return this;
	},
	
	prevPage: function() {
		if (!this.loadData) {
			return false;
		}
		
		var cp = this.viewOptions.get('cp');
		if (!cp) {
			this.viewOptions.set(cp, 1);
			return false;
		}
		
		if (cp <= 1) {
			return false;
		}
		
		this.viewOptions.set('cp', parseInt(cp) - 1);
		this.load();
		return this;
	},

	isFirstPage: function() {
		if (!this.loadData) {
			return true;
		}

		var cp = this.viewOptions.get('cp');
		if (!cp) {
			this.viewOptions.set(cp, 1);
			return true;
		}

		if (cp == 1) {
			return true;
		}

		return false;
	},

	isLastPage: function() {
		if (!this.loadData) {
			return false;
		}

		var cp = this.viewOptions.get('cp');
		var pc = this.loadData.pc;
		if (!cp) {
			this.viewOptions.set(cp, 1);
			return false;
		}

		if (cp == pc) {
			return true;
		}

		return false;
	},
	
	go: function () {
		if (this.navigator) {
			var params = $H({});
			
			this.viewOptions.each(function(param) {
				params.set(this.navigator.get('prefix') + '_' + param[0], param[1]);
			}.bind(this));
			
			this.options['filter'].each(function(filter) {
				params.set(this.navigator.get('filterPrefix') + '_' + filter[0], filter[1]);
			}.bind(this));

			Fox.Navigator.getAll(this.navigator.get('filterPrefix')).each(function (filter) {
				if (!this.options['filter'].get(filter[0])) {
					Fox.Navigator.unset(this.navigator.get('filterPrefix') + '_' + filter[0]);
				}
			}.bind(this));
			
			this.changed = true;
			this._loaded = false;
			if (this.decode) {
				params.decode = true;
			}
			Fox.Navigator.update(params);
		} else {
			this.load();
		}
		return this;
	},
	
	navigate: function(params) {
		var options = Fox.Navigator.getAll(this.navigator.get('prefix'));
		var filter = Fox.Navigator.getAll(this.navigator.get('filterPrefix'));
		if (this.changed || (this.viewOptions.toQueryString() != options.toQueryString() || $H(this.options.filter).toQueryString() != filter.toQueryString())) {
			this.changed = false;
			this.viewOptions = options;
			this.options.filter = filter;
			this._loaded = true;
			this.load();
			return;
		}
		if (!this._loaded) {
			this._loaded = true;
			this.load();
		}
		return this;
	},

	fullRedraw: function() {
		this.dispatchEvent('preDraw');
		this.firstRow = null;
		this.redraw(this.options.escapeHtml ? this.escapeHtml(this.loadData.items) : this.loadData.items);
		this.dispatchEvent('postDraw');
	},

	clearView: function() {
		this.footer = [];
		$A(this.options.container.childNodes).each(function (child) {
			child = $(child);
			if (child.remove) {
				if (!child.hasClassName('view_header')) {
					if (child.hasClassName('view_footer')) {
						this.footer.push(child.cloneNode(true));
					}
					child.remove();
				}
			}
		}.bind(this));
		
	},

	redraw: function(data) {
		this.clearView();

		if (data == 'error') {
			if (!this.options.containers[this.map.errorView]) {
				this.map.errorView = this.map.emptyView;
			}
			if (this.options.containers[this.map.errorView]) {
				this.options.containerClone.update(this.options.containers[this.map.errorView]);
				this.options.container.appendChild(this.options.containerClone.down());
				this.dispatchEvent('errorView');
			}
		} else	if (!data.length && this.options.containers[this.map.emptyView]) {
			this.options.containerClone.update(this.options.containers[this.map.emptyView]);
			this.options.container.appendChild(this.options.containerClone.down());
			this.dispatchEvent('emptyView');
		} else {
			var item, elt;
			for (var i = 0, l = data.length; i < l; i++) {
				item = data[i];
				item._iteration = i;
				elt  = this.drawRow(item, {container: this.map.row, position: 'bottom', iteration: i});
				if (i == 0) {
					this.firstRow = elt;
				}
			}

			// data.each(function(item, iteration) {
			// 	item._iteration = iteration;
			// }.bind(this));
		}
		
		this.footer.each(function (item){
			this.options.container.appendChild(item);
		}.bind(this));
	},
	
	drawRow: function(item, params) {
		this.indexedItems[item.id] = item;
		this.dispatchEvent('preRow', {item: item, iteration: params['iteration']});
		if (!params['container']) {
			params['container'] = this.map.row;
		}
		
		this.options.containerClone.update(this._applyPatterns(this.options.containers[params['container']], item, this.options.variables, this));
		switch (params['position']) {
			case 'top':
				if (this.firstRow) {
					this.firstRow.insert({before: this.options.containerClone.innerHTML});
					this.firstRow = this.firstRow.previousSibling;
				} else {
					this.options.container.insert(this.options.containerClone.innerHTML);
					this.firstRow = this.options.container.lastChild
				}
				var elt = this.firstRow; 
			break;
			case 'bottom':
			default:
				var footer = this.options.container.down('.view_footer');
				if (footer) {
					footer.insert({before: this.options.containerClone.innerHTML});
					var elt = footer.previousSibling;
				} else {
					this.options.container.insert(this.options.containerClone.innerHTML);
					var elt = this.options.container.lastChild;
				} 
			break;
		}
		this.dispatchEvent('postRow', {elt: elt, item: item, iteration: params['iteration']});
		return elt;
	},
	
	init: function(subject, value) {
		if (this._inited) {
			return;
		}
		
		this._inited = true;
		
		if (this.options.navigator) {
			this.initNavigator(this.options.navigator);
		}
		try {
			this.setContainer(this.options.container);
			//TODO this.options.containers.pager - depricated 
			if (this.options.containers.pager) {
				try {
					this.pager = Fox.Utils.evalJSON(this.options.containers.pager);
				} catch (e) {
					if (!Prototype.Browser.IE && console) {
						console.log('Pager init error: "' + e + '" --- Init string: "' + this.options.containers.pager + '"'); // TODO LOGGER
					}
				}
			}
		} catch(e) {
			if (!Prototype.Browser.IE && console) {
				console.log('View (' + this.options.name + ') init error: "' + e + "'"); // TODO LOGGER
			}
		}
		return this;
	},
	
	load: function() {
		if (!this.options.lazyload || this.lazyloaded || $(this.options.container).cumulativeOffset()[1] <= document.viewport.getScrollOffsets()[1] + $(document.body).getHeight()) {
			return this.realLoad();
		}
		
		var callback = function() {
			if ($(this.options.container).cumulativeOffset()[1] <= document.viewport.getScrollOffsets()[1] + document.body.getHeight()) {
				this.realLoad();
				this.lazyloaded = true;
				Event.stopObserving(window, 'scroll', callback);
			}
		}.bind(this);
		
		Event.observe(window, 'scroll', callback);
		return this;
	},
	
	realLoad: function() {
		if (!this.options.active) {
			return;
		}
		
		if (!this._inited) {
			this.init();
		}
		
		delete this.firstRow;
		
		if (this.navigator && !this._loaded) {
			this._loaded = true;
			this.navigate();
			return;
		}
		
		if (typeof this.api == 'object') {
			this.api.kill();
			delete this.api;
		}

		this._loaded = true;
		this.dispatchEvent('init');
		
		if (this.pager) {
			var params = this.viewOptions.merge(this.viewOptions).clone();
		} else {
			var params = this.viewOptions.clone();
		}
		
		this.indexedItems = {};
		$H(this.options['filter']).each(function(filter) {
			params.set('f_' + filter[0], filter[1]);
		}.bind(this));
		
		if (this.options['data']) {
			params.set('data', this.options['data']);
		}
		
		this.dispatchEvent('preLoad');
		params.set('rand', Math.random());
		
		try {
			this.api = new Fox.Api.secureCallx(this.options['hash']).call({
				onSuccess: function(data) {
					delete this.api;
					this.loadData = data;
					
					if (!this.loadData.cp) {
						this.loadData.cp = parseInt(this.viewOptions.get('cp')) || 1;
					}
					
					if (this.options.canRedraw) {
						try {
							this.fullRedraw();
						} catch (e) {
							if (!Prototype.Browser.IE && console) {
								console.log('View (' + this.options.name + ') redraw error: "' + e + "'"); // TODO LOGGER
							}
						}
						
						if (this.pager) {
							this.initPager(this.loadData);
						}
					}
					
					this.dispatchEvent('postLoad');
				}.bind(this),

				onFailure: function(response, trasport) {
					delete this.api;
					if (!Prototype.Browser.IE && console) {
						console.log('View load error', trasport); // TODO LOGGER
					}
					this.redraw('error');
				}.bind(this),
				
				onError: function(transport) {
					if (this.retryAttempts < this.retryAttemptsCount) {
						this.retryAttempts++;
						setTimeout(
							function(){this.realLoad()}.bind(this),
							this.retryAttemptsTimeout
						);
					} else {
						this.redraw('error');
					}
					delete this.api;
				}.bind(this),
				params: params,
				domain: this.options.domain || null
			});
		} catch (e) {
			if (!Prototype.Browser.IE && console) {
				console.log('View load error: "' + e + "'"); // TODO LOGGER
			}
		}
		return this;
	},
	
	initPager: function(data) {
		var pc = {_all_: data.pc ? data.pc : "0"};
		this._applyPatterns($$('body')[0], pc, this.pager.pagesCount, this);
		
		switch (this.pager['class']) {
			case 'Paginator':
			default:
				if (this.navigator) {
					var currentParams = Fox.Navigator.getAll().clone();
					currentParams.set(this.navigator.get('prefix') + '_cp', '__page__');
					var baseUrl = '#' + unescape(currentParams.toQueryString());
				} else {
					var onClick = function(e) {
						var page = Event.element(e).getAttribute('rel');
						this.currentPage(page).go();
					}.bind(this);
				}
				
				var iterator = 0;
				$A(this.pager.containers).each(function(place) {
					$$('body')[0].adjacent(place.path).each(function(node) {
						if (!node) {
							return;
						}
						
						if (typeof node.id == 'undefined') {
							node.id = this.options['hash'] + '_Pages_' + iterator++;
						}
						try {
							this.pager.object = new Paginator(
								node.id,
								data.pc ? data.pc : "0",
								this.pager.brc ? this.pager.brc : 3,
								this.viewOptions.get('cp') ? this.viewOptions.get('cp') : 1,
								baseUrl,
								onClick
							);
						} catch (e) {
							if (!Prototype.Browser.IE && console) {
								console.log(e);
							}
						}
					}.bind(this))
				}.bind(this));
			break;
		}
		return this;
	}
});

