/*
 * Copyright (c) 1997-2005 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */

/*
 * ContextMenu
 *
 * Used to draw a context menu with icon and text items.
 */

/**
 * context menu constructor
 * @param name the name of the context menu
 */
function ContextMenu(name) {
    this.name = name;
    this.items = new Array();
    this.xOff = 0;
    this.yOff = 0;
    this.docroot = "";
    this.attachedToMouse = false;
}

/** CSS classes */
/*String*/ContextMenu.menuClass      = "contextMenu";          // DIV element
/*String*/ContextMenu.itemClass      = "contextMenuItem";      // A/IMG elements
/*String*/ContextMenu.coatClass      = "contextMenuCoat";      // DIV element
/*String*/ContextMenu.separatorClass = "contextMenuSeparator"; // HR element
/*String*/ContextMenu.disabledClass  = "contextMenuDisabled";  // all elements

/** Width of context menu (as defined by CSS class) */
/*int*/ContextMenu.menuWidth = navigator.appName.indexOf("Microsoft") != -1 ? 122 : 142;

/** map containing all the registred context menus */
/*Object*/ContextMenu.controls = new Object();

/**
 * Creates a new ContextMenu and puts it into the control registry
 * @param name     name of new context menu
 *
 * @return newly created context menu instance
 */
/*ContextMenu*/ContextMenu.create = function(/*String*/ name) {
	return this.controls[name] = new ContextMenu(name);
}

/**
 * Returns the context menu with the given name
 * @param name name of the control to return
 *
 * @return control with the given name
 */
/*ContextMenu*/ContextMenu.getControl = function(/*String*/ name) {
	return this.controls[name];
}

/**
 * Shows the context menu with the given name
 * @param name Name of the context menu to show
 * @param elem HTML element for orientation
 * @param evt Event
 */
/*boolean*/ContextMenu.showMenu = function(/*String*/name,/*HTMLElement*/elem,/*Event*/evt) {
    return this.controls[name].show(elem,evt);
}

/**
 * Toggles the context menu with the given name
 * @param name Name of the context menu to toggle
 * @param elem HTML element for orientation
 * @param evt Event
 */
/*boolean*/ContextMenu.toggleMenu = function(/*String*/name,/*HTMLElement*/elem,
                /*Event*/evt) {
    var contextMenu = this.controls[name];
    contextMenu.init();
    if (Util.getProp(contextMenu.menu,"display") == "block") {
        contextMenu.hide(); // hide menu
        return false;
    }
    contextMenu.populate();
    return contextMenu.show(elem,evt);
}

/**
 * Hides all context menus
 */
/*boolean*/ContextMenu.hideAll = function() {
    for (var i in this.controls) {
        this.controls[i].hide();
    }
    return true;
}

/**
 * Returns an offset object with x and y property of all nested iFrames
 */
/*boolean*/ContextMenu.getFramesOffset = function(/*Document*/ targetDocument,
   /*Window*/ parentWindow) {
    
    var frames = parentWindow.frames;

    for (var i = 0; i < frames.length; i++) {
        var frame = frames[i];
        var frameElem = parentWindow.document.getElementById(frame.name);

        if (frame.document == targetDocument) {
            var offset = new Object();
            offset.x = Util.getPosX(frameElem);
            offset.y = Util.getPosY(frameElem);
            return offset;
        }
        else {
            var childOffset = ContextMenu.getFramesOffset(targetDocument, frame.frames);
            if (childOffset != null) {
                var offset = new Object();
                offset.x = childOffset.x + Util.getPosX(frameElem);
                offset.y = childOffset.y + Util.getPosY(frameElem);
                return offset;
            }
        }
    }
    // target frame is not part of this branch
    return null;
}


//------------------------------------------------------------------------------

/**
 * Sets the docroot for the images and other resources
 * @param docroot the docroot to set
 */
/*void*/ContextMenu.prototype.setDocroot = function(/*String*/ docroot) {
    this.docroot = docroot;
}

/**
 * Sets attachedToMouse - if true, the menu will be placed relative to the mouse,
 * otherwise relative to an HTML object (offsets will be respected in both cases)
 * @param attached the value
 */
/*void*/ContextMenu.prototype.setAttachedToMouse = function(/*boolean*/ attached) {
    this.attachedToMouse = attached;
}

/**
 * Sets the offset to use when showing the context menu
 * @param x Horizontal offset
 * @param y Horizontal offset
 */
/*void*/ContextMenu.prototype.setOffset= function(/*int*/ x, /*int*/ y) {
    this.xOff = x;
    this.yOff = y;
}

/**
 * Adds a menu item to the menu
 * @param item the menu item to add
 */
/*void*/ContextMenu.prototype.addItem = function(/*ContextMenuItem*/ item) {
    this.items.push(item);
    item.setDocroot(this.docroot);
    if (item.icon) {
        // preload icon
        var img = new Image();
        img.src = this.docroot+item.icon;
    }
}

