var OverlayConfigBar = Class.create({
  initialize: function(element,options){
    //console.debug('initialize');
    this.element = element;
    this.container = element.select("div").first();
    this.container.hide();
    this.trigger = new Element('img',{src: '/images/icons/pencil.png'});
    this.trigger.setStyle({position:'absolute',left: this.container.getStyle('left'),top: this.container.getStyle('top')});
    this.element.insert(this.trigger);
    this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2,
      openMode: ContextMenu.CLICK_LEFT
        }, options || {});
    this.initObservers();
  },
  initObservers: function(){
    this.element.observe('mouseover', this.mouseOver.bindAsEventListener(this));
    this.element.select('*').each(function(element){      
      element.observe('mouseover', this.mouseOver.bindAsEventListener(this));  
    }.bind(this));    
    this.element.observe('mouseout', this.mouseOut.bindAsEventListener(this));    
  },
  cancelShow: function(){
      if (this.showDelayId) {
          window.clearTimeout(this.showDelayId);
          this.showDelayId = null;
      }
      if (this.showEffect) {
          this.showEffect.cancel();
          this.showEffect = null;
      }
  },
  cancelHide: function(){
      if (this.hideDelayId) {
          window.clearTimeout(this.hideDelayId);
          this.hideDelayId = null;
      }
      if (this.hideEffect) {
          this.hideEffect.cancel();
          this.hideEffect = null;
      }
  },
  mouseOver: function(event){
      Event.stop(event);
      this.cancelHide();
      this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
  },
  mouseOut: function(event){
      Event.stop(event);
      this.cancelShow();
      this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
  },
  show: function(){
    //console.debug('show');
    if (!this.shown) {
      this.shown = true;
      this.showEffect = new Effect.Parallel([
        new Effect.Appear(this.container, {          
          sync:true
        }),
        new Effect.Fade(this.trigger, {          
          sync: true
        })
      ],{duration: this.options.duration});
    }
  },
  hide: function(){
    //console.debug('hide');
    if (this.shown) {
      this.shown = false;
      this.hideEffect = new Effect.Parallel([
        new Effect.Fade(this.container, {         
          sync: true          
        }),
        new Effect.Appear(this.trigger,{          
          sync: true
        })
      ],{duration: this.options.duration});
    }
  }


});
var OverlayConfigBar = Class.create({
  initialize: function(element,options){
    //console.debug('initialize');
    this.element = element;
    this.container = element.select("div").first();
    this.container.hide();
    this.trigger = new Element('img',{src: '/images/icons/pencil.png'});
    this.trigger.setStyle({position:'absolute',left: this.container.getStyle('left'),top: this.container.getStyle('top')});
    this.element.insert(this.trigger);
    this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2,
      openMode: ContextMenu.CLICK_LEFT
        }, options || {});
    this.initObservers();
  },
  initObservers: function(){
    this.element.observe('mouseover', this.mouseOver.bindAsEventListener(this));
    this.element.select('*').each(function(element){      
      element.observe('mouseover', this.mouseOver.bindAsEventListener(this));  
    }.bind(this));    
    this.element.observe('mouseout', this.mouseOut.bindAsEventListener(this));    
  },
  cancelShow: function(){
      if (this.showDelayId) {
          window.clearTimeout(this.showDelayId);
          this.showDelayId = null;
      }
      if (this.showEffect) {
          this.showEffect.cancel();
          this.showEffect = null;
      }
  },
  cancelHide: function(){
      if (this.hideDelayId) {
          window.clearTimeout(this.hideDelayId);
          this.hideDelayId = null;
      }
      if (this.hideEffect) {
          this.hideEffect.cancel();
          this.hideEffect = null;
      }
  },
  mouseOver: function(event){
      Event.stop(event);
      this.cancelHide();
      this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
  },
  mouseOut: function(event){
      Event.stop(event);
      this.cancelShow();
      this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
  },
  show: function(){
    //console.debug('show');
    if (!this.shown) {
      this.shown = true;
      this.showEffect = new Effect.Parallel([
        new Effect.Appear(this.container, {          
          sync:true
        }),
        new Effect.Fade(this.trigger, {          
          sync: true
        })
      ],{duration: this.options.duration});
    }
  },
  hide: function(){
    //console.debug('hide');
    if (this.shown) {
      this.shown = false;
      this.hideEffect = new Effect.Parallel([
        new Effect.Fade(this.container, {         
          sync: true          
        }),
        new Effect.Appear(this.trigger,{          
          sync: true
        })
      ],{duration: this.options.duration});
    }
  }


});
var openPopupWindows = new Array();

/**
 * Type constants for popup buttons
 * Use them for option _type_ on creating a Button instance
 */
var ButtonType = {
    SUBMIT: 'submit',
    CANCEL: 'cancel',
    RESET: 'reset',
    CUSTOM: 'custom'
};

/**
 * Popup button to submit or reset forms and to close popup window
 * To add different click behavior extend this class and overwrite onClick method
 */
Button = Class.create({
    initialize: function(value){
        this.options = Object.extend({
            name: "submit",
            value: value,
            type: ButtonType.SUBMIT,
            onClick: function(){
            }
        }, arguments[1] || {});
        
        this.node = Builder.node('input', {
            'name': this.options.name,
            'class': 'button ' + this.options.type,
            type: 'button',
            value: this.options.value
        });
        Event.observe(this.node, 'click', this.click.bindAsEventListener(this));
    },
    
    click: function(event){
        var openPopupWindow = openPopupWindows.pop();
        openPopupWindows.push(openPopupWindow);
        
        var form = $(openPopupWindow.window).down('FORM');
        this.options.onClick(form);
        if (this.options.type == ButtonType.SUBMIT) {
			      // execute on submit hooks
            Popup.onSubmitHooks.each(function(hook){
               hook(openPopupWindow);
            });
            if (form) {
                var params = form.serialize(true);
                params[this.options.name] = this.options.value;                           
                if (openPopupWindow.options.update) {
                    openPopupWindow.show_loading_overlay();     
                    new Ajax.Updater(openPopupWindow.options.update, form.action, {                       
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.close();
                        }
                    });
                }
                else {
                    openPopupWindow.show_loading_overlay();  
                    new Ajax.Updater(openPopupWindow.body, form.action, {
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.refresh();
                        }
                    });
                }
            }
            else {
                alert('There is no form to submit!');
            }
        }
        else 
            if (this.options.type == ButtonType.CANCEL) {
                openPopupWindow.close();
            }
            else 
                if (this.options.type == ButtonType.RESET) {
                    if (form) {
                        form.reset();
                    }
                    else {
                        alert('There is no form to reset');
                    }
                }
                else 
                    if (this.options.type == ButtonType.CUSTOM) {
                    // Just do the buttons onClick function
                    }
                    else {
                        this.onClick(event, this.options.type);
                    }
    },
    
    onClick: function(event, type){
        alert('Click behavior for button type "' + type + '" is not implemented yet!');
    }
});

/**
 * Constants for popup position
 * Use them for option _position_ on creating a Popup instance
 */
var PopupPosition = {
    CENTER: 'center',
    MOUSE: 'mouse'
};

/**
 *
 */
var Popup = Class.create({
    initialize: function(event, content){
        this.options = Object.extend({
            title: '',
            icon: false,
            content: content,
            width: '500px',
            position: PopupPosition.MOUSE,
            modal: true,
            sameWindow: false,
            url: false,
            update: false,
            closeOnBackgroundClick: false,
            buttons: [],
            onLoad: function(popup){
            },
            onClose: function(popup){
            },
            onRefresh: function(popup){
            }
        }, arguments[2] || {});
        
        if (this.options.sameWindow) {
            openPopupWindow = openPopupWindows.pop();
            if (openPopupWindow) {
                openPopupWindow.unload();
            }
        }
		        
        openPopupWindows.push(this);
        
        this.button = Builder.node('img', {
            'class': 'close',
            src: '/images/icons/cross.png'
        });
        this.buttons = Builder.node('div', {
            'class': 'buttons'
        });
        this.body = Builder.node('div', {
            id: 'popup_body',
            'class': 'body'
        });
        this.body.innerHTML = this.options.content;
        
        // Add registered button objects to popup window
        for (var i = 0; i < this.options.buttons.length; i++) {
            this.buttons.appendChild(this.options.buttons[i].node);
        }
        
        // Add window icon to title bar
        var title = new Array();
        if (this.options.icon) {
            title.push(Builder.node('img', {
                'class': 'icon',
                src: this.options.icon
            }));
        }
        title.push(Builder.node('span', {
            'class': 'name'
        }, this.options.title));
        
        // Create html construct for popup window
        this.window = Builder.node('div', {
            id: 'popup',
            style: 'visibility: hidden; width: ' + this.options.width
        }, [Builder.node('div', {
            'class': 'tl'
        }), Builder.node('div', {
            'class': 't'
        }), Builder.node('div', {
            'class': 'tr'
        }), Builder.node('div', {
            'class': 'l'
        }), Builder.node('div', {
            'class': 'r'
        }), Builder.node('div', {
            'class': 'bl'
        }), Builder.node('div', {
            'class': 'b'
        }), Builder.node('div', {
            'class': 'br'
        }), Builder.node('div', {
            'class': 'title'
        }, title), this.button, this.body, this.buttons]);
        
        // Create modal background layer
        this.background = Builder.node('div', {
            id: 'popup_modal_layer',
            style: 'display: none'
        });
        if (this.options.closeOnBackgroundClick) {
            this.background.setAttribute('class', 'closeable');
        }
        
        // Register events
        this.boundKeyup = this.keyup.bindAsEventListener(this);
        this.boundScroll = this.scroll.bindAsEventListener(this);
        this.boundRefresh = this.refresh.bindAsEventListener(this);
        Event.observe(window, 'resize', this.boundRefresh);
        Event.observe(window, 'scroll', this.boundScroll);
        Event.observe(document, 'keyup', this.boundKeyup);
        if (this.options.closeOnBackgroundClick) {
            Event.observe(this.background, 'click', this.close.bindAsEventListener(this));
        }
        Event.observe(this.button, 'click', this.close.bindAsEventListener(this));
        
        // Append popup window and modal background to body
        document.getElementsByTagName('body')[0].appendChild(this.background);
        document.getElementsByTagName('body')[0].appendChild(this.window);
        
        this.options.onLoad(this);
        
        // Show modal background if needed
        if (this.options.modal) {
            this.background.show();
        }
        
        // Set opening position according to mouse position
        if (this.options.position == PopupPosition.MOUSE) {
            this.moveToMousePosition(event);
        }
        this.refresh();
                
        // Load popup content with ajax and reposition popup
        if (this.options.url) {            
            this.show_loading_overlay();
            new Ajax.Updater(this.body, this.options.url, {
                evalScripts: true,                
                onComplete: function(transport){                    
                    this.hide_loading_overlay();
                    if (this.options.position == PopupPosition.MOUSE) {
                        this.moveToMousePosition(false);
                    }
                    this.refresh();
                }.bind(this)
            });
        }
    },

    show_loading_overlay: function(){
      if(!this.loading_overlay){
        var el = new Element('div', {'class': 'loading_overlay', style: 'text-align: center; vertical-align: middle; opacity: 0.5; background: lightgray; position: absolute; left: 0; top: 0; width: ' + this.window.getWidth() + 'px; height: '+ this.window.getHeight() + 'px;'});
        el.insert(new Element('img', {src: '/images/spacer.gif', style: 'vertical-align:middle;height:100%;width:1px;'}));
        el.insert(new Element('img', {src: '/images/ajax-loader.gif', style: 'vertical-align:middle;'}));
        this.loading_overlay = el;
        this.window.insert(this.loading_overlay);
      }
    },

    hide_loading_overlay: function(){
      if(this.loading_overlay){
        this.loading_overlay.remove();
        this.loading_overlay = null;
      }
    },
    
    close: function(event){
        // Hide popup window and modal layer
        this.window.hide();
        this.background.hide();
        
        // Unload current popup window
        this.unload();
    },
    
    keyup: function(event){
        if (!event) 
            event = window.event;
        
        var code = 0;
        if (event.which) {
            code = event.which;
        }
        else 
            if (event.keyCode) {
                code = event.keyCode;
            }
        
        // Close popup window if ESC button was pressed on keyboard
        if (code == 27) {
          Event.stop(event);
          this.close();
        }
        else 
            if (code == 13) {
                if (!event.element() || !(event.element() instanceof HTMLTextAreaElement)) {
                    Event.stop(event);
                    var firstButton = $A(this.buttons.childNodes).first();                    
                    if (firstButton) {
                        firstButton.click();
                    }
                }
            }
    },
    
    scroll: function(event){
        if (this.options.modal) {
        
            // Move modal layer to current viewport position
            var viewportDimensions = document.viewport.getDimensions();
            var scrollOffset = document.viewport.getScrollOffsets();
            
            this.background.style.top = scrollOffset.top + 'px';
            this.background.style.left = scrollOffset.left + 'px';
            this.background.style.height = viewportDimensions.height + 'px';
            this.background.style.width = viewportDimensions.width + 'px';
        }
    },
    
    refresh: function(){        
        this.options.onRefresh(this);
        if (this.window) {        
            // Calculate popup position in the center of viewport
            if (this.options.position == PopupPosition.CENTER) {
                var scrollOffset = document.viewport.getScrollOffsets();
                var borderSize = this.getBorderSize();
                
                var windowPositionTop = scrollOffset.top + ((document.viewport.getHeight() / 2) - (this.window.offsetHeight / 2));
                var windowPositionLeft = scrollOffset.left + ((document.viewport.getWidth() / 2) - (this.window.offsetWidth / 2));
                
                // If viewport is smaller than popup window, place popup in topper left corner
                if (windowPositionTop - borderSize.top < scrollOffset.top) {
                    windowPositionTop = scrollOffset.top + borderSize.top;
                }
                
                if (windowPositionLeft - borderSize.left < scrollOffset.left) {
                    windowPositionLeft = scrollOffset.left + borderSize.left;
                }
                
                this.window.style.top = windowPositionTop + 'px';
                this.window.style.left = windowPositionLeft + 'px';
            }
            this.window.style.visibility = 'visible';
            
            // position modal background if available
            this.scroll();
        }
    },
    
    moveToMousePosition: function(event){
        if (!event && event != false) 
            event = window.event;
        
        if (!event) {
            // Set virtual mouse position to current position 
            // Only used for second position adjustments after loading popup content with ajax
            var windowOffset = Element.cumulativeOffset(this.window);
            var mouseOffsetTop = windowOffset.top;
            var mouseOffsetLeft = windowOffset.left;
        }
        else {
            // Set position based on mouse position on popup open
            var mouseOffsetTop = Event.pointerY(event);
            var mouseOffsetLeft = Event.pointerX(event);
        }
        
        var windowOffsetLeft = 0;
        var windowOffsetTop = 0;
        
        var scrollOffset = document.viewport.getScrollOffsets();
        var viewportDimensions = document.viewport.getDimensions();
        var borderSize = this.getBorderSize();
        
        // Correction of mouse click position if coordinates are too narrow at the browser border
        if (mouseOffsetTop - borderSize.top < scrollOffset.top) {
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        
        if (mouseOffsetLeft - borderSize.left < scrollOffset.left) {
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        
        if (this.window.offsetHeight + borderSize.top + borderSize.bottom > viewportDimensions.height) {
            // If popup window is heigher than viewport, set position to viewports top border
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        else 
            if (mouseOffsetTop + this.window.offsetHeight + borderSize.bottom > scrollOffset.top + viewportDimensions.height) {
                // If popup window overlaps viewports bottom border, correct top position to fit
                windowOffsetTop = scrollOffset.top + viewportDimensions.height - mouseOffsetTop - this.window.offsetHeight - borderSize.bottom;
            }
        
        if (this.window.offsetWidth + borderSize.left + borderSize.right > viewportDimensions.width) {
            // If popup window is wider than viewport, set position to viewports left border
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        else 
            if (mouseOffsetLeft + this.window.offsetWidth + borderSize.right > scrollOffset.left + viewportDimensions.width) {
                // If popup window overlaps viewports right border, correct left position to fit
                windowOffsetLeft = scrollOffset.left + viewportDimensions.width - mouseOffsetLeft - this.window.offsetWidth - borderSize.right;
            }
        
        this.window.style.top = (mouseOffsetTop + windowOffsetTop) + 'px';
        this.window.style.left = (mouseOffsetLeft + windowOffsetLeft) + 'px';
    },
    
    getBorderSize: function(){
        if (this.window) {
            // Calculates border sizes needed for window positioning
            return {
                top: Element.getHeight(this.window.down('.t')),
                right: Element.getWidth(this.window.down('.r')),
                bottom: Element.getHeight(this.window.down('.b')),
                left: Element.getWidth(this.window.down('.l'))
            };
        }
        // If there's no window there is no border :-)
        return {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
        };
    },
    
    unload: function(){
        this.options.onClose(this);
        // execute on close hooks
        Popup.onCloseHooks.each(function(hook){
            hook(this);
        }.bind(this));
        // Unregister event observation
        Event.stopObserving(window, 'resize', this.boundRefresh);
        Event.stopObserving(window, 'scroll', this.boundScroll);
        Event.stopObserving(document, 'keyup', this.boundKeyup);
        
        // Total removal of popup windows html structure
        this.window.update("")
        this.window.purge()
        this.window.parentNode.removeChild(this.window);
        this.background.purge()
        this.background.parentNode.removeChild(this.background);
        
        for (var i = 0; i < openPopupWindows.length; i++) {
            if (openPopupWindows[i] == this) {
                openPopupWindows.splice(i, 1);
                break;
            }
        }
    }
});

/**
 * Static function to close open popup window if one is open
 */
Popup.close = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindow.close();
    }
};

/**
 * Static function to reposition popup window if one is open
 */
Popup.refresh = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindows.push(openPopupWindow);
        openPopupWindow.refresh();
    }
};

