    $.config.override({
        mainMenuDeep: 1
    })
    
    var launchers = new Array();
    
    var dropdownMenuLauncherOptions =
    {
        element: undefined,
        event: undefined,
        menu: undefined,
        loader: undefined,
        align: "horizontal"
    }
    
    function dropdownMenuLauncher(options)
    {
    	if(options == undefined) options = dropdownMenuLauncherOptions;
    	for (var option in dropdownMenuLauncherOptions) {
    	    if (options[option] == undefined) options[option] = dropdownMenuLauncherOptions[option];
    	}

		if(options.event)
		{
		    var event = options.event;
		}

		if (options.loader) {
		    var loader = options.loader;
		}
        
        if(options.menu)
		{
			this.menu = options.menu;
        }

        this.disabledFunction = function(event) { event.stopPropagation(); return false; }

        this.event = event;
        this.loader = loader;
		this.align = options.align;
        if (options.element) {
            this.addElement(options.element);
        }

        var itemObject = this;

        this.autoCloseFunction = function() {
            itemObject.finish();
        }

        launchers.push(this);     
    }

	
	dropdownMenuLauncher.prototype.element;
	dropdownMenuLauncher.prototype.event;
	dropdownMenuLauncher.prototype.menu;
	dropdownMenuLauncher.prototype.loader;
	dropdownMenuLauncher.prototype.align;	

	dropdownMenuLauncher.prototype.addElement = function(element) {

	    this.element = element;

	    var itemObject = this;

	    switch (this.event) {
	        case 'over':
	            {
	                if (this.element) {
	                    $(this.element).bind('mouseenter', function() { itemObject.launch() });
	                    $(this.element).bind('mouseleave', function() { itemObject.finish() });
	                }
	                break;
	            }
	        case 'click':
	            {
	                if (this.element) {
	                    $(this.element).unbind('click');
	                    $(this.element).toggle(function() { this.disabledFunction; itemObject.launch() }, function() { this.disabledFunction; itemObject.finish() });
	                }
	                break;
	            }
	        default:
	            {
	                itemObject.launch();
	                break;
	            }
	    }
	}

	dropdownMenuLauncher.prototype.addMenu = function(menu) {
	    this.removeMenu();
	    $(this.element).addClass('hasSubMenu');
	    this.menu = menu;
		var item = this;
		var timeout = 0;
		
		$(item.menu.element).bind('mouseleave', function() { 
		    timeout = setTimeout(function() {
		        item.finish();
		    }, 200);
		});
		
		$(item.menu.element).bind('mouseenter', function() { 
		    if (timeout) clearTimeout(timeout);
		});		
	}

	dropdownMenuLauncher.prototype.removeMenu = function() {
	    $(this.element).removeClass('hasSubMenu');
	    if (this.menu) {
	        this.menu.close();
	        $(this.menu.element).remove();
	        this.menu = undefined;
	        delete this.menu;
	    }
	}

	dropdownMenuLauncher.prototype.launch = function() {
	
	    var itemObject = this;
	    if (!$(itemObject.element).is('.control')) {
	        for (var i = 0; i < launchers.length; i++)
	            if (launchers[i] != itemObject) {
	                launchers[i].finish();
	        }
	    }

	    if (!($(itemObject.element).is('.active'))) {
	        $(itemObject.element).addClass('active');
	    }
	    
	    if (itemObject.loader && !$(itemObject.element).is('.loaded') && !$(itemObject.element).is('.inloading')) {
	        var preLoadMenu = new dropdownMenu();
	        preLoadMenu.addItem({ className: 'loading', caption: 'load' });
            itemObject.addMenu(preLoadMenu);
	        itemObject.loader.call(itemObject);
	    }

	    setTimeout(function() {
	        if (itemObject.menu && $(itemObject.element).is('.active')) {
	            var itemOffset = $(itemObject.element).offset();
	            if (itemObject.align == "vertical") {
	                var offset = {
	                    left: itemOffset.left + $(itemObject.element).width() + $.config.get("dropdownMenu.item."+$(itemObject.element).attr('key')+".left", 0),
	                    top: itemOffset.top + $.config.get("dropdownMenu.item."+$(itemObject.element).attr('key')+".top", 0),
						width: $.config.get("dropdownMenu.item."+$(itemObject.element).attr('key')+".width", 0)
	                }
	            }
	            else {
	                var offset = {
	                    left: itemOffset.left + $.config.get("dropdownMenu.item."+$(itemObject.element).attr('key')+".left", 0),
	                    top: itemOffset.top + $(itemObject.element).height() + $.config.get("dropdownMenu.item."+$(itemObject.element).attr('key')+".top", 0),
						width: $.config.get("dropdownMenu.item."+$(itemObject.element).attr('key')+".width", 0)
	                }
	            }
	            itemObject.menu.open(offset.left, offset.top, offset.width);
	        }
	    }, 150);

	    $(document).click(this.autoCloseFunction);

	}

	dropdownMenuLauncher.prototype.finish = function() {
	    var itemObject = this;
	    $(itemObject.element).removeClass('active');
	    if (itemObject.menu) {    
	        $(itemObject.menu.element).mouseenter(function() { $(itemObject.element).addClass('active') });
	        setTimeout(function() {
	            if (!$(itemObject.element).is('.active')) {
	                itemObject.menu.close();
	            }
	        }, 150);
	    }
     
	}

	dropdownMenuLauncher.prototype.destroy = function() {
	    var itemObject = this;
	    this.removeMenu();	    
	    this.loader = undefined;
	}	
	


	var dropdownMenuItemOptions =
	{
		select: undefined,
		url: undefined,
		name: undefined,
		caption: undefined,
		disabled: false,
		separator: false,
		className: 'dropdownMenuItem',
		element: undefined,
		launcher: undefined
		
	}

	function dropdownMenuItem(menu, options)
	{
		if(options == undefined) options = dropdownMenuItemOptions;
		for(var option in dropdownMenuItemOptions)
		if(options[option] == undefined) options[option] = dropdownMenuItemOptions[option];

		this.menu = menu;

		this.disabledFunction = function(event) { event.stopPropagation(); return false; }

		if(options.element)
		{
			var element = options.element;
			this.name = $(element).attr('key');
		}
		else
		{
			var element = document.createElement('li');
			$(menu.element).children('ul').append(element);
		}
		
		$(element).addClass(options.className);
		this.element = element;

		dropdownMenuItem.parentClass.constructor.call(this, element);
		
		if(options.separator) $(element).addClass('separator');

		if(!$(element).find("a").length) $(element).append('<a />');
		
		if(options.url) $(element).find("a").attr('href', options.url);

		if (options.name) {
		    this.name = options.name;
		    $(element).attr('key', options.name);
		}
		if(options.caption) $(element).find("a").text(options.caption);

		if(options.disabled) this.disable();

		if(options.submenu) this.addSubmenu(options.submenu);
		
		var itemObject = this;
		
		$(this.element).mouseenter(function() {itemObject.select()});
		$(this.element).mouseleave(function() {itemObject.deselect() });

		if (options.launcher) {
		    options.launcher.addElement(this.element);
		    this.launcher = options.launcher;
		}
	}

	extend(dropdownMenuItem, control);

	dropdownMenuItem.prototype.element;
	dropdownMenuItem.prototype.menu;
	dropdownMenuItem.prototype.name;
	dropdownMenuItem.prototype.submenu;
	dropdownMenuItem.prototype.launcher;	

	dropdownMenuItem.prototype.getType = function()
	{
		return 'dropdownMenuItem';
	}

	dropdownMenuItem.prototype.isSelected = function()
	{
		return $(this.element).is('.active');
    }
	
	dropdownMenuItem.prototype.hide = function() { }

	dropdownMenuItem.prototype.select = function() {
	    if (!this.isSelected()) {
	        var itemObject = this;

	        var items = this.menu.listItems();
	        for (var i = 0; i < items.length; i++)
	            if (items[i] != this) {
	            if (items[i].launcher) {
	                items[i].launcher.finish()
	            }
	        };

	        $(this.element).addClass('active');
	    }
	}
	
	dropdownMenuItem.prototype.deselect = function()
	{
		if(this.isSelected())
		{
			$(this.element).removeClass('active');
		}
	}

	dropdownMenuItem.prototype.remove = function() {
	    $(this.element).remove();
	    this.launcher.destroy();
	}

	dropdownMenuItem.prototype.addClass = function(className) {
	    $(this.element).addClass(className);
	}
	
	var dropdownMenuOptions =
	{
		element: undefined,
		className: 'dropdownMenu',
		itemOptions: dropdownMenuItemOptions,
		align: 'horizontal'
	}

	function dropdownMenu(options) {
	
		if(options == undefined) options = dropdownMenuOptions;
		for(var option in dropdownMenuOptions)
		if(options[option] == undefined) options[option] = dropdownMenuOptions[option];

		if(options.element)
		{
			var element = options.element;
		}
		else
		{
		    var element = document.createElement('div');
		    var list = document.createElement('ul');
		    $(element).append(list)
		    $("body").append(element);
		    $(element).hide();
		}

		this.element = element;

		$(element).addClass(options.className);

		if (options.align) {
		    $(element).addClass(options.align)
		}

		dropdownMenu.parentClass.constructor.call(this, element);
		
	}

	extend(dropdownMenu, control);

	dropdownMenu.prototype.element;

	dropdownMenu.prototype.getType = function()
	{
		return 'dropdownMenu';
	}

	dropdownMenu.prototype.isVertical = function()
	{
		return $(this.element).is('.vertical');
	}

	dropdownMenu.prototype.isHorizontal = function()
	{
		return $(this.element).is('.horizontal');
	}

	dropdownMenu.prototype.addItem = function(options) {
	    var item = new dropdownMenuItem(this, options);
	    this.updateClasses();
	    return item;
	}

	dropdownMenu.prototype.addItems = function(options) {
	    var key = 0;
	    var itemsArray = new Array();
	    for (key in options) {
	        var item = this.addItem(options[key]);
	        itemsArray.push(item);
	    }
	    return itemsArray;
	}	

	dropdownMenu.prototype.addSeparator = function()
	{
		return new dropdownMenuItem(this, {separator: true});
	}

	dropdownMenu.prototype.listItems = function()
	{
		var items = new Array();
		itemElements = $(this.element).find('li').get();
		for(var i = 0; i < itemElements.length; i++)
			if(itemElements[i].control) items.push(itemElements[i].control);
		return items;
    }

    dropdownMenu.prototype.updateClasses = function() {
        var menu = $(this.element);
        menu.find('li').removeClass('first').removeClass('last');
        menu.find('li:first-child').addClass('first');
        menu.find('li:last-child').addClass('last');
    }


	dropdownMenu.prototype.eachItem = function(fn)
	{
		var items = this.listItems();
		for(var i = 0; i < items.length; i++)
			fn.call(items[i]);
	}

	dropdownMenu.prototype.open = function(left, top, width) {
	    if (top != undefined) $(this.element).css('top', top + 'px');
	    if (left != undefined) $(this.element).css('left', left + 'px');
	    if (width != 0) $(this.element).css('width', width + 'px');
	    if (this.isHidden()) {
	        this.show();
	    }
	}
	
	dropdownMenu.prototype.isOpen = function()
	{ 
		return !this.isHidden();
	}

	dropdownMenu.prototype.close = function()
	{
		if(this.isOpen())
		{
			this.eachItem(function() {this.deselect()});
			this.hide();
		}
	}

	dropdownMenu.prototype.show = function()
	{
		dropdownMenu.parentClass.show.apply(this);
		this.eachItem(function() {this.show()});
	}

	dropdownMenu.prototype.hide = function()
	{
		this.eachItem(function() {this.hide()});
		dropdownMenu.parentClass.hide.apply(this);
	}

	jQuery.fn.dropdownMenu = function(options) {
	    var elements = this.get();
	    for (var i = 0; i < elements.length; i++) {
	        var launcher = new dropdownMenuLauncher(options.launcherOptions);
	        delete options.launcherOptions;
	        var menu = new dropdownMenu(options);
	        launcher.addElement(elements[i]);
	        launcher.addMenu(menu);
	    }
	    return menu;
	}

	var menuLoaderActive = 0;

	function mainMenuLoader(options) {
	    var item = this;
	    $(item.element).addClass('inloading');
	    var complete = function (data) {
	        menuLoaderActive = 0;
	        mainMenuLoader.data = data;
	        var itemElements = $(data).find("[component='page.navigation.menu'] item[key='" + $(item.element).attr('key') + "'] > list > item").get();
	        if (itemElements.length) {
	            var menu;
	            if ($(item.element).hasClass('control')) {
	                var menu = new dropdownMenu({ align: 'vertical' });
	            }
	            else {
	                var menu = new dropdownMenu(options);
	            }
	            item.addMenu(menu);
	            for (var i = 0; i < itemElements.length; i++) {
	                var name = $(itemElements[i]).attr('key');
	                var link = $(itemElements[i]).children('link');
	                var url = link.attr('uri');
	                var launcher = new dropdownMenuLauncher({ event: 'over', loader: mainMenuLoader });
	                item.menu.addItem({ caption: $(link).text(), url: url, name: name, launcher: launcher });
	            }
	            $(item.element).removeClass('inloading').addClass('loaded');
	            if ($(item.element).hasClass('active')) {
	                item.launch();
	            }
	        }
	        else {
	            $(item.element).removeClass('inloading').addClass('loaded');
	            item.destroy();
	        }
	    }
	    var data = {
	        componentFilter: 'page.navigation.menu',
	        outputMimeType: 'application/xml',
	        'page.navigation.menu.deep': $.config.get("mainMenuDeep")
	    };

	    if (mainMenuLoader.data) complete(mainMenuLoader.data)
	    else if (!menuLoaderActive) {
	        menuLoaderActive = 1;
	        $.ajax({type: 'GET',url: '/', data: data, success: complete, dataType: 'xml'});
	    }
	    else {
	        var interval = 0;
	        interval = setInterval(function () {
	            if (mainMenuLoader) {
	                clearInterval(interval);
	                mainMenuLoader.call(item);
	            }
	        }, 10);
        }
	    
	}

	jQuery.fn.mainMenu = function(align, hideSelected) {
	    var elements = this.get();
		if (align == undefined) align = 'horizontal';
	    for (var i = 0; i < elements.length; i++) {
			if ($(elements[i]).hasClass('selected') && hideSelected == true) continue; 
	        var launcher = new dropdownMenuLauncher({ event: 'over', loader: mainMenuLoader, align: align });
	        launcher.addElement(elements[i]);
	    }
	}