/**
 * Returns the item of a given name or null if it doesn't exist
 * @param name the name of the item
 * @return the item
/*ContextMenuItem*/ContextMenu.prototype.getItem = function(/*String*/ name) {
    var item;
    for (var i in this.items) {
        if (this.items[i].name == name) {
            item = this.items[i];
            break;
        }
    }
    return item;
}

/**
 * Returns the items of this context menu
 * @return the items of this context menu
 */
/*Array*/ContextMenu.prototype.getItems = function() {
    return this.items;
}

/**
 * Determines whether context menu has menu items
 * @return true if there are items, false otherwise
 */
/*boolean*/ContextMenu.prototype.hasItems = function() {
    return this.items.length > 0;
}

/**
 * Sets the 'enabled' state of the item specified by 'name'
 * @param name the name of the item
 * @param enable if true, enables item; if false, disables it
 */
/*void*/ContextMenu.prototype.enableItem = function(/*String*/ name, /*boolean*/enable) {
    var item = this.getItem(name);
    if (item) {
        item.enable(enable);
    } else {
        // find multi button items and propagate enable action
        for (var i in this.items) {
            if (this.items[i] instanceof ContextMenuMultiButton) {
                this.items[i].enableItem(name,enable);
            }
        }
    }
}

/**
 * Deletes all menu items on the menu
 */
/*void*/ContextMenu.prototype.clear = function() {
    this.items = new Array();
}

/**
 * Initiates this context menu
 */
/*void*/ContextMenu.prototype.init = function() {
    /*if (!this.menu)*/ this.menu = Util.getElem(this.name);
    /*if (!this.coat)*/ this.coat = Util.getElem(this.name+"_coat");
}

/**
 * Draws the context menu to the current document
 */
/*void*/ContextMenu.prototype.draw = function() {
    document.writeln(this.getOuterHTML());
}

/**
 * Returns the outer HTML of the context menu
 * @return the outer HTML of the context menu
/*String*/ContextMenu.prototype.getOuterHTML = function() {
    var str = "";
    str += '<div id="'+this.name+'" class="'+ContextMenu.menuClass+'">&nbsp;</div>';
    str += '<div id="'+this.name+'_coat" class="'+ContextMenu.coatClass+'" onclick="ContextMenu.hideAll()" oncontextmenu="ContextMenu.hideAll();return false;">&nbsp;</div>';
    return str;
}


/**
 * (Re-)Populates the context menu according to its items
 */
/*void*/ContextMenu.prototype.populate = function() {
    this.init();
    // get content
    var str = "";
    for (var i in this.items) {
        var item = this.items[i];
        str += item.getOuterHTML();
    }
    this.menu.innerHTML = str;
}


/**
 * Shows the context menu
 * @param elem HTML element for orientation
 * @param evt Event
 */
/*boolean*/ContextMenu.prototype.show = function(/*HTMLElement*/elem,/*Event*/evt) {
    //alert("show:"+this.name);
    ContextMenu.hideAll(); // hide any other context menu
    this.init();
    Util.stopEventBubble(evt);
    var x,y;

    if (this.attachedToMouse || elem == null) {
        if (evt.pageX) {
            x = evt.pageX;
            y = evt.pageY;
        }
        else {
            x = evt.clientX;
            y = evt.clientY;
        }

        // add offset if the event was fired inside an iframe
        var target; // element that did fire the event
        if (evt.srcElement) target = evt.srcElement; // ie
        else target = evt.target; // ff
        var targetDocument = target.ownerDocument;
        if (targetDocument != document) {

            var offset = ContextMenu.getFramesOffset(targetDocument, window);
            if (offset != null) {
                x += offset.x;
                y += offset.y;
            }

            if (evt.pageX) {
                // ff: add scrolling
                x -= targetDocument.body.scrollLeft;
                y -= targetDocument.body.scrollTop;
            }
        }
        x += 1;
        y += 1;
    }
    else {
        y = Util.getPosY(elem);
        x = Util.getPosX(elem);
        x += this.xOff;
        y += this.yOff;
    }

    var menuRight = x+ContextMenu.menuWidth;
    if (menuRight + 5 >= Util.getWindowWidth() + document.body.scrollLeft) {
        // menu out of window on the right side
        if (this.attachedToMouse || elem == null) x = x - ContextMenu.menuWidth;
        else x = Util.getWindowWidth() - ContextMenu.menuWidth - 20 + document.body.scrollLeft;
    }

    Util.setProp(this.menu,"top",y);
    Util.setProp(this.menu,"left",x);
    Util.setProp(this.menu,"display","block"); // show menu

    var lastItemElem = Util.getElem(this.items[this.items.length - 1].name);
    var lastItemBottom = Util.getPosY(lastItemElem);
    if (lastItemBottom + 5 > Util.getWindowHeight()) {
        // menu out of window at bottom: move menu upwards
        var menuHeight = lastItemBottom - y;
        Util.setProp(this.menu,"top",y - menuHeight - 24);
        if (parseInt(Util.getProp(this.menu, "top")) < 5) {
            // menu out of window at top
            Util.setProp(this.menu,"top",5);
        }
    }

    Util.setProp(this.coat,"width",Util.getWindowWidth()-20);

    Util.setProp(this.coat,"height",Util.getWindowHeight()-20);
    Util.setProp(this.coat,"display","block"); // show coat
    return false;
}