/**
 * on submit hooks are executed before the form gets submitted
 */
Popup.onSubmitHooks = $A();
Popup.addOnSubmitHook = function(f){
    Popup.onSubmitHooks.push(f);
};

/**
 * On close hooks are executed before the popup gets closed
 */
Popup.onCloseHooks = $A();
Popup.addOnCloseHook = function(f){
    Popup.onCloseHooks.push(f);
};

var Tooltip = Class.create({
    initialize: function(hoverElement, content, options){
        this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2
        }, options || {});
		this.hoverElement = $(hoverElement);
        this.container = new Element('div', {
            'class': 'tooltip',
            'style': 'display:none;position:absolute;z-index: 1000000;'
        });
        this.container.update(content);
        this.hoverElement.insert(this.container);        
		this.initObservers();
    },
    initObservers: function(){
        this.hoverElement.observe('mouseover', this.mouseOver.bindAsEventListener(this));
        this.hoverElement.observe('mouseout', this.mouseOut.bindAsEventListener(this));        
    },
    cancelShow: function(){
        if (this.showDelayId) {
            window.clearTimeout(this.showDelayId);
            this.showDelayId = null;
        }
        if (this.showEffect) {
            this.showEffect.cancel();
            this.showEffect = null;
        }
    },
    cancelHide: function(){
        if (this.hideDelayId) {
            window.clearTimeout(this.hideDelayId);
            this.hideDelayId = null;
        }
        if (this.hideEffect) {
            this.hideEffect.cancel();
            this.hideEffect = null;
        }
    },
    mouseOver: function(event){
        Event.stop(event);
        this.cancelHide();
        this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
    },
    mouseOut: function(event){
        Event.stop(event);
        this.cancelShow();
        this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
    },
    show: function(){
        if (!this.shown) {
            this.shown = true;
            this.showEffect = new Effect.Appear(this.container, {
                duration: this.options.duration
            });
        }
    },
    hide: function(){
        if (this.shown) {
            this.shown = false;
            this.hideEffect = new Effect.Fade(this.container, {
                duration: this.options.duration
            });
        }
    }
});

var openPopupWindows = new Array();

/**
 * Type constants for popup buttons
 * Use them for option _type_ on creating a Button instance
 */
var ButtonType = {
    SUBMIT: 'submit',
    CANCEL: 'cancel',
    RESET: 'reset',
    CUSTOM: 'custom'
};

/**
 * Popup button to submit or reset forms and to close popup window
 * To add different click behavior extend this class and overwrite onClick method
 */
Button = Class.create({
    initialize: function(value){
        this.options = Object.extend({
            name: "submit",
            value: value,
            type: ButtonType.SUBMIT,
            onClick: function(){
            }
        }, arguments[1] || {});
        
        this.node = Builder.node('input', {
            'name': this.options.name,
            'class': 'button ' + this.options.type,
            type: 'button',
            value: this.options.value
        });
        Event.observe(this.node, 'click', this.click.bindAsEventListener(this));
    },
    
    click: function(event){
        var openPopupWindow = openPopupWindows.pop();
        openPopupWindows.push(openPopupWindow);
        
        var form = $(openPopupWindow.window).down('FORM');
        this.options.onClick(form);
        if (this.options.type == ButtonType.SUBMIT) {
			      // execute on submit hooks
            Popup.onSubmitHooks.each(function(hook){
               hook(openPopupWindow);
            });
            if (form) {
                var params = form.serialize(true);
                params[this.options.name] = this.options.value;                           
                if (openPopupWindow.options.update) {
                    openPopupWindow.show_loading_overlay();     
                    new Ajax.Updater(openPopupWindow.options.update, form.action, {                       
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.close();
                        }
                    });
                }
                else {
                    openPopupWindow.show_loading_overlay();  
                    new Ajax.Updater(openPopupWindow.body, form.action, {
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.refresh();
                        }
                    });
                }
            }
            else {
                alert('There is no form to submit!');
            }
        }
        else 
            if (this.options.type == ButtonType.CANCEL) {
                openPopupWindow.close();
            }
            else 
                if (this.options.type == ButtonType.RESET) {
                    if (form) {
                        form.reset();
                    }
                    else {
                        alert('There is no form to reset');
                    }
                }
                else 
                    if (this.options.type == ButtonType.CUSTOM) {
                    // Just do the buttons onClick function
                    }
                    else {
                        this.onClick(event, this.options.type);
                    }
    },
    
    onClick: function(event, type){
        alert('Click behavior for button type "' + type + '" is not implemented yet!');
    }
});

/**
 * Constants for popup position
 * Use them for option _position_ on creating a Popup instance
 */
var PopupPosition = {
    CENTER: 'center',
    MOUSE: 'mouse'
};

/**
 *
 */
