CNY = function () {
	var moduleData={},
		eventData={},
		debug=false,
		ec=0,
		createInstance = function ( moduleId ) {
			var instance = moduleData[moduleId].creator( new Sandbox() ),
				name, method;
			if( debug === true ) {
				for( name in instance ) {
					method = instance[name];
					if( typeof method == 'function' ) {
						instance[name] = function ( method, name ) {
							return function () {
								try {
									return method.apply( this, arguments );
								}
								catch( err ) {
									CNY.log( moduleId + ' - ' + name + '(): ' + err.message );
								}
							}
						}( method, name );
					}
				}
			}
			return instance;
		}
	return {
		register: function ( moduleId, creator ) {
			moduleData[moduleId] = {
				creator: creator,
				instance: null
			}
		},
		start: function ( moduleId ) {
			moduleData[moduleId].instance = createInstance( moduleId );
			moduleData[moduleId].instance.init();
		},
		stop: function ( moduleId ) {
			var data = moduleData[moduleId];
			if( data.instance ) {
				data.instance.destroy();
				data.instance = null;
			}
		},
		startAll: function () {
			var moduleId;
			for( moduleId in moduleData ) {
				if( moduleData.hasOwnProperty(moduleId) ) {
					this.start( moduleId );
				}
			}
		},
		stopAll: function () {
			var moduleId;
			for( moduleId in moduleData ) {
				if( moduleData.hasOwnProperty(moduleId) ) {
					this.stop( moduleId );
				}
			}
		},
		addListener: function ( events, handler, ctx, allowDupes ) {
			var l = events.length,
				i = 0;
			for( i; i < l; i++ ) {
				var j = 0,
					found=false,
					m;

				if( !eventData[events[i]] ) {
					eventData[events[i]] = [];
				}

				m = eventData[events[i]].length;

				for( j; j < m; j++ ) {
					if( handler == eventData[events[i]].handler && ctx == eventData[events[i]].ctx && !allowDupes ) {
						found = true;
					}
				}
				if( !found ) {
					eventData[events[i]].push({
						handler: handler,
						ctx: ctx
					});
				}
			}
		},
		dispatchEvent: function ( msgObj ) {
			var e = msgObj.e,
				data = [],
				i = 0,
				ev, l, prop;

			for( prop in msgObj.data ) {
				data.push( msgObj.data[prop] );
			}
			for( ev in eventData ) {
				if( ev == e ) {
					l = eventData[ev].length;
					for( i; i < l; i++ ) {
						var ce = eventData[ev][i];
						ce.handler.apply( ce.ctx, data );
					}
				}
			}
		},
		removeListener: function ( e, handler, ctx ) {
			var i = 0,
				l, ce;
			if( eventData[e] ) {
				l = eventData[e].length;
				for( i; i < l; i++ ) {
					ce = eventData[e][i];
					if( ce.handler == handler && ce.ctx == ctx ) {
						eventData[e].splice( i, 1 );
					}
				}
			}
		},
		clearEventType: function ( type ) {
			if( eventData[type] ) {
				eventData[type] = [];
			}
		},
		log: function ( msg ) {
			var ret, $c;
			ec++;
			ret = 'err' + ec + ': ' + msg;
			$c = $('#console');
			if( $c.length > 0 ) {
				var orig = $c.html();
				$c.html( orig + "\n" + ret );
			}
			else if( console ) {
				console.log( ret );
			}
			else {
				return ret;
			}
		}
	}
}();