/**
 * Hides the context menu
 */
/*void*/ContextMenu.prototype.hide = function() {
    this.init();
    Util.setProp(this.menu,"display","none");
    Util.setProp(this.coat,"display","none");

}


//------------------------------------------------------------------------------
// ContextMenuItem
//------------------------------------------------------------------------------

/**
 * ContextMenuItem item constructor
 * @see #init
 */
function ContextMenuItem(/*String*/name) {
    this.init(name);
}

/**
 * initiaizes the context menu item.
 * @param name the name of the context menu item
 */
ContextMenuItem.prototype.init = function(/*String*/ name) {
    this.name = name;
    this.docroot = "";
}

/**
 * Enables or disables this context menu item
 * @param enable true if item should be enabled, false otherwise
 */
/*void*/ContextMenuItem.prototype.enable  = function(/*boolean*/enable) {
    //alert("enable:"+enable+"//isDisabled:" + this.isDisabled);

    if (this.isDisabled!=enable) return;
    var elem = Util.getElem(this.name);
    //alert(this.name);
    //alert(document.getElementById(this.name));
    if (!elem) return;
    this.isDisabled=!enable;
}

/**
 * Sets the docroot for the images and other resources
 * @param docroot the docroot to set
 */
ContextMenuItem.prototype.setDocroot = function(/*String*/docroot) {
    this.docroot = docroot;
}

/**
 * Returns the outer HTML of this item
 * @return the outer HTML of this item
 */
/*String*/ContextMenuItem.prototype.getOuterHTML = function() {
    return this.getInnerHTML();
}

/**
 * Returns the inner HTML of this item
 * @return the inner HTML of this item
 */
/*String*/ ContextMenuItem.prototype.getInnerHTML = function() {
    return "&nbsp;";
}

/**
 * subclasses the given obj from this
 */
ContextMenuItem.subClassMe = function(/*Object*/ obj) {
    obj.prototype = new this();
    obj.prototype._init = this.prototype.init;
}

//------------------------------------------------------------------------------
// ContextMenuSeparator
//------------------------------------------------------------------------------

/**
 * creates a new context menu separator item
 * @param name the name of the separator
 */
function ContextMenuSeparator(name) {
    this.init(name);
}
ContextMenuItem.subClassMe(ContextMenuSeparator);

/**
 * initializes this item
 * @param name the name of this item
 */
ContextMenuSeparator.prototype.init = function(/*String*/name) {
    this._init(name);
    //this.cssClass = "separator";
}

/**
 * @see ContextMenuItem#getInnerHTML
 */
/*String*/ ContextMenuSeparator.prototype.getInnerHTML = function(/* boolean */ inDropDown) {
    return '<hr noshade size="1" class="'+ContextMenu.separatorClass+'">';
}

//------------------------------------------------------------------------------
// ContextMenuButton
//------------------------------------------------------------------------------

/**
 * creates a new context menu button item
 * @param name the name of the new context menu button
 */
function ContextMenuButton(/*String*/name, /*String*/ icon, /*String*/text,
                /*String*/action, /*String*/alt, /*boolean*/enabled) {
    this.init(name,icon,text,action,alt,enabled);
}
ContextMenuItem.subClassMe(ContextMenuButton);

/**
 * initializes this spacer
 * @param name the name of this item
 * @param icon the icon for this button
 * @param text the text of the button
 * @param action the action
 * @param alt the alt-text
 * @param enabled the enabled flag
 */
ContextMenuButton.prototype.init = function(/*String*/name, /*String*/ icon,
              /*String*/text,/*String*/action, /*String*/alt, /*boolean*/enabled) {
    this._init(name);
    this.icon = icon;
    this.text = text;
    this.action = action;
    this.alt = alt;
    this.isDisabled=!enabled;
    if (!this.text) this.text = this.alt;
}

/**
 * @see ContextMenuItem#getInnerHTML
 */