var Popup = Class.create({
    initialize: function(event, content){
        this.options = Object.extend({
            title: '',
            icon: false,
            content: content,
            width: '500px',
            position: PopupPosition.MOUSE,
            modal: true,
            sameWindow: false,
            url: false,
            update: false,
            closeOnBackgroundClick: false,
            buttons: [],
            onLoad: function(popup){
            },
            onClose: function(popup){
            },
            onRefresh: function(popup){
            }
        }, arguments[2] || {});
        
        if (this.options.sameWindow) {
            openPopupWindow = openPopupWindows.pop();
            if (openPopupWindow) {
                openPopupWindow.unload();
            }
        }
		        
        openPopupWindows.push(this);
        
        this.button = Builder.node('img', {
            'class': 'close',
            src: '/images/icons/cross.png'
        });
        this.buttons = Builder.node('div', {
            'class': 'buttons'
        });
        this.body = Builder.node('div', {
            id: 'popup_body',
            'class': 'body'
        });
        this.body.innerHTML = this.options.content;
        
        // Add registered button objects to popup window
        for (var i = 0; i < this.options.buttons.length; i++) {
            this.buttons.appendChild(this.options.buttons[i].node);
        }
        
        // Add window icon to title bar
        var title = new Array();
        if (this.options.icon) {
            title.push(Builder.node('img', {
                'class': 'icon',
                src: this.options.icon
            }));
        }
        title.push(Builder.node('span', {
            'class': 'name'
        }, this.options.title));
        
        // Create html construct for popup window
        this.window = Builder.node('div', {
            id: 'popup',
            style: 'visibility: hidden; width: ' + this.options.width
        }, [Builder.node('div', {
            'class': 'tl'
        }), Builder.node('div', {
            'class': 't'
        }), Builder.node('div', {
            'class': 'tr'
        }), Builder.node('div', {
            'class': 'l'
        }), Builder.node('div', {
            'class': 'r'
        }), Builder.node('div', {
            'class': 'bl'
        }), Builder.node('div', {
            'class': 'b'
        }), Builder.node('div', {
            'class': 'br'
        }), Builder.node('div', {
            'class': 'title'
        }, title), this.button, this.body, this.buttons]);
        
        // Create modal background layer
        this.background = Builder.node('div', {
            id: 'popup_modal_layer',
            style: 'display: none'
        });
        if (this.options.closeOnBackgroundClick) {
            this.background.setAttribute('class', 'closeable');
        }
        
        // Register events
        this.boundKeyup = this.keyup.bindAsEventListener(this);
        this.boundScroll = this.scroll.bindAsEventListener(this);
        this.boundRefresh = this.refresh.bindAsEventListener(this);
        Event.observe(window, 'resize', this.boundRefresh);
        Event.observe(window, 'scroll', this.boundScroll);
        Event.observe(document, 'keyup', this.boundKeyup);
        if (this.options.closeOnBackgroundClick) {
            Event.observe(this.background, 'click', this.close.bindAsEventListener(this));
        }
        Event.observe(this.button, 'click', this.close.bindAsEventListener(this));
        
        // Append popup window and modal background to body
        document.getElementsByTagName('body')[0].appendChild(this.background);
        document.getElementsByTagName('body')[0].appendChild(this.window);
        
        this.options.onLoad(this);
        
        // Show modal background if needed
        if (this.options.modal) {
            this.background.show();
        }
        
        // Set opening position according to mouse position
        if (this.options.position == PopupPosition.MOUSE) {
            this.moveToMousePosition(event);
        }
        this.refresh();
                
        // Load popup content with ajax and reposition popup
        if (this.options.url) {            
            this.show_loading_overlay();
            new Ajax.Updater(this.body, this.options.url, {
                evalScripts: true,                
                onComplete: function(transport){                    
                    this.hide_loading_overlay();
                    if (this.options.position == PopupPosition.MOUSE) {
                        this.moveToMousePosition(false);
                    }
                    this.refresh();
                }.bind(this)
            });
        }
    },

    show_loading_overlay: function(){
      if(!this.loading_overlay){
        var el = new Element('div', {'class': 'loading_overlay', style: 'text-align: center; vertical-align: middle; opacity: 0.5; background: lightgray; position: absolute; left: 0; top: 0; width: ' + this.window.getWidth() + 'px; height: '+ this.window.getHeight() + 'px;'});
        el.insert(new Element('img', {src: '/images/spacer.gif', style: 'vertical-align:middle;height:100%;width:1px;'}));
        el.insert(new Element('img', {src: '/images/ajax-loader.gif', style: 'vertical-align:middle;'}));
        this.loading_overlay = el;
        this.window.insert(this.loading_overlay);
      }
    },

    hide_loading_overlay: function(){
      if(this.loading_overlay){
        this.loading_overlay.remove();
        this.loading_overlay = null;
      }
    },
    
    close: function(event){
        // Hide popup window and modal layer
        this.window.hide();
        this.background.hide();
        
        // Unload current popup window
        this.unload();
    },
    
    keyup: function(event){
        if (!event) 
            event = window.event;
        
        var code = 0;
        if (event.which) {
            code = event.which;
        }
        else 
            if (event.keyCode) {
                code = event.keyCode;
            }
        
        // Close popup window if ESC button was pressed on keyboard
        if (code == 27) {
          Event.stop(event);
          this.close();
        }
        else 
            if (code == 13) {
                if (!event.element() || !(event.element() instanceof HTMLTextAreaElement)) {
                    Event.stop(event);
                    var firstButton = $A(this.buttons.childNodes).first();                    
                    if (firstButton) {
                        firstButton.click();
                    }
                }
            }
    },
    
    scroll: function(event){
        if (this.options.modal) {
        
            // Move modal layer to current viewport position
            var viewportDimensions = document.viewport.getDimensions();
            var scrollOffset = document.viewport.getScrollOffsets();
            
            this.background.style.top = scrollOffset.top + 'px';
            this.background.style.left = scrollOffset.left + 'px';
            this.background.style.height = viewportDimensions.height + 'px';
            this.background.style.width = viewportDimensions.width + 'px';
        }
    },
    
    refresh: function(){        
        this.options.onRefresh(this);
        if (this.window) {        
            // Calculate popup position in the center of viewport
            if (this.options.position == PopupPosition.CENTER) {
                var scrollOffset = document.viewport.getScrollOffsets();
                var borderSize = this.getBorderSize();
                
                var windowPositionTop = scrollOffset.top + ((document.viewport.getHeight() / 2) - (this.window.offsetHeight / 2));
                var windowPositionLeft = scrollOffset.left + ((document.viewport.getWidth() / 2) - (this.window.offsetWidth / 2));
                
                // If viewport is smaller than popup window, place popup in topper left corner
                if (windowPositionTop - borderSize.top < scrollOffset.top) {
                    windowPositionTop = scrollOffset.top + borderSize.top;
                }
                
                if (windowPositionLeft - borderSize.left < scrollOffset.left) {
                    windowPositionLeft = scrollOffset.left + borderSize.left;
                }
                
                this.window.style.top = windowPositionTop + 'px';
                this.window.style.left = windowPositionLeft + 'px';
            }
            this.window.style.visibility = 'visible';
            
            // position modal background if available
            this.scroll();
        }
    },
    
    moveToMousePosition: function(event){
        if (!event && event != false) 
            event = window.event;
        
        if (!event) {
            // Set virtual mouse position to current position 
            // Only used for second position adjustments after loading popup content with ajax
            var windowOffset = Element.cumulativeOffset(this.window);
            var mouseOffsetTop = windowOffset.top;
            var mouseOffsetLeft = windowOffset.left;
        }
        else {
            // Set position based on mouse position on popup open
            var mouseOffsetTop = Event.pointerY(event);
            var mouseOffsetLeft = Event.pointerX(event);
        }
        
        var windowOffsetLeft = 0;
        var windowOffsetTop = 0;
        
        var scrollOffset = document.viewport.getScrollOffsets();
        var viewportDimensions = document.viewport.getDimensions();
        var borderSize = this.getBorderSize();
        
        // Correction of mouse click position if coordinates are too narrow at the browser border
        if (mouseOffsetTop - borderSize.top < scrollOffset.top) {
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        
        if (mouseOffsetLeft - borderSize.left < scrollOffset.left) {
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        
        if (this.window.offsetHeight + borderSize.top + borderSize.bottom > viewportDimensions.height) {
            // If popup window is heigher than viewport, set position to viewports top border
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        else 
            if (mouseOffsetTop + this.window.offsetHeight + borderSize.bottom > scrollOffset.top + viewportDimensions.height) {
                // If popup window overlaps viewports bottom border, correct top position to fit
                windowOffsetTop = scrollOffset.top + viewportDimensions.height - mouseOffsetTop - this.window.offsetHeight - borderSize.bottom;
            }
        
        if (this.window.offsetWidth + borderSize.left + borderSize.right > viewportDimensions.width) {
            // If popup window is wider than viewport, set position to viewports left border
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        else 
            if (mouseOffsetLeft + this.window.offsetWidth + borderSize.right > scrollOffset.left + viewportDimensions.width) {
                // If popup window overlaps viewports right border, correct left position to fit
                windowOffsetLeft = scrollOffset.left + viewportDimensions.width - mouseOffsetLeft - this.window.offsetWidth - borderSize.right;
            }
        
        this.window.style.top = (mouseOffsetTop + windowOffsetTop) + 'px';
        this.window.style.left = (mouseOffsetLeft + windowOffsetLeft) + 'px';
    },
    
    getBorderSize: function(){
        if (this.window) {
            // Calculates border sizes needed for window positioning
            return {
                top: Element.getHeight(this.window.down('.t')),
                right: Element.getWidth(this.window.down('.r')),
                bottom: Element.getHeight(this.window.down('.b')),
                left: Element.getWidth(this.window.down('.l'))
            };
        }
        // If there's no window there is no border :-)
        return {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
        };
    },
    
    unload: function(){
        this.options.onClose(this);
        // execute on close hooks
        Popup.onCloseHooks.each(function(hook){
            hook(this);
        }.bind(this));
        // Unregister event observation
        Event.stopObserving(window, 'resize', this.boundRefresh);
        Event.stopObserving(window, 'scroll', this.boundScroll);
        Event.stopObserving(document, 'keyup', this.boundKeyup);
        
        // Total removal of popup windows html structure
        this.window.update("")
        this.window.purge()
        this.window.parentNode.removeChild(this.window);
        this.background.purge()
        this.background.parentNode.removeChild(this.background);
        
        for (var i = 0; i < openPopupWindows.length; i++) {
            if (openPopupWindows[i] == this) {
                openPopupWindows.splice(i, 1);
                break;
            }
        }
    }
});

/**
 * Static function to close open popup window if one is open
 */
Popup.close = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindow.close();
    }
};

/**
 * Static function to reposition popup window if one is open
 */
Popup.refresh = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindows.push(openPopupWindow);
        openPopupWindow.refresh();
    }
};

/**
 * on submit hooks are executed before the form gets submitted
 */
Popup.onSubmitHooks = $A();
Popup.addOnSubmitHook = function(f){
    Popup.onSubmitHooks.push(f);
};

/**
 * On close hooks are executed before the popup gets closed
 */
Popup.onCloseHooks = $A();
Popup.addOnCloseHook = function(f){
    Popup.onCloseHooks.push(f);
};

var Tooltip = Class.create({
    initialize: function(hoverElement, content, options){
        this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2
        }, options || {});
		this.hoverElement = $(hoverElement);
        this.container = new Element('div', {
            'class': 'tooltip',
            'style': 'display:none;position:absolute;z-index: 1000000;'
        });
        this.container.update(content);
        this.hoverElement.insert(this.container);        
		this.initObservers();
    },
    initObservers: function(){
        this.hoverElement.observe('mouseover', this.mouseOver.bindAsEventListener(this));
        this.hoverElement.observe('mouseout', this.mouseOut.bindAsEventListener(this));        
    },
    cancelShow: function(){
        if (this.showDelayId) {
            window.clearTimeout(this.showDelayId);
            this.showDelayId = null;
        }
        if (this.showEffect) {
            this.showEffect.cancel();
            this.showEffect = null;
        }
    },
    cancelHide: function(){
        if (this.hideDelayId) {
            window.clearTimeout(this.hideDelayId);
            this.hideDelayId = null;
        }
        if (this.hideEffect) {
            this.hideEffect.cancel();
            this.hideEffect = null;
        }
    },
    mouseOver: function(event){
        Event.stop(event);
        this.cancelHide();
        this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
    },
    mouseOut: function(event){
        Event.stop(event);
        this.cancelShow();
        this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
    },
    show: function(){
        if (!this.shown) {
            this.shown = true;
            this.showEffect = new Effect.Appear(this.container, {
                duration: this.options.duration
            });
        }
    },
    hide: function(){
        if (this.shown) {
            this.shown = false;
            this.hideEffect = new Effect.Fade(this.container, {
                duration: this.options.duration
            });
        }
    }
});

var openPopupWindows = new Array();

/**
 * Type constants for popup buttons
 * Use them for option _type_ on creating a Button instance
 */
var ButtonType = {
    SUBMIT: 'submit',
    CANCEL: 'cancel',
    RESET: 'reset',
    CUSTOM: 'custom'
};

/**
 * Popup button to submit or reset forms and to close popup window
 * To add different click behavior extend this class and overwrite onClick method
 */
Button = Class.create({
    initialize: function(value){
        this.options = Object.extend({
            name: "submit",
            value: value,
            type: ButtonType.SUBMIT,
            onClick: function(){
            }
        }, arguments[1] || {});
        
        this.node = Builder.node('input', {
            'name': this.options.name,
            'class': 'button ' + this.options.type,
            type: 'button',
            value: this.options.value
        });
        Event.observe(this.node, 'click', this.click.bindAsEventListener(this));
    },
    
    click: function(event){
        var openPopupWindow = openPopupWindows.pop();
        openPopupWindows.push(openPopupWindow);
        
        var form = $(openPopupWindow.window).down('FORM');
        this.options.onClick(form);
        if (this.options.type == ButtonType.SUBMIT) {
			      // execute on submit hooks
            Popup.onSubmitHooks.each(function(hook){
               hook(openPopupWindow);
            });
            if (form) {
                var params = form.serialize(true);
                params[this.options.name] = this.options.value;                           
                if (openPopupWindow.options.update) {
                    openPopupWindow.show_loading_overlay();     
                    new Ajax.Updater(openPopupWindow.options.update, form.action, {                       
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.close();
                        }
                    });
                }
                else {
                    openPopupWindow.show_loading_overlay();  
                    new Ajax.Updater(openPopupWindow.body, form.action, {
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.refresh();
                        }
                    });
                }
            }
            else {
                alert('There is no form to submit!');
            }
        }
        else 
            if (this.options.type == ButtonType.CANCEL) {
                openPopupWindow.close();
            }
            else 
                if (this.options.type == ButtonType.RESET) {
                    if (form) {
                        form.reset();
                    }
                    else {
                        alert('There is no form to reset');
                    }
                }
                else 
                    if (this.options.type == ButtonType.CUSTOM) {
                    // Just do the buttons onClick function
                    }
                    else {
                        this.onClick(event, this.options.type);
                    }
    },
    
    onClick: function(event, type){
        alert('Click behavior for button type "' + type + '" is not implemented yet!');
    }
});

/**
 * Constants for popup position
 * Use them for option _position_ on creating a Popup instance
 */
var PopupPosition = {
    CENTER: 'center',
    MOUSE: 'mouse'
};

/**
 *
 */