Sandbox = function () {
	var href = window.location.href,
		base_url = href.match(/.+control\/\w+\//i),
		controller = href.match(/control\/\w+\/(\w+)/) ? href.match(/control\/\w+\/(\w+)/)[1] : null;

	return {
		listen: function ( events, handler, ctx, allowDupes ) {
			if( typeof events == 'string' ) {
				events = [events];
			}
			CNY.addListener( events, handler, ctx, allowDupes );
		},
		notify: function ( msgObj ) {
			CNY.dispatchEvent( msgObj );
		},
		kill: function ( e, handler, ctx ) {
			CNY.removeListener( e, handler, ctx );
		},
		killType: function ( e ) {
			CNY.clearEventType( e );
		},
		refresh: function () {
			CNY.stopAll();
			CNY.startAll();
		},
		path: function () {
			return base_url;
		},
		controller: function () {
			return controller;
		}
	}
}

CNY.register( 'resize-watch', function( sandbox ) {
	return {
		init: function () {
			$(window).bind('resize', this.resize );
		},
		resize: function ( e ) {
			sandbox.notify({
				e: 'resize-watch',
				data: {
					width: $(window).width(),
					height: $(window).height()
				}
			});
		},
		destroy: function () {
			$(window).unbind( 'resize', this.resize );
		}
	}
} );

CNY.register( 'navigation' , function ( sandbox ) {
	var self, bounds, navigation, subNavigation,
		tabs, viewports, active, visible,
		activePort, timer, timer2, activeIndex;
	return {
		init: function () {
			self = this;
			bounds = $('.nav-set');
			navigation = $('.navigation');
			tabs = navigation.find('.nav-tab');
			subNavigation = $('.sub-navigation');
			viewports = $('.nav-viewport');
			activePort = $('.active-viewport');
			activeIndex = navigation.find('.active').index();
			active = visible = navigation.find('.active').not('.empty').length > 0 ? true : false;

			if( !active ) {
				subNavigation.css({
					height: 0,
					opacity: 0
				});
			}

			tabs.not('.empty').bind('click', self.toggleActive);
		},
		toggleActive: function ( e ) {
			e.preventDefault();
			var btn = $(this);
			btn.toggleClass('active').siblings().removeClass('active');
			if( $('.navigation').find('.active').length > 0 ) {
				self.updateNav(btn);
			}
			else {
				self.concealNav(e);
			}
		},
		updateNav: function ( tab ) {
			var tag = tab.data('tag'),
				target = '#'+tag+'-nav',
				nav = $(target),
				empty = tab.hasClass('empty') ? true : false;

			clearTimeout( timer );
			timer = 0;
			timer = setTimeout( function () {
				self.displayNav( nav, empty );
			}, 75 );
		},
		displayNav: function ( nav, empty ) {
			if( empty ) {
				self.retract();
				return false;
			}

			var nav = nav.html();

			if( !visible ) {
				activePort.html('').css('opacity',0);
				activePort.html(nav).animate({
					opacity: 1
				});
				subNavigation.stop().animate({
					height: activePort.outerHeight() + parseInt(activePort.css('margin-top')) + parseInt(activePort.css('margin-bottom')),
					opacity: 1
				});
			}
			else {
				activePort.children().remove();
				activePort.html(nav);
				subNavigation.stop().animate({
					height: activePort.outerHeight() + parseInt(activePort.css('margin-top')) + parseInt(activePort.css('margin-bottom')),
					opacity: 1
				});
			}
		},
		concealNav: function ( e ) {
			e.stopImmediatePropagation();
			var nav;
			if( !active ) {
				clearTimeout( timer2 );
				timer2 = 0;
				setTimeout( self.retract, 50 );
			}
			else {
				nav = viewports.eq(activeIndex).html();
				activePort.html(nav);
				subNavigation.stop().animate({
					height: activePort.outerHeight() + parseInt(activePort.css('margin-top')) + parseInt(activePort.css('margin-bottom')),
					opacity: 1
				});
			}
		},
		retract: function () {
			activePort.children().animate({
				opacity: 0
			}, function() {
				activePort.children().remove();
			});

			subNavigation.animate({
				height: 0,
				opacity: 0
			});
		},
		destroy: function () {

		}
	}
} );

CNY.register( 'carousel', function ( sandbox ) {
	var self, thumbs, tlen, items, more, currentIndex=0, len,
		fullscreen, pages, athumb, itemsPerPage,
		currentPage = 0, timer, nextItem, prevItem, pause,
		paused = false, time, modalIndex = 0, modals,
		cheech, modal, modalWrapper, modalItems, modalContainer,
		lightboxControls, lbprev, lbclose, lbnext, wrap, container,
		galleryControls;
	return {
		init: function () {
			self = this;
			time = 6000;
			modalContainer = $('#modal-container');
			galleryControls = $('.gallery-controls');
			container = $('.gallery-carousel');
			thumbs = $('.thumb').bind('click', self.thumbClicked);
			items = $('.gallery-item').css('cursor','pointer').bind('click',self.fullScreen);;
			wrap = $('.gallery-items');
			fullscreen = $('.full-screen').bind('click', self.fullScreen);
			more = $('.more');
			athumb = $('.active.thumb').css('opacity',.25);
			more.bind('click',self.paginate);
			timer = setTimeout( self.nextItem, time );
			nextItem = $('#next-item').bind('click', function(){
				self.pause();
				self.nextItem();
			});
			prevItem = $('#prev-item').bind('click', function (){
				self.pause();
				self.prevItem();
			});
			pause = $('#pause, #play');
			lightboxControls = $('.lightbox-controls');
			cheech = $('#cheech').css({
				opacity: 0,
				display: 'none'
			});
			modalWrapper = $('#modal-items').css({
				opacity: 0,
				display: 'none'
			});
			modalItems = $('.modal-item');
			pause.bind('click', function () {
				paused == false ? self.pause() : self.unpause();
			})
			sandbox.listen('resize-watch', self.adjust, self);
			cheech.bind('click', self.killFullScreen);
			modalItems.bind('click', self.modalUpdate );

			self.prepLightbox();

			len = items.length;
			tlen = thumbs.length;
			pages = tlen >= 10 ? Math.ceil(tlen / 9) : 1;
			itemsPerPage = 9;

			lbnext = $('.lb-next').bind('click', self.modalNext);
			lbprev = $('.lb-prev').bind('click', self.modalPrev);
			lbclose = $('.lb-close').bind('click', self.killFullScreen);
			self.setCurrentIndex(0);

			$(window).bind({
				keyup: function ( e ) {
					switch( e.keyCode ) {
						case 37:
							self.modalPrev();
							break;

						case 39:
							self.modalNext();
							break;

						case 27:
							self.killFullScreen();
							break;
					}
				}
			});
		},
		modalNext: function () {
			modalItems.eq(currentIndex+4).next().click();
		},
		modalPrev: function () {
			var index = modalItems.eq(currentIndex+4).data('index');
			modalItems.eq(currentIndex+4).prev().click();
		},
		prepLightbox: function () {
			modalWrapper.prepend( modalItems.eq(modalItems.length-4).clone(), modalItems.eq(modalItems.length-3).clone(), modalItems.eq(modalItems.length-2).clone(), modalItems.eq(modalItems.length-1).clone() );
			modalWrapper.append( modalItems.eq(0).clone(), modalItems.eq(1).clone(), modalItems.eq(2).clone(), modalItems.eq(3).clone() );
			modalItems = $('.modal-item');
			len = modalItems.length;
			var i = 0;
			for( i; i < len; i++ ) {
				modalItems.eq(i).data('index', i);
			}
		},
		pause: function () {
			clearTimeout( timer );
			$('#pause').hide();
			$('#play').show();
			paused = true;
		},
		unpause: function () {
			paused = false;
			$('#pause').show();
			$('#play').hide();
			timer = setTimeout( self.nextItem, time );
		},
		nextItem: function () {
			var next = currentIndex+1;
			if( next >= tlen ) {
				next = 0;
			}
			self.setCurrentIndex(next);
			thumbs.eq(currentIndex).addClass('active').animate({
				opacity: .25
			}, 150).siblings().removeClass('active').animate({
				opacity: 1
			});
			timer = setTimeout( self.nextItem, time );
		},
		prevItem: function () {
			var next = currentIndex-1;
			if( next < 0 ) {
				next = tlen-1;
			}
			self.setCurrentIndex(next);
			thumbs.eq(currentIndex).addClass('active').animate({
				opacity: .25
			}, 150).siblings().removeClass('active').animate({
				opacity: 1
			});
		},
		paginate: function () {
			self.setCurrentPage( currentPage+1 );
			self.controlCurrentPage();
			self.updatePagination();
			self.pause();
		},
		setCurrentPage: function ( page ) {
			currentPage = page;
		},
		controlCurrentPage: function () {
	
			if( currentPage >= pages ) {
				currentPage = 0;
			}
			else if ( currentPage < 0 ) {
				currentPage = pages -1;
			}
		},
		updatePagination: function () {
			thumbs.removeClass('vis');
			var start = currentPage * itemsPerPage,
				finish = start + itemsPerPage,
				i;
			var c=0;
			for( i = start; i < finish; i++ ) {
				thumbs.eq(i).addClass('vis');
				c++;
				thumbs.eq(i)[ c % 2 != 0 ? 'addClass' : 'removeClass']('alpha');
				thumbs.eq(i)[ c >= 9 ? 'addClass' : 'removeClass' ]('bottom');	
		}
			more.detach();
			if( $('.vis').length % 2 == 0 ) {
				more.addClass('alpha');
			}
			else {
				more.removeClass('alpha');
			}
			$('.vis').last().after(more);
		},
		thumbClicked: function () {
			var thumb = $(this);
			self.pause();
			thumb.stop().animate({
				opacity: .25
			}, 150).addClass('active').siblings().removeClass('active').stop().animate({
				opacity: 1
			});
			self.setCurrentIndex( thumb.data('index') );
		},
		setCurrentIndex: function ( index ) {
			currentIndex = index;
			currentIndex = currentIndex;
			self.updateData();
		},
		controlCurrentIndex: function () {
			if( currentIndex >= tlen ) {
				var c = currentIndex,
					off = Math.abs(tlen - c),
					ci = modalItems.eq(off+4),
					offset = ci.offset().left - modalWrapper.offset().left;
				modalWrapper.css({
					left: -offset + $(window).width()/2 - ci.width()/2
				});
				modalItems.eq(off+4).children('img').css('opacity',1);
				self.setCurrentIndex(off);
			}
			else if ( currentIndex < 0 ) {
				var c = currentIndex,
					off = modalItems.length + c - 4,
					ci = modalItems.eq(off),
					offset = ci.offset().left - modalWrapper.offset().left;
				modalWrapper.css({
					left: -offset + $(window).width()/2 - ci.width()/2
				});
				modalItems.eq(off).children('img').css('opacity',1);
				self.setCurrentIndex(off-4);
			}
		},
		modalUpdate: function ( e ) {
			self.setCurrentIndex( $(this).data('index')-4 );
		},
		updateData: function ( reset ) {
			var ci = modalItems.eq(currentIndex+4),
				offset = ci.offset().left - modalWrapper.offset().left,
				width = parseInt(items.eq(currentIndex).css('width'));

			items.eq(currentIndex).css({
				opacity: 0,
				display: 'inline-block'
			}).stop().animate({
				opacity: 1
			}, 850).siblings().stop().animate({
				opacity: 0
			}, 850, function () {
				$(this).css('display', 'none');
			});
			thumbs.eq(currentIndex).stop().animate({
				opacity: .25
			}).siblings().stop().animate({
				opacity: 1
			});

			ci.children('img').stop().animate({
				opacity: 1
			}).parent('li').siblings().children('img').stop().animate({
				opacity: .25
			});
			modalWrapper.stop().animate({
				left: -offset + $(window).width()/2 - ci.width()/2
			}, function() {
				self.controlCurrentIndex();
			});
			galleryControls.animate({
				width: width-30
			});
			container.animate({
				width: width
			});
			wrap.animate({
				width: width
			});
			self.checkPage();
		},
		checkPage: function () {
			page = Math.floor(currentIndex / itemsPerPage);
			self.setCurrentPage(page);
			self.controlCurrentPage();
			self.updatePagination();
		},
		fullScreen: function ( e ) {
			self.pause();
			modalContainer.css('display','block');
			cheech.css({
				display: 'block',
				opacity: 0
			}).animate({
				opacity: .9
			}, 350, function () {
				modalWrapper.css({
					display: 'inline-block',
					opacity: 1
				});
				lightboxControls.css({
					display: 'inline-block',
					opacity: 0
				}).animate({
					opacity: 1
				});
				$(window).trigger('resize');
			} );
		},
		killFullScreen: function ( e ) {
			modalWrapper.animate({
				opacity: 0
			}, function () {
				modalWrapper.css('display', 'none');
				modalContainer.css('display','none');
				cheech.animate({
					opacity: 0
				}, function () {
					cheech.css('display', 'none');
				});
			});
			lightboxControls.animate({
				opacity: 0
			}, function () {
				lightboxControls.css({
					display: 'inline-block',
					opacity: 0
				})
			});
		},
		adjust: function ( width, height ) {
			var ci = modalItems.eq(currentIndex+4),
				offset = ci.offset().left - modalWrapper.offset().left;

			modalWrapper.css({
				left: -offset + $(window).width()/2 - ci.width()/2,
				top: ($(window).height()-modalWrapper.height())/2
			});

			lightboxControls.css({
				left: (width-lightboxControls.width())/2,
				top: modalWrapper.offset().top + modalWrapper.height() + 20
			});
			if( height < 568 ) {
				modalItems.find('img').css('height', height - 100 );
			}
			else {
				modalItems.find('img').css('height','auto');
			}
		},
		destroy: function () {

		}
	}
} );

CNY.register( 'map', function ( sandbox ) {
	var self, map, ajaxTarget, markers = [];
	return {
		init: function () {
			self = this;
			map = document.getElementById('cny_map');
			ajaxTarget = site_url + '_resources/cny_locations/';
			$.ajax({
				type: 'get',
				url: ajaxTarget,
				success: self.instantiate,
				error: self.error
			});
		},
		instantiate: function ( data ) {
			var i, pos, opts, center, c=0;
			opts = {
					zoom: 12,
					mapTypeId: google.maps.MapTypeId.ROADMAP,
					center: new google.maps.LatLng( 0,0 )
			};
			map = new google.maps.Map(document.getElementById('cny_map'), opts );
			var latlngbounds = new google.maps.LatLngBounds();
			for( i in data ) {
				pos = new google.maps.LatLng(data[i].lat,data[i].lng);
				var size = new google.maps.Size(71,83),
					origin = new google.maps.Point(0,0),
					anchor = new google.maps.Point(47,76),
					image = new google.maps.MarkerImage( data[i].img, size, origin, anchor ),
					marker = new google.maps.Marker({
						position: pos,
						map: map,
						title: data[i].name,
						icon: public_dir + 'images_sys/cny-map_point.png'
					});
				markers.push( marker );
				latlngbounds.extend( pos );
				c++;
			};
			markerCount = markers.length;
			map.setCenter( latlngbounds.getCenter() );
			map.fitBounds( latlngbounds );
		},
		error: function ( err ) {
			console.log( err );
		},
		destroy: function () {

		}
	}
} );

CNY.register( 'center-body', function ( sandbox ) {
	var self, body;
	return {
		init: function () {
			self = this;
			body = $('.body');
			sandbox.listen( 'resize-watch', self.adjust, self );
		},
		adjust: function ( width, height ) {
			var val = (height-body.height())/2;
			body.css('margin-top', val);
		},
		destroy: function () {

		}
	}
} );

CNY.register( 'scroll-bar', function ( sandbox ) {
	var self, bar, puck, max, sp, wrapper, container, wh, ch;
	(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
	return {
		init: function () {
			self = this;
			bar = $('.scroll-bar');
			puck = $('.scroll-puck');
			wrapper = bar.siblings('.content-wrapper');
			container = wrapper.parent().bind('scroll', self.onScroll);
			wh = wrapper.outerHeight();
			ch = container.bind('mousewheel',self.mscroll).height();
			if( wh > ch ) {
				max = bar.outerHeight() - puck.outerHeight();
				self.drag(puck);
				bar.css('display', 'block').bind('mousedown', self.jump);
			}
		},
		jump: function ( e ) {
			e.preventDefault();
			if( $(e.target).hasClass('ui-draggable') ) {
				e.stopImmediatePropagation();
				return false;
			}
			$('body').bind('mousemove', self.dragging);
			$('body').bind('mouseup', self.stopdrag);
			var p = Math.ceil( (e.offsetY/max)*(wh-ch) );
			container.scrollTop( p );
		},
		stopdrag: function ( e ) {
			$('body').unbind( 'mousemove', self.dragging );
		},
		dragging: function ( e ) {
			var p = e.pageY - bar.offset().top,
				d = Math.ceil( (p/max)*(wh-ch) );
			container.scrollTop( d );
			if( $.browser.mozilla == true ) {
				bar.css('margin-top', container.scrollTop());	
			}
		},
		drag: function ( obj ) {
			obj.draggable({
				axis: 'y',
				containment: 'parent',
				drag: self.onDrag
			});
		},
		mscroll: function ( e ) {
			e.preventDefault();
			container.scrollTop( e.wheelDelta > 0 ? container.scrollTop() - 35 : container.scrollTop() + 35 );	
			if( $.browser.mozilla == true ) {
				bar.css('margin-top', container.scrollTop());	
			}
	},
		onScroll: function ( e ) {
			var st = container.scrollTop(),
				p = Math.floor( max*(st/(wh-ch)) );
			puck.css('top', p < max ? p : max);
		},
		onDrag: function ( e, ui ) {
			sp = ui.position.top / max;
			p = Math.ceil( (wh-ch)*sp );
			container.scrollTop( p );
			if( $.browser.mozilla == true ) {
				bar.css('margin-top', container.scrollTop());	
			}
		},
		destroy: function () {
			
		}
	}
} );

$(function(){
	//CNY.start( 'navigation' );
	CNY.start('resize-watch');
	if( $('.gallery-carousel').length > 0 ) {
		CNY.start( 'carousel' );
	}
	if( $('#cny_map').length > 0 ) {
		CNY.start( 'map' );
	}
	if( $('.center').length > 0 ) {
		CNY.start( 'center-body' );
	}
	if( $('.scroll-bar'.length > 0 ) ) {
		CNY.start( 'scroll-bar' );
	}
	$(window).load(function(){
		$(window).trigger('resize');
	});
});