ContextMenuButton.prototype.getInnerHTML = function() {
    var str = "";
    var href= "javascript:"+this.action;
    var onclick = "ContextMenu.hideAll()";
    var cssClass = ContextMenu.itemClass;
    var cssStyle = "";
    if (!this.icon) cssStyle = "padding-left:20px";
    else cssStyle = "padding-right:20px;";
    if (this.isDisabled) cssClass +=" "+ContextMenu.disabledClass;
    if (this.isDisabled) {
            str = '<a class="'+cssClass+'" style="'+cssStyle+'" id="'+this.name+'" title="'+this.alt+'">';
    } else {
            str = '<a class="'+cssClass+'" style="'+cssStyle+'" id="'+this.name+'" href="'+href+'" onclick="'+onclick+'" title="'+this.alt+'">';
    }
    if (this.icon) {
                str+='<img class="'+cssClass+'" src="'+this.docroot+this.icon+'">';
    }
    str += this.text;
    str += '</a>';
    return str;
}

//------------------------------------------------------------------------------
// ContextMenuMultiButton
//------------------------------------------------------------------------------

/**
 * creates a new context menu multi button item
 * @param name the name of the new context menu multi button item
 */
function ContextMenuMultiButton(/*String*/name, /*String*/ icon,
              /*String*/text, /*String*/action, /*String*/alt,
              /*boolean*/enabled) {
    this.init(name,icon,text,action,alt,enabled);
}
ContextMenuItem.subClassMe(ContextMenuMultiButton);

/**
 * initializes this multi button item
 * @param name the name of this item
 * @param icon the icon for this button
 * @param text the text of the button
 * @param action the action
 * @param alt the alt-text
 * @param enabled the enabled flag
 */
ContextMenuMultiButton.prototype.init = function(/*String*/name, /*String*/ icon,
              /*String*/text,/*String*/action, /*String*/alt, /*boolean*/enabled) {
    this._init(name);
    this.icon = icon;
    this.text = alt;
    this.action = action;
    this.alt = alt;
    this.isDisabled=!enabled;
    this.contextMenu = ContextMenu.create(this.name+"_sub");
    this.contextMenu.setOffset(ContextMenu.menuWidth, 0);

}

/**
 * Adds a new item to this multi button item
 * @param item context menu item to add
 */
/*void*/ContextMenuMultiButton.prototype.addItem = function(/*ContextMenuItem*/ item) {
    this.contextMenu.addItem(item);
}

/**
 * Deletes all items from this multi button item
 */
/*void*/ContextMenuMultiButton.prototype.clear = function() {
    this.contextMenu.clear();
}


/**
 * Determines whether multi button item has items
 * @return true if there are items, false otherwise
 */
/*boolean*/ContextMenuMultiButton.prototype.hasItems = function() {
    return this.contextMenu.hasItems();
}

/**
 * @see ContextMenuItem#setDocroot
 */
ContextMenuMultiButton.prototype.setDocroot = function(/*String*/docroot) {
    this.docroot = docroot;
    this.contextMenu.setDocroot(docroot);
}

/**
 * @see ContextMenuItem#getInnerHTML
 */
ContextMenuMultiButton.prototype.getInnerHTML = function() {
    var str = "";
    var href = "javascript:void(0);";
    var onclick = "ContextMenu.toggleMenu('"+this.contextMenu.name+"',this,event)";
    var onfocus = "this.blur()";
    var onclick = "ContextMenu.hideAll()";
    var cssClass = ContextMenu.itemClass;
    var cssStyle = "";
    if (!this.icon) cssStyle = "padding-left:20px";
    if (this.isDisabled) cssClass +=" "+ContextMenu.disabledClass;
    if (this.isDisabled) {
        str += '<a class="'+cssClass+'" style="'+cssStyle+'" id="'+this.name+'" title="'+this.alt+'">';
    } else {
        str += '<a class="'+cssClass+'" style="'+cssStyle+'" id="'+this.name+'" href="'+href+'" onclick="'+onclick+'" onfocus="'+onfocus+'" title="'+this.alt+'">';
    }
    if (this.icon) {
        str += '<img class="'+cssClass+'" src="'+this.docroot+this.icon+'">';
    }
    str += this.text;
    str += '</a>';
    return str;

    var str = "";
    var cssClass = ContextMenu.buttonClass;
    if (this.isDisabled) cssClass +=" "+ContextMenu.disabledClass;
    if (!this.isDisabled) {
        str += '<a class="'+cssClass+'" href="'+href+'" onclick="'+onclick+'" onfocus="'+onfocus+'" title="'+this.alt+'">';
    } else {
        str += '<span title="'+this.alt+'" class="'+cssClass+'">';
    }
    if (this.icon) {
        str+='<img class="'+cssClass+'" src="'+this.docroot+this.icon+'">';
    }
    str+= this.text ? this.text : '&nbsp;';
    if (!this.isDisabled) {
        str+='</a>';
    } else {
        str+='</span>';
    }
    str += this.contextMenu.getOuterHTML();
    return str;
}