var Popup = Class.create({
    initialize: function(event, content){
        this.options = Object.extend({
            title: '',
            icon: false,
            content: content,
            width: '500px',
            position: PopupPosition.MOUSE,
            modal: true,
            sameWindow: false,
            url: false,
            update: false,
            closeOnBackgroundClick: false,
            buttons: [],
            onLoad: function(popup){
            },
            onClose: function(popup){
            },
            onRefresh: function(popup){
            }
        }, arguments[2] || {});
        
        if (this.options.sameWindow) {
            openPopupWindow = openPopupWindows.pop();
            if (openPopupWindow) {
                openPopupWindow.unload();
            }
        }
		        
        openPopupWindows.push(this);
        
        this.button = Builder.node('img', {
            'class': 'close',
            src: '/images/icons/cross.png'
        });
        this.buttons = Builder.node('div', {
            'class': 'buttons'
        });
        this.body = Builder.node('div', {
            id: 'popup_body',
            'class': 'body'
        });
        this.body.innerHTML = this.options.content;
        
        // Add registered button objects to popup window
        for (var i = 0; i < this.options.buttons.length; i++) {
            this.buttons.appendChild(this.options.buttons[i].node);
        }
        
        // Add window icon to title bar
        var title = new Array();
        if (this.options.icon) {
            title.push(Builder.node('img', {
                'class': 'icon',
                src: this.options.icon
            }));
        }
        title.push(Builder.node('span', {
            'class': 'name'
        }, this.options.title));
        
        // Create html construct for popup window
        this.window = Builder.node('div', {
            id: 'popup',
            style: 'visibility: hidden; width: ' + this.options.width
        }, [Builder.node('div', {
            'class': 'tl'
        }), Builder.node('div', {
            'class': 't'
        }), Builder.node('div', {
            'class': 'tr'
        }), Builder.node('div', {
            'class': 'l'
        }), Builder.node('div', {
            'class': 'r'
        }), Builder.node('div', {
            'class': 'bl'
        }), Builder.node('div', {
            'class': 'b'
        }), Builder.node('div', {
            'class': 'br'
        }), Builder.node('div', {
            'class': 'title'
        }, title), this.button, this.body, this.buttons]);
        
        // Create modal background layer
        this.background = Builder.node('div', {
            id: 'popup_modal_layer',
            style: 'display: none'
        });
        if (this.options.closeOnBackgroundClick) {
            this.background.setAttribute('class', 'closeable');
        }
        
        // Register events
        this.boundKeyup = this.keyup.bindAsEventListener(this);
        this.boundScroll = this.scroll.bindAsEventListener(this);
        this.boundRefresh = this.refresh.bindAsEventListener(this);
        Event.observe(window, 'resize', this.boundRefresh);
        Event.observe(window, 'scroll', this.boundScroll);
        Event.observe(document, 'keyup', this.boundKeyup);
        if (this.options.closeOnBackgroundClick) {
            Event.observe(this.background, 'click', this.close.bindAsEventListener(this));
        }
        Event.observe(this.button, 'click', this.close.bindAsEventListener(this));
        
        // Append popup window and modal background to body
        document.getElementsByTagName('body')[0].appendChild(this.background);
        document.getElementsByTagName('body')[0].appendChild(this.window);
        
        this.options.onLoad(this);
        
        // Show modal background if needed
        if (this.options.modal) {
            this.background.show();
        }
        
        // Set opening position according to mouse position
        if (this.options.position == PopupPosition.MOUSE) {
            this.moveToMousePosition(event);
        }
        this.refresh();
                
        // Load popup content with ajax and reposition popup
        if (this.options.url) {            
            this.show_loading_overlay();
            new Ajax.Updater(this.body, this.options.url, {
                evalScripts: true,                
                onComplete: function(transport){                    
                    this.hide_loading_overlay();
                    if (this.options.position == PopupPosition.MOUSE) {
                        this.moveToMousePosition(false);
                    }
                    this.refresh();
                }.bind(this)
            });
        }
    },

    show_loading_overlay: function(){
      if(!this.loading_overlay){
        var el = new Element('div', {'class': 'loading_overlay', style: 'text-align: center; vertical-align: middle; opacity: 0.5; background: lightgray; position: absolute; left: 0; top: 0; width: ' + this.window.getWidth() + 'px; height: '+ this.window.getHeight() + 'px;'});
        el.insert(new Element('img', {src: '/images/spacer.gif', style: 'vertical-align:middle;height:100%;width:1px;'}));
        el.insert(new Element('img', {src: '/images/ajax-loader.gif', style: 'vertical-align:middle;'}));
        this.loading_overlay = el;
        this.window.insert(this.loading_overlay);
      }
    },

    hide_loading_overlay: function(){
      if(this.loading_overlay){
        this.loading_overlay.remove();
        this.loading_overlay = null;
      }
    },
    
    close: function(event){
        // Hide popup window and modal layer
        this.window.hide();
        this.background.hide();
        
        // Unload current popup window
        this.unload();
    },
    
    keyup: function(event){
        if (!event) 
            event = window.event;
        
        var code = 0;
        if (event.which) {
            code = event.which;
        }
        else 
            if (event.keyCode) {
                code = event.keyCode;
            }
        
        // Close popup window if ESC button was pressed on keyboard
        if (code == 27) {
          Event.stop(event);
          this.close();
        }
        else 
            if (code == 13) {
                if (!event.element() || !(event.element() instanceof HTMLTextAreaElement)) {
                    Event.stop(event);
                    var firstButton = $A(this.buttons.childNodes).first();                    
                    if (firstButton) {
                        firstButton.click();
                    }
                }
            }
    },
    
    scroll: function(event){
        if (this.options.modal) {
        
            // Move modal layer to current viewport position
            var viewportDimensions = document.viewport.getDimensions();
            var scrollOffset = document.viewport.getScrollOffsets();
            
            this.background.style.top = scrollOffset.top + 'px';
            this.background.style.left = scrollOffset.left + 'px';
            this.background.style.height = viewportDimensions.height + 'px';
            this.background.style.width = viewportDimensions.width + 'px';
        }
    },
    
    refresh: function(){        
        this.options.onRefresh(this);
        if (this.window) {        
            // Calculate popup position in the center of viewport
            if (this.options.position == PopupPosition.CENTER) {
                var scrollOffset = document.viewport.getScrollOffsets();
                var borderSize = this.getBorderSize();
                
                var windowPositionTop = scrollOffset.top + ((document.viewport.getHeight() / 2) - (this.window.offsetHeight / 2));
                var windowPositionLeft = scrollOffset.left + ((document.viewport.getWidth() / 2) - (this.window.offsetWidth / 2));
                
                // If viewport is smaller than popup window, place popup in topper left corner
                if (windowPositionTop - borderSize.top < scrollOffset.top) {
                    windowPositionTop = scrollOffset.top + borderSize.top;
                }
                
                if (windowPositionLeft - borderSize.left < scrollOffset.left) {
                    windowPositionLeft = scrollOffset.left + borderSize.left;
                }
                
                this.window.style.top = windowPositionTop + 'px';
                this.window.style.left = windowPositionLeft + 'px';
            }
            this.window.style.visibility = 'visible';
            
            // position modal background if available
            this.scroll();
        }
    },
    
    moveToMousePosition: function(event){
        if (!event && event != false) 
            event = window.event;
        
        if (!event) {
            // Set virtual mouse position to current position 
            // Only used for second position adjustments after loading popup content with ajax
            var windowOffset = Element.cumulativeOffset(this.window);
            var mouseOffsetTop = windowOffset.top;
            var mouseOffsetLeft = windowOffset.left;
        }
        else {
            // Set position based on mouse position on popup open
            var mouseOffsetTop = Event.pointerY(event);
            var mouseOffsetLeft = Event.pointerX(event);
        }
        
        var windowOffsetLeft = 0;
        var windowOffsetTop = 0;
        
        var scrollOffset = document.viewport.getScrollOffsets();
        var viewportDimensions = document.viewport.getDimensions();
        var borderSize = this.getBorderSize();
        
        // Correction of mouse click position if coordinates are too narrow at the browser border
        if (mouseOffsetTop - borderSize.top < scrollOffset.top) {
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        
        if (mouseOffsetLeft - borderSize.left < scrollOffset.left) {
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        
        if (this.window.offsetHeight + borderSize.top + borderSize.bottom > viewportDimensions.height) {
            // If popup window is heigher than viewport, set position to viewports top border
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        else 
            if (mouseOffsetTop + this.window.offsetHeight + borderSize.bottom > scrollOffset.top + viewportDimensions.height) {
                // If popup window overlaps viewports bottom border, correct top position to fit
                windowOffsetTop = scrollOffset.top + viewportDimensions.height - mouseOffsetTop - this.window.offsetHeight - borderSize.bottom;
            }
        
        if (this.window.offsetWidth + borderSize.left + borderSize.right > viewportDimensions.width) {
            // If popup window is wider than viewport, set position to viewports left border
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        else 
            if (mouseOffsetLeft + this.window.offsetWidth + borderSize.right > scrollOffset.left + viewportDimensions.width) {
                // If popup window overlaps viewports right border, correct left position to fit
                windowOffsetLeft = scrollOffset.left + viewportDimensions.width - mouseOffsetLeft - this.window.offsetWidth - borderSize.right;
            }
        
        this.window.style.top = (mouseOffsetTop + windowOffsetTop) + 'px';
        this.window.style.left = (mouseOffsetLeft + windowOffsetLeft) + 'px';
    },
    
    getBorderSize: function(){
        if (this.window) {
            // Calculates border sizes needed for window positioning
            return {
                top: Element.getHeight(this.window.down('.t')),
                right: Element.getWidth(this.window.down('.r')),
                bottom: Element.getHeight(this.window.down('.b')),
                left: Element.getWidth(this.window.down('.l'))
            };
        }
        // If there's no window there is no border :-)
        return {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
        };
    },
    
    unload: function(){
        this.options.onClose(this);
        // execute on close hooks
        Popup.onCloseHooks.each(function(hook){
            hook(this);
        }.bind(this));
        // Unregister event observation
        Event.stopObserving(window, 'resize', this.boundRefresh);
        Event.stopObserving(window, 'scroll', this.boundScroll);
        Event.stopObserving(document, 'keyup', this.boundKeyup);
        
        // Total removal of popup windows html structure
        this.window.update("")
        this.window.purge()
        this.window.parentNode.removeChild(this.window);
        this.background.purge()
        this.background.parentNode.removeChild(this.background);
        
        for (var i = 0; i < openPopupWindows.length; i++) {
            if (openPopupWindows[i] == this) {
                openPopupWindows.splice(i, 1);
                break;
            }
        }
    }
});

/**
 * Static function to close open popup window if one is open
 */
Popup.close = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindow.close();
    }
};

/**
 * Static function to reposition popup window if one is open
 */
Popup.refresh = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindows.push(openPopupWindow);
        openPopupWindow.refresh();
    }
};

/**
 * on submit hooks are executed before the form gets submitted
 */
Popup.onSubmitHooks = $A();
Popup.addOnSubmitHook = function(f){
    Popup.onSubmitHooks.push(f);
};

/**
 * On close hooks are executed before the popup gets closed
 */
Popup.onCloseHooks = $A();
Popup.addOnCloseHook = function(f){
    Popup.onCloseHooks.push(f);
};

var Tooltip = Class.create({
    initialize: function(hoverElement, content, options){
        this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2
        }, options || {});
		this.hoverElement = $(hoverElement);
        this.container = new Element('div', {
            'class': 'tooltip',
            'style': 'display:none;position:absolute;z-index: 1000000;'
        });
        this.container.update(content);
        this.hoverElement.insert(this.container);        
		this.initObservers();
    },
    initObservers: function(){
        this.hoverElement.observe('mouseover', this.mouseOver.bindAsEventListener(this));
        this.hoverElement.observe('mouseout', this.mouseOut.bindAsEventListener(this));        
    },
    cancelShow: function(){
        if (this.showDelayId) {
            window.clearTimeout(this.showDelayId);
            this.showDelayId = null;
        }
        if (this.showEffect) {
            this.showEffect.cancel();
            this.showEffect = null;
        }
    },
    cancelHide: function(){
        if (this.hideDelayId) {
            window.clearTimeout(this.hideDelayId);
            this.hideDelayId = null;
        }
        if (this.hideEffect) {
            this.hideEffect.cancel();
            this.hideEffect = null;
        }
    },
    mouseOver: function(event){
        Event.stop(event);
        this.cancelHide();
        this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
    },
    mouseOut: function(event){
        Event.stop(event);
        this.cancelShow();
        this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
    },
    show: function(){
        if (!this.shown) {
            this.shown = true;
            this.showEffect = new Effect.Appear(this.container, {
                duration: this.options.duration
            });
        }
    },
    hide: function(){
        if (this.shown) {
            this.shown = false;
            this.hideEffect = new Effect.Fade(this.container, {
                duration: this.options.duration
            });
        }
    }
});

var openPopupWindows = new Array();

/**
 * Type constants for popup buttons
 * Use them for option _type_ on creating a Button instance
 */
var ButtonType = {
    SUBMIT: 'submit',
    CANCEL: 'cancel',
    RESET: 'reset',
    CUSTOM: 'custom'
};

/**
 * Popup button to submit or reset forms and to close popup window
 * To add different click behavior extend this class and overwrite onClick method
 */
Button = Class.create({
    initialize: function(value){
        this.options = Object.extend({
            name: "submit",
            value: value,
            type: ButtonType.SUBMIT,
            onClick: function(){
            }
        }, arguments[1] || {});
        
        this.node = Builder.node('input', {
            'name': this.options.name,
            'class': 'button ' + this.options.type,
            type: 'button',
            value: this.options.value
        });
        Event.observe(this.node, 'click', this.click.bindAsEventListener(this));
    },
    
    click: function(event){
        var openPopupWindow = openPopupWindows.pop();
        openPopupWindows.push(openPopupWindow);
        
        var form = $(openPopupWindow.window).down('FORM');
        this.options.onClick(form);
        if (this.options.type == ButtonType.SUBMIT) {
			      // execute on submit hooks
            Popup.onSubmitHooks.each(function(hook){
               hook(openPopupWindow);
            });
            if (form) {
                var params = form.serialize(true);
                params[this.options.name] = this.options.value;                           
                if (openPopupWindow.options.update) {
                    openPopupWindow.show_loading_overlay();     
                    new Ajax.Updater(openPopupWindow.options.update, form.action, {                       
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.close();
                        }
                    });
                }
                else {
                    openPopupWindow.show_loading_overlay();  
                    new Ajax.Updater(openPopupWindow.body, form.action, {
                        evalScripts: true,
                        parameters: params,
                        onComplete: function(transport){
                          openPopupWindow.hide_loading_overlay();
                          Popup.refresh();
                        }
                    });
                }
            }
            else {
                alert('There is no form to submit!');
            }
        }
        else 
            if (this.options.type == ButtonType.CANCEL) {
                openPopupWindow.close();
            }
            else 
                if (this.options.type == ButtonType.RESET) {
                    if (form) {
                        form.reset();
                    }
                    else {
                        alert('There is no form to reset');
                    }
                }
                else 
                    if (this.options.type == ButtonType.CUSTOM) {
                    // Just do the buttons onClick function
                    }
                    else {
                        this.onClick(event, this.options.type);
                    }
    },
    
    onClick: function(event, type){
        alert('Click behavior for button type "' + type + '" is not implemented yet!');
    }
});

/**
 * Constants for popup position
 * Use them for option _position_ on creating a Popup instance
 */
var PopupPosition = {
    CENTER: 'center',
    MOUSE: 'mouse'
};

/**
 *
 */
