(function() {

	var eventMatchers = {
		'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
		'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/
	}
	var defaultOptions = {
		pointerX: 0,
		pointerY: 0,
		button: 0,
		ctrlKey: false,
		altKey: false,
		shiftKey: false,
		metaKey: false,
		bubbles: true,
		cancelable: true
	}
	
	Event.simulate = function(element, eventName) {
		var options = Object.extend(Object.clone(defaultOptions), arguments[2] || { });
		var oEvent, eventType = null;
		
		element = $(element);
		
		for (var name in eventMatchers) {
			if (eventMatchers[name].test(eventName)) { eventType = name; break; }
		}
 
		if (!eventType)
			throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');
 
		if (document.createEvent) {
			oEvent = document.createEvent(eventType);
			if (eventType == 'HTMLEvents') {
				oEvent.initEvent(eventName, options.bubbles, options.cancelable);
			}
			else {
				oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
					options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
					options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
			}
			element.dispatchEvent(oEvent);
		}
		else {
			options.clientX = options.pointerX;
			options.clientY = options.pointerY;
			oEvent = Object.extend(document.createEventObject(), options);
			element.fireEvent('on' + eventName, oEvent);
		}
		return element;
	}
	
	Element.addMethods({ simulate: Event.simulate });

	window.map = {
		defaults: {
			debug: true,
			isRequesting: false,
			elements: {
				items: $$('body.top div#content div.item, body.ja div#also div.item, body.en div#also div.item, body.en div#reports li.first, body.fes div.item, body.fes dt.item, body.fes dd.item, body.ko div#also div.item, body.ko div#reports li.first, body.fes .works .categories .item'), // Do not use body#top, use body className
				topMenuLinks: $$('div#navbar a'),
				popupLinks: $$('a.pop'),
				pictures: $$('div.picture'),
				themes: $('themes'),
				shuffles: $$('div.shuffle'),
				themesDisplayControl: $('theme-control'),
				themesShuffleControl: $('shuffle-control'),
				themesPopupControl: $('themes-popup-close')
			},
			classNames: {
				activeControl: 'active-control',
				hover: 'over',
				popup: 'pop'
			},
			nullOutput: function() {
				return;
			},
			spacer: '/common/img/icons/spacer.gif',
			shuffleURL: '/common/js/maf-shuffle.php',
			descSkeleton: '<img src="/common/images/spacer.gif" width="200" height="112" alt="" /><div class="ui-clip"><h3><a href="[link]">[title]</a></h3><div class="description"><p>[desc]</p></div></div>'
		},
		models: {
			init: function() {
				for (var i in map.defaults) {
					if (map.defaults.hasOwnProperty(i)) {
						map[i] = map.defaults[i];
					}
				}
				map.defaults = null;
				var $items = map.elements.items || false,
					$popupLinks = map.elements.popupLinks || false,
					$pictures = map.elements.pictures || false,
					$themes = map.elements.themes || false,
					$shuffles = map.elements.shuffles || false,
					$themeButton = map.elements.themesDisplayControl || false,
					$themesShuffleButton = map.elements.themesShuffleControl || false,
					$themesCloseButton = map.elements.themesPopupControl || false,
					$topMenuLinks = map.elements.topMenuLinks || false;
				if ($topMenuLinks) $topMenuLinks.each(map.controllers.highLightItem);
				if ($popupLinks) $popupLinks.each(map.models.popups);
				if ($items) $items.each(map.models.items);
				if ($pictures) $pictures.each(map.models.pictures);
				if ($themeButton && $themes) {
					for ( var i = 0, themeLinkController = map.controllers.themeLink, themesLinks = $themes.getElementsByTagName( 'a' ); i < themesLinks.length; i++ ) {
						themeLinkController( themesLinks[ i ] );
					}
					$themes.hide().style.zIndex = 2;
					var addThemesBinders = map.controllers.toggleThemesList($themes, $themeButton);
					if ($themesCloseButton) {
						addThemesBinders = map.controllers.toggleThemesList($themes, $themeButton, $themesCloseButton);
					}
					if ($themesShuffleButton && $shuffles) {
						addThemesBinders = map.controllers.toggleTheme($themesShuffleButton, $shuffles[0] || false);
					}
				}
			},
			popups: function($link) {
				var o, classArr = $link.className.split(' ') || [];
				if (!$link.target)
					$link.target = (classArr.length > 2) ? classArr[1] : '_blank';
				o = classArr[2].split('-');
				$link.options = 'scrollbars=' + (o[1] || 'yes')
							+ ',resizable=' + (o[2] || 'yes')
							+ ',width=' + (o[3] || '640')
							+ ',height=' + (o[4] || '640');
				map.controllers.openURL($link, 'click');

			},
			items: function($item) {
				var targetURL = false,
					itemLink = $item.getElementsByTagName('a');
				if (itemLink.length > 0) {
					targetURL = itemLink[0].href || false;
					if (targetURL) {
						$item.href = targetURL;
						$item.target = itemLink[0].target || '_self';
						map.controllers.highLightItem($item);
					}
				}
			},
			pictures: function( $pic, newThumbnail ) {
				var targetURL = false,
					link = $pic.getElementsByTagName('a')[0] || false;
				if (link) {
					targetURL = link.href || false;
				}
				if ( typeof newThumbnail != 'number') {
					( $pic.getElementsByTagName('img')[0] || {} ).style.backgroundImage = 'url(' + newThumbnail + ')';
				}
				if ( targetURL ) {
					link.removeAttribute('href');
					$pic.href = targetURL;
					$pic.target = link.target || '_self';
					map.controllers.openURL($pic);
					var divs = $pic.getElementsByTagName('div'),
						$clip = $(divs[0]) || false;
					if ($clip) {
						var binder = map.controllers.togglePicturesDesc($pic, $clip, $(link));
					}
				}
			}
		},
		views: {
			themeDescSkeleton: function( skeleton, data ) {
				for ( var i in data ) {
					skeleton = skeleton.replace( '[' + i + ']', data[i] );
				}
				return skeleton;
			},
			loading: function($pictures) {
				return $pictures.each(
					function($pic) {
						$pic.addClassName('loading');
						var $thumbnail = $pic.firstDescendant();
						$thumbnail.src = map.spacer;
						$thumbnail.next().remove();
					}
				);
			},
			newTheme: function( o ) {
				var $pictures = o.pictures || false,
					$datas = o.datas.themesData || false,
					$theme = o.datas.themesCategory || false
					$skeleton = o.skeleton || false,
					$callBack = o.callBack || {};
				if ( !$pictures || !$datas || !$skeleton ) {
					return false;
				}
				$pictures.each(
					function( $pic, i ) {
						var newSkeleton = map.views.themeDescSkeleton( $skeleton, $datas[i]);
						map.models.pictures( $pic.update( newSkeleton ), $datas[i].image );
					}
				);
				var h1s = $$( 'h1' ) || [ ], $themeTitle = h1s[ 1 ] || false;
				if ( $themeTitle ) {
					$themeTitle.update( $theme.title || '' );
					var $themeDesc = $themeTitle.nextSiblings()[ 0 ];
					if ( $themeDesc ) {
						$themeDesc.update( '<p>' + ( $theme.description || '') + '</p>' );
					}
				}
				if ( typeof $callBack == 'function' ) {
					$callBack();
				}
			}
		},
		controllers: {
			openURL: function($link, $event) {
				if (!$link || !$link.href) return false;
				Event.observe($link, $event || 'click', function(event) {
					if (!$link.options) {
						if ( $link.target == '_self' ) {
							document.location.href = $link.href;
						}
						else if ( $link.target == '_blank' ) {
							Event.stop(event);
							window.open($link.href, $link.target);
						}
						else {
						}
					}
					else {
						Event.stop(event);
						window.open($link.href, $link.target, $link.options || null);
					}
				});
			},
			togglePicturesDesc: function( $pic, $clip, $link ) {
				if ( !$pic || !$clip || !$link ) return false;
				$pic.removeClassName( 'loading' );
				if ( !$pic.id ) {
					$pic.id = 'pic' + ( Math.floor( Math.random() * ( 666 - 13 + 1 ) ) + 13 );
				}
				else {
					Event.stopObserving( $pic );
				}
				var picId = $pic.id;
				Event.observe($link, 'mouseover', function( event ) {
					Event.stop( event );
					var mouseQueues = Effect.Queues.get( picId );
					mouseQueues.each(function(effect){effect.cancel();});
					$pic.addClassName( map.classNames.hover );
					new Effect.Move( $clip, {
						x: 0,
						y: 87 - 34,
						mode: 'absolute',
						queue: {
							position: 'end',
							scope: picId
						}
					});
				});
				Event.observe( $pic, 'mouseleave', function(event) {
					Event.stop( event );
					var mouseQueues = Effect.Queues.get( picId );
					mouseQueues.each(function(effect){effect.cancel();});
					$pic.removeClassName( map.classNames.hover );
					new Effect.Move( $clip, {
						x: 0,
						y: 87,
						mode: 'absolute',
						queue: {
							position: 'end',
							scope: picId
						}
					});
				});
				return true;
			},
			highLightItem: function($item) {
				if (!$item) return false;
				return [
					Event.observe($item, 'mouseenter', function() {
						$item.addClassName(map.classNames.hover);
						self.status = $item.href;
					}),
					Event.observe($item, 'mouseleave', function() {
						$item.removeClassName(map.classNames.hover);
						self.status = '';
					}),
					map.controllers.openURL($item)
				];
			},
			themeLink: function( $link ) {
				Event.observe( $link, 'click', function( event ) {
					Event.stop( event );
					if ( !map.isRequesting ) {
						map.isRequesting = true;
					}
					else {
						return;
					}
					var themeURL = unescape( decodeURI( $link.rel ) );
					if ( !themeURL ) {
						return;
					}
					new Ajax.Request( themeURL, {
						method: 'get',
						evalJSON: 'force',
						onComplete: function( transport ) {
							map.views.newTheme({
								pictures: map.elements.pictures,
								datas: transport.responseJSON || null,
								skeleton: map.descSkeleton,
								callBack: function() {
									map.isRequesting = false;
									var $closeButton = map.elements.themesDisplayControl;
									if ( $closeButton ) {
										$closeButton.simulate( 'click' );
									}
								}
							});
						},
						onFailure: function ( obj ) {
							// alert( obj.responseText || '' );
						},
						onException: function ( obj, exc ) {
							// alert( exc.message );
						}
					});
				});
			},
			toggleTheme: function($shuffleButton, $shuffleDiv) {
				return Event.observe($shuffleButton, 'click', function(event) {
					Event.stop(event);
					if ( !map.isRequesting ) {
						map.isRequesting = true;
					}
					else {
						return;
					}
					var $shuffleButtonContainer = Element.up($shuffleButton);
					if (!$shuffleButtonContainer.hasClassName(map.classNames.activeControl)) {
						if ($shuffleDiv) {
							$shuffleDiv.setStyle({visibility: 'visible'});
						}
						$shuffleButtonContainer.addClassName(map.classNames.activeControl)
						map.elements.pictures = map.views.loading(map.elements.pictures);
						new Ajax.Request( map.shuffleURL, {
							method:'get',
							evalJSON: 'force',
							onSuccess: function( transport ) {
								map.views.newTheme({
									pictures: map.elements.pictures,
									datas: transport.responseJSON.themesData || null,
									skeleton: map.descSkeleton,
									callBack: function() {
										map.isRequesting = false;
									}
								});
							}
						});
					}
				});
			},
			toggleThemesList: function($list, $masterButton, $slaveButton) {
				if (!$list || !$masterButton)
					return false;
				var targetButton = $slaveButton ? $slaveButton : $masterButton;
				return Event.observe(targetButton, 'click', function(event) {
					Event.stop(event);
					Element.up($masterButton).toggleClassName(map.classNames.activeControl);
					if ($list.style.display == 'none') {
						new Effect.SlideDown($list, {scaleY: true});
					}
					else {
						new Effect.SlideUp($list, {scaleY: true});
					}
				});
			}
		}
	};

	Event.observe(window, 'load', function() {
		window.map.models.init();
	});

})();
