
var LayoutController = Backbone.Model.extend({
	
	// model attributes
	defaults: {
		screenMode: CONSTANTS.screenModes.DESKTOP,
		viewMode: CONSTANTS.viewModes.SIDE_BY_SIDE,
		panels: undefined
	},

	// other attributes
	windowResizeTimer: -1,
	
	initialize: function() {
		this.bind('change:screenMode', this.onScreenModeChanged, this);
	},
	
	onScreenModeChanged: function() {
		var mode = this.get('screenMode');
		if (mode === CONSTANTS.screenModes.HANDHELD) {
			this.set({viewMode:CONSTANTS.viewModes.STACKED});			
		} else {
			this.set({viewMode:CONSTANTS.viewModes.SIDE_BY_SIDE});
		}
	},
	
	togglePanel: function(panel) {
		if (this.get('viewMode') === CONSTANTS.viewModes.SIDE_BY_SIDE) {
			if (panel === CONSTANTS.panels.MAP) {
				// cannot toggle map view
				return;
			}
			var panels = this.get('panels');
			this.set({panels: panels ^ panel});
		} else { 
			var panels = this.get('panels');
			if (panels & panel) {
				// instead of removing this panel, we just set it to MAP
				panel = CONSTANTS.panels.MAP;
			}
			this.set({panels: panel});
		}
	},
	
	/**
	If side by side: add the current panel next to the map.
	If stacked: show the current panel that is not the map.
	*/
	sanitizePanels: function() {
		var panels = this.get('panels');
		if (this.get('viewMode') === CONSTANTS.viewModes.SIDE_BY_SIDE) {
			if (!(panels & CONSTANTS.panels.MAP)) {
				// always show map: add it
				panels |= CONSTANTS.panels.MAP;
			}
			this.set({panels: panels});
		} else {
			// find out first panel that is not map
			if (panels & CONSTANTS.panels.FILTER) {
				this.set({panels: CONSTANTS.panels.FILTER});
			} else if (panels & CONSTANTS.panels.ADDRESS) {
				this.set({panels: CONSTANTS.panels.ADDRESS});
			} else {
				this.set({panels: CONSTANTS.panels.MAP});
			}
		}
	},
	
	isPanelVisible: function(panel) {
		var panels = this.get('panels');
		return panels & panel;
	}

});