var Popup = Class.create({
    initialize: function(event, content){
        this.options = Object.extend({
            title: '',
            icon: false,
            content: content,
            width: '500px',
            position: PopupPosition.MOUSE,
            modal: true,
            sameWindow: false,
            url: false,
            update: false,
            closeOnBackgroundClick: false,
            buttons: [],
            onLoad: function(popup){
            },
            onClose: function(popup){
            },
            onRefresh: function(popup){
            }
        }, arguments[2] || {});
        
        if (this.options.sameWindow) {
            openPopupWindow = openPopupWindows.pop();
            if (openPopupWindow) {
                openPopupWindow.unload();
            }
        }
		        
        openPopupWindows.push(this);
        
        this.button = Builder.node('img', {
            'class': 'close',
            src: '/images/icons/cross.png'
        });
        this.buttons = Builder.node('div', {
            'class': 'buttons'
        });
        this.body = Builder.node('div', {
            id: 'popup_body',
            'class': 'body'
        });
        this.body.innerHTML = this.options.content;
        
        // Add registered button objects to popup window
        for (var i = 0; i < this.options.buttons.length; i++) {
            this.buttons.appendChild(this.options.buttons[i].node);
        }
        
        // Add window icon to title bar
        var title = new Array();
        if (this.options.icon) {
            title.push(Builder.node('img', {
                'class': 'icon',
                src: this.options.icon
            }));
        }
        title.push(Builder.node('span', {
            'class': 'name'
        }, this.options.title));
        
        // Create html construct for popup window
        this.window = Builder.node('div', {
            id: 'popup',
            style: 'visibility: hidden; width: ' + this.options.width
        }, [Builder.node('div', {
            'class': 'tl'
        }), Builder.node('div', {
            'class': 't'
        }), Builder.node('div', {
            'class': 'tr'
        }), Builder.node('div', {
            'class': 'l'
        }), Builder.node('div', {
            'class': 'r'
        }), Builder.node('div', {
            'class': 'bl'
        }), Builder.node('div', {
            'class': 'b'
        }), Builder.node('div', {
            'class': 'br'
        }), Builder.node('div', {
            'class': 'title'
        }, title), this.button, this.body, this.buttons]);
        
        // Create modal background layer
        this.background = Builder.node('div', {
            id: 'popup_modal_layer',
            style: 'display: none'
        });
        if (this.options.closeOnBackgroundClick) {
            this.background.setAttribute('class', 'closeable');
        }
        
        // Register events
        this.boundKeyup = this.keyup.bindAsEventListener(this);
        this.boundScroll = this.scroll.bindAsEventListener(this);
        this.boundRefresh = this.refresh.bindAsEventListener(this);
        Event.observe(window, 'resize', this.boundRefresh);
        Event.observe(window, 'scroll', this.boundScroll);
        Event.observe(document, 'keyup', this.boundKeyup);
        if (this.options.closeOnBackgroundClick) {
            Event.observe(this.background, 'click', this.close.bindAsEventListener(this));
        }
        Event.observe(this.button, 'click', this.close.bindAsEventListener(this));
        
        // Append popup window and modal background to body
        document.getElementsByTagName('body')[0].appendChild(this.background);
        document.getElementsByTagName('body')[0].appendChild(this.window);
        
        this.options.onLoad(this);
        
        // Show modal background if needed
        if (this.options.modal) {
            this.background.show();
        }
        
        // Set opening position according to mouse position
        if (this.options.position == PopupPosition.MOUSE) {
            this.moveToMousePosition(event);
        }
        this.refresh();
                
        // Load popup content with ajax and reposition popup
        if (this.options.url) {            
            this.show_loading_overlay();
            new Ajax.Updater(this.body, this.options.url, {
                evalScripts: true,                
                onComplete: function(transport){                    
                    this.hide_loading_overlay();
                    if (this.options.position == PopupPosition.MOUSE) {
                        this.moveToMousePosition(false);
                    }
                    this.refresh();
                }.bind(this)
            });
        }
    },

    show_loading_overlay: function(){
      if(!this.loading_overlay){
        var el = new Element('div', {'class': 'loading_overlay', style: 'text-align: center; vertical-align: middle; opacity: 0.5; background: lightgray; position: absolute; left: 0; top: 0; width: ' + this.window.getWidth() + 'px; height: '+ this.window.getHeight() + 'px;'});
        el.insert(new Element('img', {src: '/images/spacer.gif', style: 'vertical-align:middle;height:100%;width:1px;'}));
        el.insert(new Element('img', {src: '/images/ajax-loader.gif', style: 'vertical-align:middle;'}));
        this.loading_overlay = el;
        this.window.insert(this.loading_overlay);
      }
    },

    hide_loading_overlay: function(){
      if(this.loading_overlay){
        this.loading_overlay.remove();
        this.loading_overlay = null;
      }
    },
    
    close: function(event){
        // Hide popup window and modal layer
        this.window.hide();
        this.background.hide();
        
        // Unload current popup window
        this.unload();
    },
    
    keyup: function(event){
        if (!event) 
            event = window.event;
        
        var code = 0;
        if (event.which) {
            code = event.which;
        }
        else 
            if (event.keyCode) {
                code = event.keyCode;
            }
        
        // Close popup window if ESC button was pressed on keyboard
        if (code == 27) {
          Event.stop(event);
          this.close();
        }
        else 
            if (code == 13) {
                if (!event.element() || !(event.element() instanceof HTMLTextAreaElement)) {
                    Event.stop(event);
                    var firstButton = $A(this.buttons.childNodes).first();                    
                    if (firstButton) {
                        firstButton.click();
                    }
                }
            }
    },
    
    scroll: function(event){
        if (this.options.modal) {
        
            // Move modal layer to current viewport position
            var viewportDimensions = document.viewport.getDimensions();
            var scrollOffset = document.viewport.getScrollOffsets();
            
            this.background.style.top = scrollOffset.top + 'px';
            this.background.style.left = scrollOffset.left + 'px';
            this.background.style.height = viewportDimensions.height + 'px';
            this.background.style.width = viewportDimensions.width + 'px';
        }
    },
    
    refresh: function(){        
        this.options.onRefresh(this);
        if (this.window) {        
            // Calculate popup position in the center of viewport
            if (this.options.position == PopupPosition.CENTER) {
                var scrollOffset = document.viewport.getScrollOffsets();
                var borderSize = this.getBorderSize();
                
                var windowPositionTop = scrollOffset.top + ((document.viewport.getHeight() / 2) - (this.window.offsetHeight / 2));
                var windowPositionLeft = scrollOffset.left + ((document.viewport.getWidth() / 2) - (this.window.offsetWidth / 2));
                
                // If viewport is smaller than popup window, place popup in topper left corner
                if (windowPositionTop - borderSize.top < scrollOffset.top) {
                    windowPositionTop = scrollOffset.top + borderSize.top;
                }
                
                if (windowPositionLeft - borderSize.left < scrollOffset.left) {
                    windowPositionLeft = scrollOffset.left + borderSize.left;
                }
                
                this.window.style.top = windowPositionTop + 'px';
                this.window.style.left = windowPositionLeft + 'px';
            }
            this.window.style.visibility = 'visible';
            
            // position modal background if available
            this.scroll();
        }
    },
    
    moveToMousePosition: function(event){
        if (!event && event != false) 
            event = window.event;
        
        if (!event) {
            // Set virtual mouse position to current position 
            // Only used for second position adjustments after loading popup content with ajax
            var windowOffset = Element.cumulativeOffset(this.window);
            var mouseOffsetTop = windowOffset.top;
            var mouseOffsetLeft = windowOffset.left;
        }
        else {
            // Set position based on mouse position on popup open
            var mouseOffsetTop = Event.pointerY(event);
            var mouseOffsetLeft = Event.pointerX(event);
        }
        
        var windowOffsetLeft = 0;
        var windowOffsetTop = 0;
        
        var scrollOffset = document.viewport.getScrollOffsets();
        var viewportDimensions = document.viewport.getDimensions();
        var borderSize = this.getBorderSize();
        
        // Correction of mouse click position if coordinates are too narrow at the browser border
        if (mouseOffsetTop - borderSize.top < scrollOffset.top) {
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        
        if (mouseOffsetLeft - borderSize.left < scrollOffset.left) {
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        
        if (this.window.offsetHeight + borderSize.top + borderSize.bottom > viewportDimensions.height) {
            // If popup window is heigher than viewport, set position to viewports top border
            mouseOffsetTop = scrollOffset.top + borderSize.top;
        }
        else 
            if (mouseOffsetTop + this.window.offsetHeight + borderSize.bottom > scrollOffset.top + viewportDimensions.height) {
                // If popup window overlaps viewports bottom border, correct top position to fit
                windowOffsetTop = scrollOffset.top + viewportDimensions.height - mouseOffsetTop - this.window.offsetHeight - borderSize.bottom;
            }
        
        if (this.window.offsetWidth + borderSize.left + borderSize.right > viewportDimensions.width) {
            // If popup window is wider than viewport, set position to viewports left border
            mouseOffsetLeft = scrollOffset.left + borderSize.left;
        }
        else 
            if (mouseOffsetLeft + this.window.offsetWidth + borderSize.right > scrollOffset.left + viewportDimensions.width) {
                // If popup window overlaps viewports right border, correct left position to fit
                windowOffsetLeft = scrollOffset.left + viewportDimensions.width - mouseOffsetLeft - this.window.offsetWidth - borderSize.right;
            }
        
        this.window.style.top = (mouseOffsetTop + windowOffsetTop) + 'px';
        this.window.style.left = (mouseOffsetLeft + windowOffsetLeft) + 'px';
    },
    
    getBorderSize: function(){
        if (this.window) {
            // Calculates border sizes needed for window positioning
            return {
                top: Element.getHeight(this.window.down('.t')),
                right: Element.getWidth(this.window.down('.r')),
                bottom: Element.getHeight(this.window.down('.b')),
                left: Element.getWidth(this.window.down('.l'))
            };
        }
        // If there's no window there is no border :-)
        return {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
        };
    },
    
    unload: function(){
        this.options.onClose(this);
        // execute on close hooks
        Popup.onCloseHooks.each(function(hook){
            hook(this);
        }.bind(this));
        // Unregister event observation
        Event.stopObserving(window, 'resize', this.boundRefresh);
        Event.stopObserving(window, 'scroll', this.boundScroll);
        Event.stopObserving(document, 'keyup', this.boundKeyup);
        
        // Total removal of popup windows html structure
        this.window.update("")
        this.window.purge()
        this.window.parentNode.removeChild(this.window);
        this.background.purge()
        this.background.parentNode.removeChild(this.background);
        
        for (var i = 0; i < openPopupWindows.length; i++) {
            if (openPopupWindows[i] == this) {
                openPopupWindows.splice(i, 1);
                break;
            }
        }
    }
});

/**
 * Static function to close open popup window if one is open
 */
Popup.close = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindow.close();
    }
};

/**
 * Static function to reposition popup window if one is open
 */
Popup.refresh = function(){
    var openPopupWindow = openPopupWindows.pop();
    if (openPopupWindow) {
        openPopupWindows.push(openPopupWindow);
        openPopupWindow.refresh();
    }
};

/**
 * on submit hooks are executed before the form gets submitted
 */
Popup.onSubmitHooks = $A();
Popup.addOnSubmitHook = function(f){
    Popup.onSubmitHooks.push(f);
};

/**
 * On close hooks are executed before the popup gets closed
 */
Popup.onCloseHooks = $A();
Popup.addOnCloseHook = function(f){
    Popup.onCloseHooks.push(f);
};

var Tooltip = Class.create({
    initialize: function(hoverElement, content, options){
        this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2
        }, options || {});
		this.hoverElement = $(hoverElement);
        this.container = new Element('div', {
            'class': 'tooltip',
            'style': 'display:none;position:absolute;z-index: 1000000;'
        });
        this.container.update(content);
        this.hoverElement.insert(this.container);        
		this.initObservers();
    },
    initObservers: function(){
        this.hoverElement.observe('mouseover', this.mouseOver.bindAsEventListener(this));
        this.hoverElement.observe('mouseout', this.mouseOut.bindAsEventListener(this));        
    },
    cancelShow: function(){
        if (this.showDelayId) {
            window.clearTimeout(this.showDelayId);
            this.showDelayId = null;
        }
        if (this.showEffect) {
            this.showEffect.cancel();
            this.showEffect = null;
        }
    },
    cancelHide: function(){
        if (this.hideDelayId) {
            window.clearTimeout(this.hideDelayId);
            this.hideDelayId = null;
        }
        if (this.hideEffect) {
            this.hideEffect.cancel();
            this.hideEffect = null;
        }
    },
    mouseOver: function(event){
        Event.stop(event);
        this.cancelHide();
        this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
    },
    mouseOut: function(event){
        Event.stop(event);
        this.cancelShow();
        this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
    },
    show: function(){
        if (!this.shown) {
            this.shown = true;
            this.showEffect = new Effect.Appear(this.container, {
                duration: this.options.duration
            });
        }
    },
    hide: function(){
        if (this.shown) {
            this.shown = false;
            this.hideEffect = new Effect.Fade(this.container, {
                duration: this.options.duration
            });
        }
    }
});

var Tab = Class.create({
    initialize: function(name, args){
        this.name = name;
		if (args) {
			this.element = $(args.element);
			this.content = args.content;
			this.url = args.url;
			this.active = args.active;
		}
    }
    
});

var Tabs = Class.create({
    initialize: function(element, tabs,mode){
      this.element = $(element);
		this.mode = mode || Tabs.REPLACE;
      this.tabs = $A(tabs);
      this.ul = new Element('ul', {
          'class': 'tabsLabels ' + this.mode
      })
      this.element.insert(this.ul);
      this.containers = new Element('div', {
          'class': 'tabsContainers ' + this.mode
      });
      this.element.insert(this.containers);
  		this.initContainers();
  		this.initLabels();
  		if(!this.active){
  			this.setActiveTab(this.tabs.first().name);
  		}
    },
	initContainers: function(){
		this.orderedContainers = $H();
		for (var i = 0, il = this.tabs.length; i < il; ++i) {
			var tab = this.tabs[i];
			var container = $(tab.element) || new Element('div', {});
			if (tab.content) {
				container.update(tab.content);
			}
			// remove containers from HTML 
			container.remove();					
			this.orderedContainers.set(tab.name,container);
			if (this.mode == Tabs.OVERLAY) {
			   container.hide();
			   this.containers.insert(container);
			}
		}
	}, 
  initLabels: function(){
    this.orderedTabs = $H();
    this.orderedLabels = $H();
    for (var i = 0, il = this.tabs.length; i < il; ++i) {
      var tab = this.tabs[i];
      var name = tab.name;
	    this.orderedTabs.set(name, tab);
      
      var label = new Element('li');
      	    
	    if(this.mode == Tabs.RADIO){
        var input = new Element("input",{type: 'radio', value: name});
        label.insert(input);
        var span = new Element('span');
        span.insert(name);
        label.insert(span);
        span.observe('click', function(event){
          event.stop();         
          this.setActiveTab(event.target.firstChild.data);
          return false;
        }.bindAsEventListener(this));
        input.observe('click', function(event){
          event.stop();
          this.setActiveTab(event.target.getValue());
          return false;
        }.bindAsEventListener(this));
      }else{
        var labelLink = new Element('a',{href: '#', onclick: 'return false;'});
        labelLink.update(name);
        labelLink.observe('click', function(event){
          this.setActiveTab(event.target.firstChild.data);
          return false;
        }.bindAsEventListener(this));
        label.insert(labelLink);     
      }      
          
	    this.orderedLabels.set(name, label);
	    this.ul.insert(label);
	    if(tab.active){
		    this.setActiveTab(name);
	    }          
    }
  },
  setActiveTab: function(name){
	this.active = name;
    var tab = this.orderedTabs.get(name);
	  var activeLabel = this.orderedLabels.get(name);
    if (activeLabel) {
      var labels = this.orderedLabels.values();
      for (var i = 0, il = labels.length; i < il; ++i) {
      	var label = labels[i];
	      label.removeClassName('active');
        if(this.mode == Tabs.RADIO){
          label.select('input').first().checked = false;
        }				
      }
		  activeLabel.addClassName('active');

      if(this.mode == Tabs.RADIO){        
        activeLabel.select('input').first().checked = true;
      }
		
		  var containers = this.orderedContainers.values();
		
		  var activeContainer = this.orderedContainers.get(name);
		  if (tab.content) {
			  activeContainer.update(tab.content);
		  }
		  if (this.mode == Tabs.OVERLAY) {
			  for (var i = 0, il = containers.length; i < il; ++i) {
				  var container = containers[i];
				  container.hide();
			  }
			  activeContainer.show();
        //this.containers.setStyle({height: activeContainer.getHeight() + 'px'});
		  }else {
		    this.containers.update(activeContainer);          				
		  }
		
		  if(tab.url){
			  new Ajax.Updater(activeContainer,tab.url,{evalScripts: true});
		  }
    }        
  }
});

