/* appInterface is used by flash & javascript to update
 * and request the app state 
 */
appInterface = (function() {
    
	var status = "loading",
			getState;
    
	function createHash(o) {
		var activeState = getState(),
			s = $.extend( {}, activeState, o ),
			hash = ( s.article.length ? s.article + '/' : '' );

        if( s.activity ) {
            hash += '/activity-' + s.activity; 
        }

        if( s.light ) {
            hash += '/light-' + s.light; 
        }

		return hash;
    }    

	function boolToNum(property) {
		return property ? 1 : 0;
	}

	/* Public */
	return {
		getStatus: function() {
			return status;
		},
		requestState: function(k) {
			return getState(k)
		},
		DOMFinishedLoading: function(fn) {
			getState = fn;
			status = "ready";
		},
		setState: function(o) {
			var hash = createHash(o);
			$.history.load(hash);
		}
	}
})();

/*
 * AppState is responsible for holding the state of
 * the app. Flash & JavaScript should use appInterface
 * in order to access and modify the state
 */
function AppState(o) {
	var observers = [],
			state = {
				lang: o.lang || 'no',
				article: '',
				light: null,
				activity: null,
				update: function(k, v) {
					if(this[k] != v) {
						this[k] = v;
						return true;
					} else {
						return false;
					}
				}
			};
    
	this.setState = function(newState) {
		var stateHasChanged = false, 
				params = {};

		$.each(newState, function(i, stateParam) {
			if(!stateParam.length) return;

            if( stateParam == 'article-false' ) {
                if(state.update('article', false)) stateHasChanged = true;
                return;
            }
			if(/-/.test(stateParam)) {
				var a = stateParam.split('-');
				if(isValidStateParam(a[0])) { // light / activity
					params[a[0]] = a[1];
				} else { // article with slug that contains dashes?
					if(i === 0) { // assume article if at position 1 in hash
						if(state.update('article', stateParam)) stateHasChanged = true;
					}
				}
			} else { // article
				if(state.update('article', stateParam)) stateHasChanged = true;
			}
		});
		
		if(params.light === undefined) {
			params.light = null;
		}
		if(params.activity === undefined) {
			params.activity = null;
		}
		
		for(var st in params) if(params.hasOwnProperty(st)) {
			if(state.update(st, params[st])) stateHasChanged = true;
		}
		
		// Notify state observers that
		// some change has occured
		if(stateHasChanged) {
			$.each(observers, function() {
				this.notify();
			});
		}
	};
	
	this.getState = function(k) {
		if(k) {
			return state[k];
		} else {
			var o = {};
			for(var k in state) if(state.hasOwnProperty(k)){
				if(typeof state[k] !== 'function') {
					o[k] = state[k];
				}
			}
			return o;
		}
	};

	this.observe = function(subscriber) {
		observers.push(subscriber);
	};

	function isValidStateParam(k) {
		return state.hasOwnProperty(k);
	}
}

/*
 * ContentManager is responsible for updating the DOM so that it
 * cohere with the AppState
 */
