/**
 * This is to be used for rendering database objects like
 * documents and categories.  It handles drag and drop, menu
 * display and more.
 * @param {String} type The type of object (eg, kNexusObjectDocument)
 * @param {Number/String} id The id of the object.
 */
function NexusObject(type,id)
{	
	/** The id of the nexus object */
	this.id = id;
	
	/** The title of the nexus object */
	this.title = '';
    
    /** Holds the tooltip object */
    this.tooltip = '';

	/** The type of nexus object - kNexusObjectDocument or kNexusObjectCateogry */
	this.type = '';
	
	/** The description of the nexus object (optional) */
	this.description = '';

	/** the relative path (from the nexus root) to the representative image */
	this.icon = '';

	/** The link to use to for elements that should have links 
	 * 	(optional) 
	 */
	this.defaultLink = '';
	
	/** This is text that gives meta information about the object and is
	 * is specific to the type of object this is (e.g. categories use this 
	 * to tell the user how many documents are inside)
	 */
	this.specialInfo;
	
	/**
	 * The id of the element that the user can manipualte to indicate selection
	 * or deselection.
	 */
	this.selectorId;
	
	/** The date that this object was last modified (optional) */
	this.modifiedDate = '';
	
	/** The list of actions that can be performed on this object (optional) */
	this.actions = new Array();
	
	/** Used internally */
	this.dragObject = null;
	
	/** Used internally */
	this.menu = null;
	
	/** whether or not this item is selected */	
	this.selected = false;
	
	/** This is the function that is called by event handler to update 
	 * the appearance of the object on screen based on whether or not 
	 * the object is now selected (takes a single parameter which is a  
	 * bool indicating whether or not it's selected).
	 */
	this.updateSelectionStyle = null;
		
	// this is where the nexus objects are rendered
	this.containerDiv = 'nexusObjects';
			
	/**
	 * Called when the user has clicked on the element that has
	 * been tagged as the 'trigger' for the display of the menu.
	 * @param {Object} e The event that occured
	 * @param {Object} me The object passed into the subscription
	 * 					call.  in this case, a NexusObject reference
	 */
	this.onMenuTriggerClick = function (e,me)
	{
		// This will only render if it has not already been rendered
		this.renderActionsAsMenu();
		
		var region = YAHOO.util.Dom.getRegion(me.getElementId());
		
		// Move the menu to the current position of the element.
		me.menu.cfg.setProperty('x',region.right);
		me.menu.cfg.setProperty('y',region.top);
		me.menu.show();
	}

	/**
	 * This handler should only be used by menu items that have to
	 * execute javascript upon clicking.  Otherwise, the menu item should
	 * simply use the 'url' property. 
	 * @param {Object} e1 Type of event
	 * @param {Object} e2 mouse event info
	 * @param {String} obj The javascript expression to evaluate
	 */
	this.onMenuItemClicked = function (e1,e2,obj)
	{		
		eval(obj);
	}
	
	/**
	 * Called when the selected element is clicked by the user.  The selection
	 * value is stored in this object, not in the element itself.
	 * @param {Object} e1 Type of event
	 * @param {NexusObject} obj The nexus object (this)
	 */
	this.onSelectionChanged = function (e1,obj)
	{
		obj.setSelection(!obj.selected);
	}
    
    /**
     * Changes the seleciton state of the object. Nothing will
     *  be done if the selection state is already set to the 
     *  given value.
     *  @param {bool} True to select false otherwise.
     */
    this.setSelection = function(bSelect)
    {
        if (this.selected == bSelect)
        {
            return true;
        }
        
        this.selected = bSelect;
        if (this.updateSelectionStyle)
        {
            this.updateSelectionStyle(this.selected);
        }
        
        return true;
    }
    
	
	// initialize the member function references 
	// for the class prototype
	if (typeof(_nexusobject_prototype_called) == 'undefined')
	{
		 _nexusobject_prototype_called = true;
		 NexusObject.prototype.render_large = render_large;
		 NexusObject.prototype.render_small = render_small;
		 NexusObject.prototype.render_list = render_list;
		 NexusObject.prototype.renderActionsAsMenu = renderActionsAsMenu;
		 NexusObject.prototype.getElementId = getElementId;
		 NexusObject.prototype.prepareDragDrop = prepareDragDrop;
		 NexusObject.prototype.addAction = addAction;		
		 	
	}
	 
	/**
	 * Retrieves the ID of the element that represents this object.
	 * The ID is a string that merges the type identifier with the 
	 * nexus object id (e.g. doc_5)
	 */ 	
	function getElementId()
	{
		return (this.type + '_' + this.id);	
	}	
			
	/**
	 * Use this to add new actions to the list of possible
	 * actions allowed for this object.  You should only
	 * render the element *after* the actions have been added.
	 * Some rendering function do not use actions so this
	 * list will be ignored (eg, render_small)
	 * @param {String} name The name of the action as it will appear to the user
	 * @param {Object} link The standard link used to execute the action
	 * @param {Object} specialLink Javascript that should be executed when the user
	 * 					invokes the action.
	 */
	function addAction(name,link,specialLink,icon)
	{
		var action = new Array();
		action['name'] = name;
		action['link'] = link;
		action['specialLink'] = specialLink;
		action['icon'] = icon;
		
		this.actions[this.actions.length] = action;
		
		return this.actions.length;
	}

	/**
	 * Renders the object in our standard vertical list format
	 * 
	 */
	function render_list(containerDiv)
	{
		// start by creating the child container
		var el = document.createElement('div');
		el.setAttribute('id','nexus_' + this.type + '_'+this.id);		
		
		// Then wrap the parent container
		var elParent = YAHOO.util.Dom.get(containerDiv);
		
		var menuId = 'menu_content_'+ this.type +'_' + this.id;
		var menuTriggerId = 'menu_trigger_' + this.type + '_' + this.id;
		
		var itemId = this.getElementId();
		
		var dragItemId = itemId + '_drag';
		var titleItemId = itemId + '_name';
		this.selectorId = 'select_' + this.type + '_' + this.id;
		
		var checked = this.selected ? 'checked' : '';
		
		itemMarkup = '<div id="' + itemId + '" class="browser_item_wrapper">';	
		itemMarkup += '<div class="browser_item_checkbox">';		
		itemMarkup += '<input type="checkbox" name="nexus_objects[]" id="'+
									this.selectorId+'" ' + checked + ' value="'+itemId+'"/>';
									
		itemMarkup += '<div style="padding-left:3px;" id="' + dragItemId + '"><img src="themes/default/images/draghandle.png"/></div>';									
		itemMarkup += '</div>';
		itemMarkup += '<div class="browser_item_icon">';
		itemMarkup += '<a title="View" href="'+ this.defaultLink +'"><img align="top" border="0" src="'+this.icon+'"></a>';
		itemMarkup += '</div>';
		itemMarkup += '<div class="browser_item_info">';
		itemMarkup += '<span id="'+ titleItemId +'" class="browser_item_title">' + this.title + '</span>';
		itemMarkup += '<span class="browser_item_type">(' + this.specialInfo + ')</span>';
		
		var desc = '[no description given]';
		if (this.description != '')
		{
			desc = this.description;			
		}
					
		itemMarkup += '<div class="browser_item_description">' + desc + '</div>';
		
		for (i=0;i<this.actions.length;i++)
		{			
			var action = this.actions[i];

			itemMarkup += '<span id="'+ action['id'] + '_' + this.id + '">';
			itemMarkup += '<a href="'+ action['link'] + '" onclick="'+ action['specialLink']+'">';
			itemMarkup += '<img title="'+ action['name'] +'" border="0" src="'+ action['icon']+'"/>';
			itemMarkup += '</a>'; 
			itemMarkup += '</span>';
		}	
				
		el.innerHTML = itemMarkup;
		elParent.appendChild(el);
		
		// this will be called when the user selects/deselect the item
		//	so that we can customize the selection appearance for this 
		//	type of rendering.
		this.updateSelectionStyle = function(selected)
		{
			var itemId = this.type + '_' + this.id;
			if (selected)
			{
				YAHOO.util.Dom.setStyle(itemId, 'border-left-width','4px');
			}		
			else
			{
				YAHOO.util.Dom.setStyle(itemId, 'border-left-width','1px');
			}
		}
		
		YAHOO.util.Event.addListener(this.selectorId, "click", 
										this.onSelectionChanged, this, true);
																		
		this.prepareDragDrop(dragItemId);		
	}
	
	/**
	 * This will instantiate the dragdrop object and setup the 
	 * appropriate callbacks for dropping.
	 * @param {String} dragItemId The Id of the item to be dragged.
	 */
	function prepareDragDrop(dragItemId)
	{
		this.dragObject = new YAHOO.util.DD(dragItemId);
			
		if (this.type == kNexusTypeDocument)
		{
			this.dragObject.onDragDrop = 
				function(e,dropItemId)
				{
					dragItemId = YAHOO.util.DragDropMgr.dragCurrent.dragElId;
					onDragDropItem(dropItemId,dragItemId);
				};
		}
		else if (this.type == kNexusTypeCategory)
		{
			this.dragObject.onDragDrop = 
				function(e,dropItemId)
				{
					dragItemId = YAHOO.util.DragDropMgr.dragCurrent.dragElId;
					onDragDropCategory(dropItemId,dragItemId);
				};
		}
			

		this.dragObject.startDrag = prepareDrag;
		this.dragObject.onInvalidDrop = cleanupDrag;			
	}
	
	/**
	 * Renders the object into an area appropriate for sidebars
	 * or other constrained spaces.  This was created primarily for
	 * the category browser and the recent documents list found on
	 * the frontpage sidebar.
	 * @param {String} The container element id into which this 
	 * 					object should berendered
	 */
	function render_small(containerDiv)
	{
		// start by creating the child container
		var el = document.createElement('div');
		el.setAttribute('id','nexus_small_' + this.type + '_'+this.id);
		
		// Then wrap the parent container
		var elParent = YAHOO.util.Dom.get(containerDiv);				
		var itemId = this.getElementId();
				
		// The item itself
		itemMarkup = '<div class="icBrowseItem" id="'+ itemId +'">';
		itemMarkup += '<a href="'+this.defaultLink+'">';
		itemMarkup += '<img style="margin-right:3px;float:left" border="0" src="'+this.icon+'" alt="'+this.title+'"/>';
		itemMarkup += this.title;
		itemMarkup += '<span class="date">&nbsp;('+this.modifiedDate+')</span></a>';
		itemMarkup += '</div>';
												
		el.innerHTML = itemMarkup;
		elParent.appendChild(el);
				
		this.prepareDragDrop(itemId);
	}
	
	function renderActionsAsMenu()
	{
		// We only need to render the menu once.
		if (this.menu != null) return;
		
		var itemId = this.getElementId();
		var menuId = 'menu_content_'+ this.type +'_' + this.id;
		
		// Actions		
		this.menu = new YAHOO.widget.Menu(menuId);						
		for (i=0;i<this.actions.length;i++)
		{			
			var action = this.actions[i];
			
			var menuItem = this.menu.addItem(new YAHOO.widget.MenuItem(action['name']));
			if (action['specialLink'] == '')  
			{
				menuItem.cfg.setProperty('url',action['link']);
			}
			else
			{
				menuItem.cfg.setProperty('onclick',{fn:this.onMenuItemClicked,obj:action['specialLink'],scope:this});
			}
		}	
		
		this.menu.render(document.body);		
	}
	
	/**
	 * This will render the object into the container
	 * div.  
	 * @param {String} containerDiv The div to render it into.
	 */	
	function render_large(containerDiv)
	{
		var itemId = this.getElementId();
				
		// start by creating the child container
		var el = document.createElement('div');
		el.setAttribute('id','container_' + itemId);
		//el.setAttribute('class','iconViewItem');
				
		// Then wrap the parent container
		var elParent = YAHOO.util.Dom.get(containerDiv);
		
		var menuTriggerId = 'menu_trigger_' + this.type + '_' + this.id;
		this.selectorId = 'sel_trigger_' + this.type + '_' + this.id;
		
		var titleItemId = itemId + '_name';
				
		// The item itself
		var itemMarkup = '<div id="'+ itemId +'" class="iconViewItem">';
		itemMarkup += '<div id="' + this.selectorId + '" class="menu"><a href="javascript:void(0);">';
		itemMarkup += '<img id="' + menuTriggerId + '" src="themes/default/images/menu_trigger.jpg" border="0"/></a></div>';
		itemMarkup += '<div class="iconViewIcon">';
        
        if (this.defaultLink != '') {
            itemMarkup += '<a href="'+this.defaultLink+'">';
        }
        
		itemMarkup += '<div><img border="0" src="'+ this.icon +'"/></div>';
        
        if (this.defaultLink != '') {
            itemMarkup += '</a>';
        }
        
        itemMarkup += '</div>';
		itemMarkup += '<div class="iconViewText">';
        
        if (this.defaultLink != '') {
            itemMarkup += '<a id="'+ titleItemId +'" href="'+this.defaultLink+'">';
        }
        else{
            itemMarkup += '<div style="font-weight:bold;padding:2px;">';
        }

		itemMarkup += this.title;
        
        if (this.defaultLink != '') {
            itemMarkup += '</a>';
        }
        else {
            itemMarkup += '</div>';
        }
                
        itemMarkup += '</div></div>';
										
		el.innerHTML = itemMarkup;
		elParent.appendChild(el);

		// Selection
		// this will be called when the user selects/deselect the item
		//	so that we can customize the selection appearance for this 
		//	type of rendering.
		this.updateSelectionStyle = function(selected)
		{
			var itemId = this.type + '_' + this.id;
			if (selected)
			{
				YAHOO.util.Dom.setStyle(itemId, 'border','1px solid #7fa4c2');
			}		
			else
			{
				YAHOO.util.Dom.setStyle(itemId, 'border','1px solid #efefef');
			}
		}
		
		YAHOO.util.Event.addListener(this.selectorId, "click", 
										this.onSelectionChanged, this, true);		
		
		YAHOO.util.Event.addListener(menuTriggerId, "click", this.onMenuTriggerClick, this, true);
			
        this.tooltip = new YAHOO.widget.Tooltip(itemId+'_tooltip', { context:this.getElementId(), text:this.title } );          	
		// Drag/Drop
		this.prepareDragDrop(itemId);	
	}
}