Tabs.OVERLAY = "overlay";
Tabs.REPLACE = "replace";
Tabs.RADIO = "radio";

var Tab = Class.create({
    initialize: function(name, args){
        this.name = name;
		if (args) {
			this.element = $(args.element);
			this.content = args.content;
			this.url = args.url;
			this.active = args.active;
		}
    }
    
});

var Tabs = Class.create({
    initialize: function(element, tabs,mode){
      this.element = $(element);
		this.mode = mode || Tabs.REPLACE;
      this.tabs = $A(tabs);
      this.ul = new Element('ul', {
          'class': 'tabsLabels ' + this.mode
      })
      this.element.insert(this.ul);
      this.containers = new Element('div', {
          'class': 'tabsContainers ' + this.mode
      });
      this.element.insert(this.containers);
  		this.initContainers();
  		this.initLabels();
  		if(!this.active){
  			this.setActiveTab(this.tabs.first().name);
  		}
    },
	initContainers: function(){
		this.orderedContainers = $H();
		for (var i = 0, il = this.tabs.length; i < il; ++i) {
			var tab = this.tabs[i];
			var container = $(tab.element) || new Element('div', {});
			if (tab.content) {
				container.update(tab.content);
			}
			// remove containers from HTML 
			container.remove();					
			this.orderedContainers.set(tab.name,container);
			if (this.mode == Tabs.OVERLAY) {
			   container.hide();
			   this.containers.insert(container);
			}
		}
	}, 
  initLabels: function(){
    this.orderedTabs = $H();
    this.orderedLabels = $H();
    for (var i = 0, il = this.tabs.length; i < il; ++i) {
      var tab = this.tabs[i];
      var name = tab.name;
	    this.orderedTabs.set(name, tab);
      
      var label = new Element('li');
      	    
	    if(this.mode == Tabs.RADIO){
        var input = new Element("input",{type: 'radio', value: name});
        label.insert(input);
        var span = new Element('span');
        span.insert(name);
        label.insert(span);
        span.observe('click', function(event){
          event.stop();         
          this.setActiveTab(event.target.firstChild.data);
          return false;
        }.bindAsEventListener(this));
        input.observe('click', function(event){
          event.stop();
          this.setActiveTab(event.target.getValue());
          return false;
        }.bindAsEventListener(this));
      }else{
        var labelLink = new Element('a',{href: '#', onclick: 'return false;'});
        labelLink.update(name);
        labelLink.observe('click', function(event){
          this.setActiveTab(event.target.firstChild.data);
          return false;
        }.bindAsEventListener(this));
        label.insert(labelLink);     
      }      
          
	    this.orderedLabels.set(name, label);
	    this.ul.insert(label);
	    if(tab.active){
		    this.setActiveTab(name);
	    }          
    }
  },
  setActiveTab: function(name){
	this.active = name;
    var tab = this.orderedTabs.get(name);
	  var activeLabel = this.orderedLabels.get(name);
    if (activeLabel) {
      var labels = this.orderedLabels.values();
      for (var i = 0, il = labels.length; i < il; ++i) {
      	var label = labels[i];
	      label.removeClassName('active');
        if(this.mode == Tabs.RADIO){
          label.select('input').first().checked = false;
        }				
      }
		  activeLabel.addClassName('active');

      if(this.mode == Tabs.RADIO){        
        activeLabel.select('input').first().checked = true;
      }
		
		  var containers = this.orderedContainers.values();
		
		  var activeContainer = this.orderedContainers.get(name);
		  if (tab.content) {
			  activeContainer.update(tab.content);
		  }
		  if (this.mode == Tabs.OVERLAY) {
			  for (var i = 0, il = containers.length; i < il; ++i) {
				  var container = containers[i];
				  container.hide();
			  }
			  activeContainer.show();
        //this.containers.setStyle({height: activeContainer.getHeight() + 'px'});
		  }else {
		    this.containers.update(activeContainer);          				
		  }
		
		  if(tab.url){
			  new Ajax.Updater(activeContainer,tab.url,{evalScripts: true});
		  }
    }        
  }
});

Tabs.OVERLAY = "overlay";
Tabs.REPLACE = "replace";
Tabs.RADIO = "radio";

var BannerRotator = Class.create({
    initialize: function(container, options){
        this.container = $(container);
        this.options = Object.extend({
            interval: 10,
            transitionTime: 1,
            transition: BannerRotator.Transitions.Blend,
			transitionBehaviour: Effect.Transitions.linear
        }, options);
        this.options.transition = this.options.transition.bind(this);
        this.fetchElements();
        if (this.elements.length > 1) {
            this.currentIndex = Math.round(Math.random()*1000000000)%this.elements.length;			
			this.currentElement = this.elements[this.currentIndex];
            this.currentElement.setStyle({display: 'block'});
            new PeriodicalExecuter(this.rotate.bind(this), this.options.interval);
        }
    },
    fetchElements: function(){
        this.elements = $A();
        this.elements = this.container.immediateDescendants();
        for (var i = 0, il = this.elements.length; i < il; ++i) {
            this.elements[i].setStyle({
                position: 'absolute',
				display: 'none'
            });
        }
    },
    rotate: function(){
        var oldElement = this.currentElement;
        this.currentIndex = (this.currentIndex + 1) % this.elements.length;
        this.currentElement = this.elements[this.currentIndex];
        this.options.transition(oldElement, this.currentElement);
    }
});

BannerRotator.Transitions = {
    Slide: function(oldElement, newElement){
        var containerWidth = this.container.getWidth();
        var containerHeight = this.container.getHeight();
        newElement.setStyle({
            display: 'block',
            left: containerWidth + 'px'
        });
        new Effect.Parallel([new Effect.Move(oldElement, {
            mode: 'absolute',
            sync: true,
            x: 0 - containerWidth
        }), new Effect.Move(newElement, {
            mode: 'absolute',
            sync: true,
            x: 0
        })], {
			transition: this.options.transitionBehaviour,
            duration: this.options.transitionTime
        });
    },
    Blend: function(oldElement, newElement){
        newElement.setStyle({
            display: 'none'          
        });
        new Effect.Parallel([new Effect.Fade(oldElement, {            
            sync: true
        }), new Effect.Appear(newElement, {            
            sync: true
        })], {
			transition: this.options.transitionBehaviour,
            duration: this.options.transitionTime
        });
    }
};



var BannerRotator = Class.create({
    initialize: function(container, options){
        this.container = $(container);
        this.options = Object.extend({
            interval: 10,
            transitionTime: 1,
            transition: BannerRotator.Transitions.Blend,
			transitionBehaviour: Effect.Transitions.linear
        }, options);
        this.options.transition = this.options.transition.bind(this);
        this.fetchElements();
        if (this.elements.length > 1) {
            this.currentIndex = Math.round(Math.random()*1000000000)%this.elements.length;			
			this.currentElement = this.elements[this.currentIndex];
            this.currentElement.setStyle({display: 'block'});
            new PeriodicalExecuter(this.rotate.bind(this), this.options.interval);
        }
    },
    fetchElements: function(){
        this.elements = $A();
        this.elements = this.container.immediateDescendants();
        for (var i = 0, il = this.elements.length; i < il; ++i) {
            this.elements[i].setStyle({
                position: 'absolute',
				display: 'none'
            });
        }
    },
    rotate: function(){
        var oldElement = this.currentElement;
        this.currentIndex = (this.currentIndex + 1) % this.elements.length;
        this.currentElement = this.elements[this.currentIndex];
        this.options.transition(oldElement, this.currentElement);
    }
});

BannerRotator.Transitions = {
    Slide: function(oldElement, newElement){
        var containerWidth = this.container.getWidth();
        var containerHeight = this.container.getHeight();
        newElement.setStyle({
            display: 'block',
            left: containerWidth + 'px'
        });
        new Effect.Parallel([new Effect.Move(oldElement, {
            mode: 'absolute',
            sync: true,
            x: 0 - containerWidth
        }), new Effect.Move(newElement, {
            mode: 'absolute',
            sync: true,
            x: 0
        })], {
			transition: this.options.transitionBehaviour,
            duration: this.options.transitionTime
        });
    },
    Blend: function(oldElement, newElement){
        newElement.setStyle({
            display: 'none'          
        });
        new Effect.Parallel([new Effect.Fade(oldElement, {            
            sync: true
        }), new Effect.Appear(newElement, {            
            sync: true
        })], {
			transition: this.options.transitionBehaviour,
            duration: this.options.transitionTime
        });
    }
};



var EditableGrid = Class.create({
    initialize: function(table, templateRow){
        this.table = table;
		this.templateRow = templateRow;
    }
    
});

HtmlEditor = {
    destroy_all: function(parent){
        parent.select('textarea.html_editor').each(function(element){
            var id = element.id
            var editor = tinyMCE.editors[id];
            if (editor && editor.destroy) {                
                editor.destroy();
            }
        });
    },
    save_all: function(){
        tinyMCE.triggerSave(true, true);
    },
    add_popup_hooks: function(){
        try {
            Popup.addOnCloseHook(function(popup){
                HtmlEditor.destroy_all(popup.window);
            });
            
            Popup.addOnSubmitHook(function(popup){
                HtmlEditor.save_all();
                HtmlEditor.destroy_all(popup.window);
            });
        } 
        catch (e) {
			alert(e.message)
            HtmlEditor.add_popup_hooks.delay(0.1);
        }
    }
};

HtmlEditor.add_popup_hooks.delay(0.1);




var EditableList = Class.create({
    initialize: function(element, options){
        this.element = $(element);
        this.element.list = this;
        this.entryElements = $H();
        this.optionElements = $H();
        this.options = Object.extend({
            duplicatesAllowed: false,
            sortAllowed: true,
            addAllowed: true,
            deleteAllowed: true,
            editAllowed: false,
            name: 'order',
            addImageSrc: '/images/icons/add.png',
            needsAddButton: true
        }, options || {});
    },
    selectFirstVisibleOption: function(){
        if (this.chooser && this.chooser.options) {
            for (var i = 0, il = this.chooser.options.length; i < il; ++i) {
                var option = this.chooser.options[i];
                if (option.getStyle('display') != 'none') {
                    this.chooser.selectedIndex = i;
                    return;
                }
            }
            this.chooser.selectedIndex = -1;
        }
    },
    addEntry: function(value, label, url){
        var li = new Element('li');
        li.setStyle({listStyle: 'none'});
        this.entryElements.set(value, li);
        var span = new Element('span');
        if (!this.options.editAllowed) {
            if (url && !this.options.sortAllowed) {
                link = new Element('a', {
                    href: url,
                    target: '_self'
                });
                link.update(label);
                span.update(link);
            }
            else {
                span.update(label);
            }
        }
        var input = new Element('input', {
            name: this.options.name + '[]',
            value: value,
            type: this.options.editAllowed ? 'text' : 'hidden'
        });
        span.insert(input);
        li.insert(span);
		
        this.element.insert(li);
        if (this.options.deleteAllowed) {
            var deleteLink = new Element('a');
            deleteLink.setStyle({
                cursor: 'pointer'
            });
            deleteLink.observe('click', function(){
                this.deleteEntry(li, value);
            }
.bindAsEventListener(this));
            var deleteImg = new Element('img', {
                src: '/images/icons/delete.png'
            });
            deleteLink.insert(deleteImg);
            deleteLink.setStyle({
                marginLeft: '5px',
                verticalAlign: 'middle'
            });
            li.insert(deleteLink);
        }
        if (!this.options.editAllowed && this.options.sortAllowed) {
            li.setStyle({
                cursor: 'pointer'
            });
            Sortable.create(this.element);
        }
        if (!this.options.duplicatesAllowed) {
            var option = this.optionElements.get(value);
            if (option) {
                option.setStyle({
                    display: 'none'
                });
            }
        }
        this.selectFirstVisibleOption();
    },
    deleteEntry: function(li, value){
        if (li) {
            this.element.removeChild(li);
        }
        var option = this.optionElements.get(value)
        if (option) {
            option.setStyle({
                display: 'block'
            });
        }
        this.selectFirstVisibleOption();
    },
    setChooser: function(chooser){
        this.chooser = chooser;
        if (this.chooser) {
            this.chooser.list = this;
            this.chooser.setStyle({
                display: 'inline-block',
                verticalAlign: 'middle'
            });
            var options = this.chooser.options ||
            []
            for (var i = 0, il = options.length; i < il; ++i) {
                var option = options[i];
                var value = option.value;
                this.optionElements.set(value, option);
                if (!this.options.duplicatesAllowed && this.entryElements.get(value)) {
                    option.setStyle({
                        display: 'none'
                    });
                }
            }
            this.element.insert({
                after: this.chooser
            });
        }
        if (this.options.needsAddButton) {
            var addLink = new Element('a');
            addLink.setStyle({
                cursor: 'pointer',
                marginLeft: '5px',
                verticalAlign: 'middle'
            });
            addLink.observe('click', function(){
                if (this.chooser) {
                    var options = this.chooser.options;
                    if (options) {
                        var selectedOption = options[this.chooser.selectedIndex];
                        this.addEntry(selectedOption.value, selectedOption.text);
                    }
                    else {
                        var value = this.chooser.value;
                        this.addEntry(value, value);
                        this.chooser.value = '';
                    }
                }
                else {
                    if (this.options.onAdd) {
                        this.options.onAdd(this);
                    }
                }
            }
.bindAsEventListener(this));
            
            var addImg = new Element('img', {
                src: this.options.addImageSrc
            });
            addLink.insert(addImg);
            if (this.chooser) {
                this.chooser.insert({
                    after: addLink
                });
            }
            else {
                this.element.insert({
                    after: addLink
                });
            }
        }
        this.selectFirstVisibleOption();
    }
});