var LayoutView = Backbone.View.extend({
	
	isTouchDevice: false,

	controlsView: undefined,
	filterView: undefined,
	addressView: undefined,
	mapView: undefined,
	
	initialize: function (options) {
		
		this.isTouchDevice = ('ontouchstart' in document.documentElement) ? true : false;
		var useIScrollbars = this.isTouchDevice ? true : false;
			
		this.model.bind('change:screenMode', this.onScreenModeChanged, this);
		this.model.bind('change:viewMode', this.onViewModeChanged, this);
		this.model.bind('change:panels', this.onPanelsChanged, this);
		
		this.controlsView = this.options.controlsView;
		this.filterView = this.options.filterView;
		this.addressView = this.options.addressView;
		this.mapView = this.options.mapView;
		
		this.filterView.useIScrollbar(useIScrollbars);
		this.addressView.useIScrollbar(useIScrollbars);
		
		this.model.set({panels:CONSTANTS.panels.MAP});		
		// if you instead want to show all panels at the start:
		// this.model.set({panels:CONSTANTS.panels.MAP | CONSTANTS.panels.FILTER | CONSTANTS.panels.ADDRESS});
		
		this._initInterface();
	},
	
	events : {
		"click .filterView"  : "_toggleFilterView",
		"click .addressView" : "_toggleAddressView"
	},
	
	update: function() {
		this.model.sanitizePanels();
		this._redrawPanels();
	},
	
	onViewModeChanged: function () {
		this.update();
	},
	
	onScreenModeChanged: function () {
		this.update();
	},
	
	onPanelsChanged: function () {
		this._redrawPanels();
	},
	
	_toggleFilterView: function() {
		this.model.togglePanel(CONSTANTS.panels.FILTER);
	},
	
	_toggleAddressView: function() {
		this.model.togglePanel(CONSTANTS.panels.ADDRESS);
	},
	
	_redrawPanels: function () {
		var viewMode = this.model.get('viewMode');

		switch (viewMode) {
			case CONSTANTS.viewModes.SIDE_BY_SIDE:
				this._updatePanelsSideBySide();
				break;
			case CONSTANTS.viewModes.STACKED:
				this._updatePanelsStacked();
				break;
		}
		this._redrawPanelContents();
		this._resizePageElements();
		this._updateHtmlStates();
	},
	
	_redrawPanelContents: function() {
		var panels = this.model.get('panels');
		var screenMode = this.model.get('screenMode');
		
		if (panels & CONSTANTS.panels.FILTER) {
			this.filterView.update(screenMode, CONSTANTS.screenModes);
			this.filterView.show();
		} else {
			this.filterView.hide();
		}
		if (panels & CONSTANTS.panels.ADDRESS) {
			this.addressView.update(screenMode, CONSTANTS.screenModes);
			this.addressView.show();
		} else {
			this.addressView.hide();
		}
		if (panels & CONSTANTS.panels.MAP) {
			this.mapView.update(screenMode, CONSTANTS.screenModes);
			this.mapView.show();
		} else {
			this.mapView.hide();
		}
		this.controlsView.render(screenMode, CONSTANTS.screenModes);
	},
	
	_updatePanelsSideBySide: function () {
		var left = 0, panels = this.model.get('panels');

		var HIDE_CSS = {
			display: 'none',
			left: 0,
			width: 0
		};
		
		if (panels & CONSTANTS.panels.FILTER) {
			this.filterView.el.css({
				display: 'block',
				left: left,
				width: CONSTANTS.layout.PANEL_WIDTH_SIDE_BY_SIDE
			});
			left += CONSTANTS.layout.PANEL_WIDTH_SIDE_BY_SIDE;
		} else {
			this.filterView.el.css(HIDE_CSS);
		}
		
		if (panels & CONSTANTS.panels.ADDRESS) {
			this.addressView.el.css({
				display: 'block',
				left: left,
				width: CONSTANTS.layout.PANEL_WIDTH_SIDE_BY_SIDE
			});
			left += CONSTANTS.layout.PANEL_WIDTH_SIDE_BY_SIDE;
		} else {
			this.addressView.el.css(HIDE_CSS);
		}
		
		if (panels & CONSTANTS.panels.MAP) {
			this.mapView.el.css({
				display: 'block',
				left: left,
				width: $('body').width() - left
			});
		} else {
			this.mapView.el.css(HIDE_CSS);
		}

	},
		
	_updatePanelsStacked: function () {
		var SHOW_CSS = {
			display: 'block',
			left: 0,
			width: $('body').width()
		},
		HIDE_CSS = {
			display: 'none',
			left: 0,
			width: 0
		},
		panels = this.model.get('panels');
		
		if (panels & CONSTANTS.panels.FILTER) {
			this.filterView.el.css(SHOW_CSS);
		} else {
			this.filterView.el.css(HIDE_CSS);
		}
		
		if (panels & CONSTANTS.panels.ADDRESS) {
			this.addressView.el.css(SHOW_CSS);
		} else {
			this.addressView.el.css(HIDE_CSS);
		}
		
		if (panels & CONSTANTS.panels.MAP) {
			this.mapView.el.css(SHOW_CSS);
		} else {
			this.mapView.el.css(HIDE_CSS);
		}

	},
	
	/**
	Sets the heights of #app,#mapView,#filterView,#addressView.
	Sets the width and left pos of #mapView
	*/
	_resizePageElements: function() {
		// map
		var left = 0;
		
		var panels = this.model.get('panels');
		if (panels & CONSTANTS.panels.FILTER) {
			left += $('#filterView').width();
		}
		if (panels & CONSTANTS.panels.ADDRESS) {
			left += $('#addressView').width();
		}
		var width = this.el.width();
		if ( width == 100 ) {
			width = 940; /* hack by erik */
		}
		$('#mapView').css({
			left: left,
			width: width - left
		});
		
		var windowHeight = $(window).height() - 2*20;
		if (/mobile/i.test(navigator.userAgent)) {
			windowHeight += 60;
		}
		this.el.css({
			height: windowHeight
		});
		
		var panelHeight = windowHeight - this.controlsView.el.outerHeight();
		var CSS = {
			height: panelHeight
		};
		
		$('#mapView').css(CSS);
		$('.panels').css(CSS);
		
		// hide url bar by scrolling a bit
		if (/mobile/i.test(navigator.userAgent) && !window.location.hash) {
			window.scrollTo(0, 1);
		}
	},
	
	/**
	Writes the panel states as class names in html so that buttons are highlighted with css.
	*/
	_updateHtmlStates: function () {
		panels = this.model.get('panels');
		
		if (panels & CONSTANTS.panels.FILTER) {
			this.el.addClass('filterView');
		} else {
			this.el.removeClass('filterView');
		}
		
		if (panels & CONSTANTS.panels.ADDRESS) {
			this.el.addClass('addressView');
		} else {
			this.el.removeClass('addressView');
		}
		
		if (panels & CONSTANTS.panels.MAP) {
			this.el.addClass('mapView');
		} else {
			this.el.removeClass('mapView');
		}
	},
	
	_initInterface: function() {
		if (this.isTouchDevice) {
			$('body').addClass('touch');
		}

		// screen size monitor elements; display is set by CSS media queries, and read by js
		var screenDesktopMonitor = $('<div></div>').attr('id', 'screenDesktop').insertAfter(this.el);
		var screenTabletMonitor = $('<div></div>').attr('id', 'screenTablet').insertAfter(this.el);
		var screenHandheldMonitor = $('<div></div>').attr('id', 'screenHandheld').insertAfter(this.el);
		
		var self = this;
		$(window).resize(function () {
			// use a timer to not fire all the time
			var wait = 400;
			if (self.windowResizeTimer) {
				clearTimeout(self.windowResizeTimer);
			}
			self.windowResizeTimer = setTimeout(function () {
				self._updateInterface();
			}, wait);
		});
		this._updateInterface();
	},
	
	_updateInterface: function() {
		// check screen mode based on visibility of 'monitor' elements
		var mode = CONSTANTS.screenModes.NONE;
		
		if ($('#screenDesktop').css('display') !== 'none') {
			mode = CONSTANTS.screenModes.DESKTOP;
		} else if ($('#screenTablet').css('display') !== 'none') {
			mode = CONSTANTS.screenModes.TABLET;
		} else if ($('#screenHandheld').css('display') !== 'none') {
			mode = CONSTANTS.screenModes.HANDHELD;
		}
		
		// update now, because not all size changes will trigger a new screen mode or view mode
		this.mapView.render();
		this.controlsView.render();
		this._resizePageElements(); 
		this.model.set({screenMode: mode});
		$(window).trigger('resize');
	}
	
});	