function ContentManager(options) {
	this.container = options.container;
	this.init();
}
ContentManager.prototype = {
	// bind all interaction that affects the 
	// application state in this method
	init: function() {	
		$('#topmenu a').click(function(e) {
			var values = $(this).attr('href').match(/([^\/]*)\/?$/);
			appInterface.setState({ article: values[1] });
			return false;
		});
	},
	loadArticle: function(slug) {
		var that = this;

        if( slug ) {
            $.ajax({
                url: baseDir + 'api/node/' + slug,
                dataType: 'json',
                success: function(content) {
                    // update content
                    that.container.html(content.body);
                    bindEventHandlers();
                    that.setDocumentTitle(content.title);
    
                    // update which menu item that is active
                    that.updateNavigation(slug, content.id);
                    
                    that.tagPageWithLevel(content.level);
                },
                error: function(xhr, textStatus, errorThrown) {}
            });
        } else {
            that.updateNavigation();
        }
		
		/*
		 * Bind all events for node/article content that was loaded
		 */
		function bindEventHandlers() {
            if( $('.partners .partner').length > 0 ) {
                $('.partners').tabs('.partner-panes > .partner-body',{
                    current: 'partner-active',
                    tabs: '.partner',
                    initialIndex: -1
                });
            }

			$('#submenu a').click(function() {
				var values = $(this).attr('href').match(/([^\/]*)\/?$/);
				appInterface.setState({ article: values[1] });
				return false;
			});
		}
	},
	tagPageWithLevel: function(level) {
		var page = $('#page'), 
				classNames = page.attr('className').split(' ');
				
		// fetch any of the classes .level1, level2, level3 
		// and remove if present
		classNames = $.grep(classNames, function(n, i) {
			return /^level[1-3]$/.test(n);
		}).join(" ");
		
		page.removeClass(classNames);
		page.addClass('level' + level);
	},
	unloadArticle: function() {
		this.container.empty();
	},
	updateNavigation: function(slug, nodeId) {
		var cn = 'selected', 
            current, re, listItem;

		$('#topmenu').find('.' + cn).removeClass(cn); // reset menu state
		
		if( nodeId ) {
			current = $('#obj-' + nodeId);
			var level = getLevel(current);
			
			switch ( level ) {
				case 1:
					current.parent().parent().addClass(cn);
					break;
				case 2:
					current.closest('li').addClass(cn)
							.parents('li').addClass(cn);
					break;
				case 3:
					var item = getItemBySlug(slug);
					if( getLevel(item) === 1 ) {
						item.closest('li').addClass(cn)
								.children('ul').find('li:first').addClass(cn);
					}

					if( getLevel(item) === 2 ) {
						item.closest('li').addClass(cn)
								.parents('li').addClass(cn);
					}
					
					if( getLevel(item) === 3 ) {
						var nodeId = item.closest('ul').attr('class').replace('parent-','');
						$('#obj-' + nodeId).closest('li').addClass(cn)
								.parents('li').addClass(cn)
					}
					break;
			}
		}
		
		function getItemBySlug(slug, context) {
			var menuItem = $('#topmenu a, #submenu a').filter(function() {
				var hrefSlug = $(this).attr('href').match(/([^\/]*)\/?$/)[1];
                
				return hrefSlug === slug && $(this).parents(context).length;
			});
			return menuItem;
		}
		
		function getLevel(item) {
			var level = 0,
					list = item.closest('ul'),
					parent = list.parent();
					
			if( parent.is('#topmenu') ) {
				level = 1; 
			} else if ( parent.closest('ul').parent().is('#topmenu') ) {
				level = 2;
			} else {
				level = 3;
			}
			return level;
		}
	},
	setDocumentTitle: function(title) {
		document.title = title + ' | Visit Norway';
	},
	toggleFlash: function(article) {
		if ( article ) {
            $('#page').removeClass('page-collapsed');
            $('#flash').height('122px');
		} else {
            $('#page').addClass('page-collapsed');
            $('#flash').height('600px');
        }
	},
	notify: function() {
		var newState = appInterface.requestState();
        this.loadArticle(newState.article);
		this.toggleFlash(newState.article);
	}
};

$(document).ready(function() {
	var appState, cm, flashObj, interval = null;

	// Initialize app state,
	// Responsible for holding the state 
	appState = new AppState({ lang: $('#languages .selected a').attr('id') });

	// init appInterface
	appInterface.DOMFinishedLoading(appState.getState);

    // Initialize ContentManager. 
    // responsible for javascript modifications of DOM content
    cm = new ContentManager({
        container: $('#content')
    });
    appState.observe(cm);
    cm.notify();
	
	// flash object can't subscribe for notifications
	// until the swf loading is complete 
	// (load callback is available in SWFObject 2.2+)
	intv = setInterval(function() {
		flashObj = getFlash('swf_placeholder');
		if ( flashObj && flashObj.notify ) {
			appState.observe(flashObj);
			clearInterval(intv);
		}
	}, 200);
	
	

	// initialize history plugin with
	// handle pageload function
	$.history.init(function(hash) {
        var o = hash.split('/').clean("");
        var slug = hash.replace(/((light-|activity-)\d+)|\//,'');
        if( !slug ) {
            o.push('article-false');
        }
        appState.setState(o);
	});

	/* returns the flash object in a 
	 * cross browser normalized manner */
	function getFlash(name) {
		return $.browser.msie ? window[name] : document[name];
	}
});

/* Utils */
Array.prototype.clean = function(dirt) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == dirt) {         
      this.splice(i, 1);
      i--;
    }
  }
  return this;
};