var DateTimePicker = Class.create({
    monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    initialize: function(input, time, showedPicker){
        this.time = time;
        this.showedPicker = showedPicker || 'both';
        this.input = $(input);
        this.input.picker = this;
        this.extendInput();
        if (time) {
            this.updateInput(this.time);
        }
    },
    updateInput: function(time){
        this.setTime(time);
        this.input.fire('datetime:changed');
    },
    setTime: function(time){
        var value = ''
        if (this.showedPicker == 'date' || this.showedPicker == 'both') {
            value = value + this.fillString(time.getDate()) + '-' + this.fillString(time.getMonth() + 1) + '-' + time.getFullYear() + '  ';
        }
        if (this.showedPicker == 'time' || this.showedPicker == 'both') {
            value = value + this.fillString(time.getHours()) + ':' + this.fillString(time.getMinutes());
        }
        this.input.value = value;
        this.time = time;
    },
	setShowedPicker: function(showedPicker){
		this.showedPicker = showedPicker;
		if (this.time) {
			this.setTime(this.time);
		}		
		if(this.datePickerOpener){
		   if(this.showedPicker == 'date' || this.showedPicker == 'both')
		      this.datePickerOpener.show()
		   else{
			  this.datePickerOpener.hide()
		   }		   
		}
		if(this.timePickerOpener){
		   if(this.showedPicker == 'time' || this.showedPicker == 'both')
		      this.timePickerOpener.show()
		   else{
			  this.timePickerOpener.hide()
		   }		   
		}
	},
    fillString: function(text){
        text = text + '';
        if (text.length == 1) {
            return '0' + text;
        }
        return text
    }
});


var PopupDateTimePicker = Class.create(DateTimePicker, {
    extendInput: function(){        
        if (this.showedPicker == 'date' || this.showedPicker == 'both') {
            this.input.setStyle({
                width: (this.input.getWidth() - 25) + 'px'
            });
            this.datePickerOpener = new Element('img', {
                src: '/images/icons/calendar.png'
            });
            this.datePickerOpener.setStyle({
                width: '16px',
                height: '16px',
                marginLeft: '3px',
                cursor: 'pointer'
            });
            this.datePickerOpener.observe('click', function(event){
                var x = this.datePickerOpener.positionedOffset()[0] - 100;
                var y = this.datePickerOpener.positionedOffset()[1] + 25;
                this.openDatePicker(x, y);
            }.bindAsEventListener(this));
            this.input.insert({
                after: this.datePickerOpener
            });
            this.input.observe('click', function(event){
                var x = this.datePickerOpener.positionedOffset()[0] - 100;
                var y = this.datePickerOpener.positionedOffset()[1] + 25;
                this.openDatePicker(x, y);
            }.bindAsEventListener(this));
        }
        if (this.showedPicker == 'time' || this.showedPicker == 'both') {
            this.input.setStyle({
                width: (this.input.getWidth() - 25) + 'px'
            });
            this.timePickerOpener = new Element('img', {
                src: '/images/icons/clock.png'
            });
            this.timePickerOpener.setStyle({
                width: '16px',
                height: '16px',
                marginLeft: '3px',
                cursor: 'pointer'
            });
            this.timePickerOpener.observe('click', function(event){
                var x = this.timePickerOpener.positionedOffset()[0] - 100;
                var y = this.timePickerOpener.positionedOffset()[1] + 25;
                this.openTimePicker(x, y);
            }.bindAsEventListener(this));
            (this.datePickerOpener || this.input).insert({
                after: this.timePickerOpener
            });
        }
    },
    close: function(){
        if (this.picker) {
            this.picker.parentNode.removeChild(this.picker);
            this.picker = null;
        }
    },
    openPicker: function(x, y, cssClass){
        var time = this.time || new Date();
        this.month = time.getMonth();
        this.fullYear = time.getFullYear();
        this.year = time.getYear();
        this.hour = time.getHours();
        this.minute = time.getMinutes();
        this.picker = new Element('div', {
            'class': cssClass
        })
        this.picker.setStyle({
            position: 'absolute',
            left: x + 'px',
            top: y + 'px',
            zIndex: '10000000'
        });
        this.input.insert({
            after: this.picker
        });
        
        var closeDiv = new Element('span', {
            'class': 'dateTimePickerClose'
        })
        closeDiv.insert('close');
        closeDiv.observe('click', function(){
            this.close();
            return false;
        }
.bindAsEventListener(this))
        this.picker.insert(closeDiv);
    },
    openDatePicker: function(x, y){
        if (!this.picker) {
            this.openPicker(x, y, 'datePicker');
            this.yearSelectorDiv = new Element('div', {
                'class': 'datePickerYearSelector'
            });
            this.picker.insert(this.yearSelectorDiv);
            this.renderYearSelector();
            this.monthSelectorDiv = new Element('div', {
                'class': 'datePickerMonthSelector'
            });
            this.picker.insert(this.monthSelectorDiv);
            this.renderMonthSelector();
            
            this.daySelectorDiv = new Element('div', {
                'class': 'datePickerDaySelector'
            });
            
            this.picker.insert(this.daySelectorDiv);
            this.renderDaySelector();
        }
        else {
            this.close();
        }
    },
    renderYearSelector: function(){
        var leftSpan = new Element('div', {
            'class': 'left'
        });
        leftSpan.insert('<');
        leftSpan.observe('click', function(){
            this.switchYear(-1)
        }
.bind(this));
        this.yearSelectorDiv.insert(leftSpan);
        var middleSpan = new Element('div', {
            'class': 'middle'
        });
        middleSpan.insert(this.fullYear);
        this.yearSelectorDiv.insert(middleSpan);
        var rightSpan = new Element('div', {
            'class': 'right'
        });
        rightSpan.insert('>');
        rightSpan.observe('click', function(){
            this.switchYear(1)
        }
.bind(this));
        this.yearSelectorDiv.insert(rightSpan);
    },
    renderMonthSelector: function(){
        var leftSpan = new Element('div', {
            'class': 'left'
        });
        leftSpan.insert('<');
        leftSpan.observe('click', function(){
            this.switchMonth(-1)
        }
.bind(this));
        this.monthSelectorDiv.insert(leftSpan);
        var middleSpan = new Element('div', {
            'class': 'middle'
        });
        middleSpan.insert(this.monthNames[this.month]);
        this.monthSelectorDiv.insert(middleSpan);
        var rightSpan = new Element('div', {
            'class': 'right'
        });
        rightSpan.insert('>');
        rightSpan.observe('click', function(){
            this.switchMonth(1)
        }
.bind(this));
        this.monthSelectorDiv.insert(rightSpan);
    },
    switchMonth: function(diff){
        this.month = ((this.month + diff + 12) % 12);
        if (diff > 0 && this.month == 0) {
            this.year = this.year + 1;
            this.fullYear = this.fullYear + 1;
        }
        else 
            if (diff < 0 && this.month == 11) {
                this.year = this.year - 1;
                this.fullYear = this.fullYear - 1;
            }
        $$('.datePickerMonthSelector .middle')[0].update(this.monthNames[this.month]);
        this.renderDaySelector();
    },
    switchYear: function(diff){
        this.year = this.year + diff;
        this.fullYear = this.fullYear + diff;
        $$('.datePickerYearSelector .middle')[0].update(this.fullYear);
        this.renderDaySelector();
    },
    renderDaySelector: function(){
        var time = this.time || new Date();
        table = new Element('table');
        table.setStyle({
            width: '100%',
            height: '100%'
        });
        var weekday = (new Date(this.fullYear, this.month, 1).getDay() - 1) % 7;
        if (weekday == 0) {
            weekday = 7;
        }
        var day = 1 - weekday;
        
        weekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']
        var tr = new Element('tr');
        for (var i = 0; i < 7; i++) {
            var td = new Element('td', {
                'class': 'header'
            });
            td.insert(weekdays[i]);
            tr.insert(td);
        }
        table.insert(tr);
        for (var i = 0; i < 6; i++) {
            var tr = new Element('tr');
            for (var k = 0; k < 7; k++) {
                var date = new Date(this.fullYear, this.month, day);
                td = new Element('td');
                if (date.getMonth() == this.month) {
                    var cl = 'active';
                    if (date.getDate() == time.getDate() && date.getMonth() == time.getMonth() && date.getYear() == time.getYear()) {
                        cl = 'selected';
                        td.observe('mouseout', function(event){
                            event.element().writeAttribute('class', 'selected');
                        });
                    }
                    else {
                        td.observe('mouseover', function(event){
                            event.element().writeAttribute('class', 'hover');
                        });
                        td.observe('mouseout', function(event){
                            event.element().writeAttribute('class', 'active');
                        });
                    }
                    td.writeAttribute('class', cl);
                    td.observe('click', function(event){
                        var d = parseInt(event.element().firstChild.nodeValue);
                        this.updateInput(new Date(this.fullYear, this.month, d, time.getHours(), time.getMinutes()));
                        this.close();
                    }
.bindAsEventListener(this));
                }
                td.insert(date.getDate());
                day = day + 1;
                tr.insert(td);
            }
            table.insert(tr);
        }
        if (this.daySelectorDiv.firstChild) {
            this.daySelectorDiv.removeChild(this.daySelectorDiv.firstChild);
        }
        this.daySelectorDiv.insert(table);
    },
    openTimePicker: function(x, y){
        var time = this.time || new Date();
        if (!this.picker) {
            this.openPicker(x, y, 'timePicker');
            var timeSelectorDiv = new Element('div', {
                'class': 'timePickerTimeSelector'
            });
            var hoursField = new Element('select');
            for (var i = 0; i <= 23; i++) {
                var option = new Element('option', {
                    value: i,
                    selected: i == time.getHours()
                });
                option.insert(i);
                hoursField.insert(option);
            }
            var minutesField = new Element('select');
            for (var i = 0; i <= 11; ++i) {
                var option = new Element('option', {
                    value: i*5,
                    selected: time.getMinutes() >= i*5 && time.getMinutes() < (i+1)*5
                });
                option.insert(i*5);
                minutesField.insert(option);
            }
            var update = function(event){
                var hours = parseInt(hoursField.value);
                var minutes = parseInt(minutesField.value);
                this.updateInput(new Date(time.getFullYear(), time.getMonth(), time.getDate(), hours, minutes));
            }
.bindAsEventListener(this);
            hoursField.observe('change', update);
            minutesField.observe('change', update);
            timeSelectorDiv.insert(hoursField);
            timeSelectorDiv.insert(':');
            timeSelectorDiv.insert(minutesField);
            this.picker.insert(timeSelectorDiv);
            
        }
        else {
            this.close();
        }
    }
});

var SelectDateTimePicker = Class.create(DateTimePicker, {
    extendInput: function(){
        var update = function(){
            this.input.setValue('');
            if (this.showedPicker == 'both' || this.showedPicker == 'date') {
                this.input.setValue(this.input.getValue() + this.daySelect.getValue() + '-' + this.monthSelect.getValue() + '-' + this.yearSelect.getValue() + ' ')
            }
            if (this.showedPicker == 'both' || this.showedPicker == 'time') {
                this.input.setValue(this.input.getValue() + this.hourSelect.getValue() + ':' + this.minuteSelect.getValue());
            }
        }.bindAsEventListener(this);
        if (this.showedPicker == 'both' || this.showedPicker == 'date') {
            this.daySelect = new Element('select', {
                'class': 'dateTimePickerSelect'
            });
            this.daySelect.observe('change', update);
            for (var i = 1; i <= 31; ++i) {
                this.daySelect.insert(new Element('option', {
                    value: i,
                    selected: this.time && this.time.getDate() == i
                }).insert(this.fillString(i)));
            }
            this.input.insert({
                after: this.daySelect
            });
            this.monthSelect = new Element('select', {
                'class': 'dateTimePickerSelect'
            })
            this.monthSelect.observe('change', update);
            for (var i = 1; i <= 12; ++i) {
                this.monthSelect.insert(new Element('option', {
                    value: i,
                    selected: this.time && (this.time.getMonth() + 1) == i
                }).insert(this.fillString(i)));
            }
            this.daySelect.insert({
                after: this.monthSelect
            });
            this.daySelect.insert({
                after: '-&nbsp;'
            });
            
            this.yearSelect = new Element('select', {
                'class': 'dateTimePickerSelect'
            })
            this.yearSelect.observe('change', update);
            var now = new Date()
            for (var i = now.getFullYear(); i >= now.getFullYear() - 100; --i) {
                this.yearSelect.insert(new Element('option', {
                    value: i,
                    selected: this.time && this.time.getFullYear() == i
                }).insert(i));
            }
            this.monthSelect.insert({
                after: this.yearSelect
            });
            this.monthSelect.insert({
                after: '-&nbsp;'
            });
        }
        if (this.showedPicker == 'both' || this.showedPicker == 'time') {
            this.hourSelect = new Element('select', {
                'class': 'dateTimePickerSelect'
            })
            this.hourSelect.observe('change', update.bindAsEventListener(this));
            for (var i = 0; i <= 11; ++i) {
                this.hourSelect.insert(new Element('option', {
                    value: i,
                    selected: this.time && this.time.getHours() == i
                }).insert(this.fillString(i)));
            }
            if (this.yearSelect) {
                this.yearSelect.insert({
                    after: this.hourSelect
                });
                this.yearSelect.insert({
                    after: "&nbsp;"
                });
            }
            else {
                this.input.insert({
                    after: this.hourSelect
                });
            }            
            this.minuteSelect = new Element('select', {
                'class': 'dateTimePickerSelect'
            })
            this.minuteSelect.observe('change', update.bindAsEventListener(this));
            for (var i = 0; i <= 5; ++i) {
                this.minuteSelect.insert(new Element('option', {
                    value: i*10,
                    selected: this.time && this.time.getMinutes() >= i*10 && this.time.getMinutes() < (i+1)*10
                }).insert(this.fillString(i*10)));
            }
            this.hourSelect.insert({
                after: this.minuteSelect
            });
			this.hourSelect.insert({
                after: ':&nbsp;'
            });
        }
		// IE7 does not like this
        //this.input.writeAttribute('type','hidden');
		update();
    }
});


var ContextMenu = Class.create({
    initialize: function(element, entries, options){
       this.element = $(element);
        this.container = new Element('div', {
            'class': 'context_menu',
            'style': 'display:none;position:absolute;z-index: 1000000;'
        });
		var ul = new Element('ul');
		$A(entries).each(function(entry){
		  var li = new Element('li');		  
		  if (entry.handler) {
		  	li.addClassName('no_link');
		  	li.update(entry.title);
		  	li.observe('click', entry.handler);
		  }else if(entry.href){
		  	var a = new Element('a',{'class': 'context_menu_link',href: entry.href});
			a.update(entry.title);
			li.update(a);
		  }	
		  ul.insert(li);
		}.bind(this));		
        this.container.update(ul);
        this.element.insert(this.container);
        this.options = Object.extend({
            showDelay: 0.1,
            hideDelay: 0.3,
            duration: 0.2,
			openMode: ContextMenu.CLICK_LEFT
        }, options || {});
		this.initObservers();       
    },
    initObservers: function(){
        switch (this.options.openMode){
		  case ContextMenu.CLICK_LEFT:            
		    this.element.observe('click', function(event){              
			  if(event.isLeftClick()){			  	
				this.show();
			  }			  
            }.bindAsEventListener(this));
			break;
          case ContextMenu.CLICK_RIGHT:
            this.element.observe('click', function(event){
              if(event.isRightClick()){
			    Event.stop(event);
				this.show();
		      }
			  return false;
            }.bindAsEventListener(this));
			break;
          case ContextMenu.HOVER:
            this.element.observe('mouseover', this.mouseOver.bindAsEventListener(this));
			break;
        }
		this.container.observe('mouseover', this.mouseOver.bindAsEventListener(this));
		this.container.select('*').each(function(element){			
			element.observe('mouseover', this.mouseOver.bindAsEventListener(this));	
		}.bind(this));		
        this.element.observe('mouseout', this.mouseOut.bindAsEventListener(this));		
    },
    cancelShow: function(){
        if (this.showDelayId) {
            window.clearTimeout(this.showDelayId);
            this.showDelayId = null;
        }
        if (this.showEffect) {
            this.showEffect.cancel();
            this.showEffect = null;
        }
    },
    cancelHide: function(){
        if (this.hideDelayId) {
            window.clearTimeout(this.hideDelayId);
            this.hideDelayId = null;
        }
        if (this.hideEffect) {
            this.hideEffect.cancel();
            this.hideEffect = null;
        }
    },
    mouseOver: function(event){
        Event.stop(event);
        this.cancelHide();
        this.showDelayId = this.show.bind(this).delay(this.options.showDelay);
    },
    mouseOut: function(event){
        Event.stop(event);
        this.cancelShow();
        this.hideDelayId = this.hide.bind(this).delay(this.options.hideDelay);
    },
    show: function(){
        if (!this.shown) {
            this.shown = true;
            this.showEffect = new Effect.Appear(this.container, {
                duration: this.options.duration
            });
        }
    },
    hide: function(){
        if (this.shown) {
            this.shown = false;
            this.hideEffect = new Effect.Fade(this.container, {
                duration: this.options.duration
            });
        }
    }
});
ContextMenu.CLICK_LEFT = 'mouseclickleft';
ContextMenu.CLICK_RIGHT = 'mouseclickright';
ContextMenu.HOVER = 'mousehover';

var Schedule = {
    hide_effects: $H(),
    show_effects: $H(),
    hide_delays: $H(),
    show_delays: $H(),
    open_new_schedule_entry_popup: function(event, schedule_id, timetable_id, title, year, month, day, start_time, subject){
        new Popup(event, 'loading...', {
            title: title,
            width: '1024px',
            url: '/_call/' + schedule_id + '/_new_entry_view_html?year=' + year + '&month=' + month + '&day=' + day + '&start_time=' + start_time + '&subject=' + subject + '&timetable_id=' + timetable_id,
            closeOnBackgroundClick: false,
            buttons: [new Button('Save', {
                type: ButtonType.SUBMIT
            }), new Button('Cancel', {
                type: ButtonType.CANCEL
            })]
        });
    },
    open_existing_schedule_entry_popup: function(event, schedule_id, timetable_id, title, entry_id){
        new Popup(event, 'loading...', {
            title: title,
            width: '1024px',
            url: '/_call/' + schedule_id + '/_existing_entry_view_html?entry_id=' + entry_id + '&timetable_id=' + timetable_id,
            closeOnBackgroundClick: false,
            buttons: [new Button('Save', {
                type: ButtonType.SUBMIT
            }), new Button('Cancel', {
                type: ButtonType.CANCEL
            })]
        });
    },
    abort_show_effect: function(id){
        if (effect = this.show_effects.get(id)) {            
			effect.cancel();
			this.show_effects.unset(id);			
        }
		if(delay = this.show_delays.get(id)){
			window.clearTimeout(delay);
            this.show_delays.unset(id);
		}
    },
    abort_hide_effect: function(id){
        if (effect = this.hide_effects.get(id)) {			
            effect.cancel();
			this.hide_effects.unset(id);
        }
		if(delay = this.hide_delays.get(id)){			
			window.clearTimeout(delay);
            this.hide_delays.unset(id);
		}
    },
	show_edit_image:function(id){
		this.abort_hide_effect(id);
		this.show_delays.set(id,this.show_edit_image_delayed.bind(this).delay(0.01,id));
	},    
    show_edit_image_delayed: function(id){        
        this.show_effects.set(id, new Effect.Appear($('show_edit_img_' + id), {
            duration: 0.1
        }));
    },
	hide_edit_image: function(id){
		this.abort_show_effect(id);
		this.hide_delays.set(id,this.hide_edit_image_delayed.bind(this).delay(0.2,id));
	},
    hide_edit_image_delayed: function(id){
        this.hide_effects.set(id, new Effect.Fade($('show_edit_img_' + id), {
            duration: 0.1
        }));
    },
	attach_edit_image_observers:function(menu,id){
		menu.container.observe('mouseout',function(){this.hide_edit_image(id);}.bind(this));
		menu.container.select('*').each(function(element){
			element.observe('mouseover',function(){this.show_edit_image(id)}.bind(this));
		}.bind(this));
	}
};



var Schedule = {
    hide_effects: $H(),
    show_effects: $H(),
    hide_delays: $H(),
    show_delays: $H(),
    open_new_schedule_entry_popup: function(event, schedule_id, timetable_id, title, year, month, day, start_time, subject){
        new Popup(event, 'loading...', {
            title: title,
            width: '1024px',
            url: '/_call/' + schedule_id + '/_new_entry_view_html?year=' + year + '&month=' + month + '&day=' + day + '&start_time=' + start_time + '&subject=' + subject + '&timetable_id=' + timetable_id,
            closeOnBackgroundClick: false,
            buttons: [new Button('Save', {
                type: ButtonType.SUBMIT
            }), new Button('Cancel', {
                type: ButtonType.CANCEL
            })]
        });
    },
    open_existing_schedule_entry_popup: function(event, schedule_id, timetable_id, title, entry_id){
        new Popup(event, 'loading...', {
            title: title,
            width: '1024px',
            url: '/_call/' + schedule_id + '/_existing_entry_view_html?entry_id=' + entry_id + '&timetable_id=' + timetable_id,
            closeOnBackgroundClick: false,
            buttons: [new Button('Save', {
                type: ButtonType.SUBMIT
            }), new Button('Cancel', {
                type: ButtonType.CANCEL
            })]
        });
    },
    abort_show_effect: function(id){
        if (effect = this.show_effects.get(id)) {            
			effect.cancel();
			this.show_effects.unset(id);			
        }
		if(delay = this.show_delays.get(id)){
			window.clearTimeout(delay);
            this.show_delays.unset(id);
		}
    },
    abort_hide_effect: function(id){
        if (effect = this.hide_effects.get(id)) {			
            effect.cancel();
			this.hide_effects.unset(id);
        }
		if(delay = this.hide_delays.get(id)){			
			window.clearTimeout(delay);
            this.hide_delays.unset(id);
		}
    },
	show_edit_image:function(id){
		this.abort_hide_effect(id);
		this.show_delays.set(id,this.show_edit_image_delayed.bind(this).delay(0.01,id));
	},    
    show_edit_image_delayed: function(id){        
        this.show_effects.set(id, new Effect.Appear($('show_edit_img_' + id), {
            duration: 0.1
        }));
    },
	hide_edit_image: function(id){
		this.abort_show_effect(id);
		this.hide_delays.set(id,this.hide_edit_image_delayed.bind(this).delay(0.2,id));
	},
    hide_edit_image_delayed: function(id){
        this.hide_effects.set(id, new Effect.Fade($('show_edit_img_' + id), {
            duration: 0.1
        }));
    },
	attach_edit_image_observers:function(menu,id){
		menu.container.observe('mouseout',function(){this.hide_edit_image(id);}.bind(this));
		menu.container.select('*').each(function(element){
			element.observe('mouseover',function(){this.show_edit_image(id)}.bind(this));
		}.bind(this));
	}
};



var Schedule = {
    hide_effects: $H(),
    show_effects: $H(),
    hide_delays: $H(),
    show_delays: $H(),
    open_new_schedule_entry_popup: function(event, schedule_id, timetable_id, title, year, month, day, start_time, subject){
        new Popup(event, 'loading...', {
            title: title,
            width: '1024px',
            url: '/_call/' + schedule_id + '/_new_entry_view_html?year=' + year + '&month=' + month + '&day=' + day + '&start_time=' + start_time + '&subject=' + subject + '&timetable_id=' + timetable_id,
            closeOnBackgroundClick: false,
            buttons: [new Button('Save', {
                type: ButtonType.SUBMIT
            }), new Button('Cancel', {
                type: ButtonType.CANCEL
            })]
        });
    },
    open_existing_schedule_entry_popup: function(event, schedule_id, timetable_id, title, entry_id){
        new Popup(event, 'loading...', {
            title: title,
            width: '1024px',
            url: '/_call/' + schedule_id + '/_existing_entry_view_html?entry_id=' + entry_id + '&timetable_id=' + timetable_id,
            closeOnBackgroundClick: false,
            buttons: [new Button('Save', {
                type: ButtonType.SUBMIT
            }), new Button('Cancel', {
                type: ButtonType.CANCEL
            })]
        });
    },
    abort_show_effect: function(id){
        if (effect = this.show_effects.get(id)) {            
			effect.cancel();
			this.show_effects.unset(id);			
        }
		if(delay = this.show_delays.get(id)){
			window.clearTimeout(delay);
            this.show_delays.unset(id);
		}
    },
    abort_hide_effect: function(id){
        if (effect = this.hide_effects.get(id)) {			
            effect.cancel();
			this.hide_effects.unset(id);
        }
		if(delay = this.hide_delays.get(id)){			
			window.clearTimeout(delay);
            this.hide_delays.unset(id);
		}
    },
	show_edit_image:function(id){
		this.abort_hide_effect(id);
		this.show_delays.set(id,this.show_edit_image_delayed.bind(this).delay(0.01,id));
	},    
    show_edit_image_delayed: function(id){        
        this.show_effects.set(id, new Effect.Appear($('show_edit_img_' + id), {
            duration: 0.1
        }));
    },
	hide_edit_image: function(id){
		this.abort_show_effect(id);
		this.hide_delays.set(id,this.hide_edit_image_delayed.bind(this).delay(0.2,id));
	},
    hide_edit_image_delayed: function(id){
        this.hide_effects.set(id, new Effect.Fade($('show_edit_img_' + id), {
            duration: 0.1
        }));
    },
	attach_edit_image_observers:function(menu,id){
		menu.container.observe('mouseout',function(){this.hide_edit_image(id);}.bind(this));
		menu.container.select('*').each(function(element){
			element.observe('mouseover',function(){this.show_edit_image(id)}.bind(this));
		}.bind(this));
	}
};




