/*************************************************************
Widget: rock.unimerse.category
Description: Unimerse product category widget

Depends on: 
jmaki.js, prototype.js, scriptaculous/Builder.js,
rock.js, rock-utils.js, rock-amazon.js

Author: Joe Hu, joe.hu@unimerse.com
Verseion: 1.0.0
	
Widget attributes:
  service: service url - xhp url, optional. 
  			 default: jmaki.webRoot + "/xhp".
  args:
  	rootCategoriesUrl - default: categories.json
  	browseNodeId - must be a valid BrowseNodeId. default: -1
  	browseCategoryLabel - must match a key in the root categories. default: Home
	targetId - ID of target container for displaying search result. default: content
    		
NOTE: "Subject"'s browse node id is 1000.    		      
***************************************************************/
 
// define the namespaces
jmaki.namespace("jmaki.widgets.rock.unimerse.category");

jmaki.widgets.rock.unimerse.category.Widget = function(wargs) {
			
    var CATEGORORIES_LABEL = "Categories";  
    var HOME_CATEGORY = "Electronics";	  // home or blended or all category is mapped to this category.
    var name = "rock.unimerse.category";  // component name
    var uuid = wargs.uuid;
    var rootCategories; // literal object - map of root categories 
    var expandedNodes = [];

    //service
    var service = jmaki.webRoot + "/xhp";  // default service url   

    //args
    var rootCategoriesUrl = 'categories.json';
    var browseNodeId = -1;       	
    var browseCategoryLabel = 'Home';  
    var targetId = "content"; // default target container ID

    // published events (topics)
    var topicBeforeNodeExpanded = "/rock/unimerse/category/beforeNodeExpanded";  

    // subscribed events
    var topicOnTabClicked = "/rock/tabview/tabClicked";	 
    
    // check attribute service
    if(wargs.service){
	service = wargs.service;
    }
	    
    // check attribute args
    if (wargs.args){		
	// check browseNodeId
    	if (wargs.args.browseNodeId) {
	        browseNodeId = wargs.args.browseNodeId;
	}			
		
	// check rootCategoriesUrl
    	if (wargs.args.rootCategoriesUrl) {
		rootCategoriesUrl = wargs.args.rootCategoriesUrl;
	}
		
	// check browseCategoryLabel
    	if (wargs.args.browseCategoryLabel) {
		browseCategoryLabel = wargs.args.browseCategoryLabel;
	}	
				
    	// check targetId
    	if (wargs.args.targetId) {
		targetId = wargs.args.targetId;
	}			   			
    }				

    // load root category list
    loadRootCategories(rootCategoriesUrl);		
		
    if(browseNodeId >= 0){
    	// ok, browseNodeId specified. expand it!
	expand(browseNodeId);		
    }else{
	expandCategory(browseCategoryLabel);  	     			
    }
	          	  	     		        

    /**
     * Retrieve definition of root categories
     */
    function loadRootCategories(url){
	new Ajax.Request( 
	    url, 
	    { method: 'get', 
	      onSuccess: function(req){
		    jmaki.log(name + "/loadRootCategories/onSuccess: response= " + 
			      req.responseText);
		    rootCategories = eval("(" + req.responseText + ")");
	      },
	      onFailure: function(req) {
		    jmaki.log(name + "/loadRootCategories: onFailure");
		    var msg = "Http error. Status: " + req.status;
		    if(req.statusText){
			msg += " - " + req.statusText;
		    }
		    if(req.responseText){
			msg += ", Response: " + req.responseText;
		    }
		    rock.showErrorMsg(msg, $(uuid)); 
	      },	
	      onException: function(req, exception) {
		    jmaki.log(name + "/loadRootCategories: onException");
		    var msg = "Application exception: " + exception;
		    rock.showErrorMsg(msg, $(uuid)); 
	      }			     
	    }
        );
    }
	      
    /**
     * Given a category label, expand the category.
     * The category label must be one of keys of the root category map.
     */
    function expandCategory(categoryLabel){
	if(categoryLabel){
	    // ok, browseCategoryLabel specified
	    var categoryLabelLC = categoryLabel.toLowerCase();
	    if(categoryLabelLC.toLowerCase() == 'home' || 
	       categoryLabelLC.toLowerCase() == 'blended' ||
	       categoryLabelLC == 'all'){
		// this is the root
		// to ensure rootCategories is loaded, use Javascript's setInterval to execute a function after a delay
		var timeoutId = setInterval(function(){
		    if(rootCategories){
			clearInterval(timeoutId);	
			// update current browse category
			browseCategoryLabel = categoryLabel;
			// show root categories
			showRootCategories();
		    }
		    }, 50);	//setInterval

	    }else{
		// this is a level 1 category
		// to ensure rootCategories is loaded, use Javascript's setInterval to execute a function after a delay
		var timeoutId = setInterval(function(){
			if(rootCategories){
			    clearInterval(timeoutId);
			    // lookup the category
			    var cat = rootCategories[categoryLabel];
			    if(cat){
			      if(cat.nodeId){
				// update current browse category
				browseCategoryLabel = categoryLabel;
				// expand the node
				expand(cat.nodeId);
			      }else{
				rock.showErrorMsg("Category " + categoryLabel +
						  "'s node id cannnot be found.", $(uuid));
			      }
			    }else{
				rock.showErrorMsg("Category " + categoryLabel +
					" cannot be found in the root category list.", $(uuid));
			    }
			}
		    }, 50); //setInterval     		
	    }//if
	}//if
    }//function
	
   /**
    * Expand a node, given a BrowseNode's ID   	
    */
    function expand(nodeId) {
      jmaki.log(name + ': Expanding node ' + nodeId);      	
	      
      // publish event topicBeforeNodeExpanded
      var data = {
	  nodeId: nodeId,  // BrowseNode ID
	  category: browseCategoryLabel, // category
	  categoryMap: rootCategories,
	  service: service,
	  onSuccess: onBrowseNodeLookupCompleted,
	  onFailure: onBrowseNodeLookupFailed,
	  onException: onBrowseNodeLookupException
      };
      jmaki.publish(topicBeforeNodeExpanded, data);

      // do browseNodeSearch - BrowseNodeLookup (get subcategories)      			
      jmaki.log(name + "/expand: Calling rock.amazon.browseNodeLookup..."); 
      rock.showLoadingIcon($(uuid));
      // making ajax call
      rock.amazon.browseNodeLookup(data);
    }
    	
    function onBrowseNodeLookupCompleted(req) {   	
    	jmaki.log(name + '/onBrowseNodeLookupCompleted: ' + req.responseText);
	rock.hideLoadingIcon($(uuid));
    	
     	// convert responseText to json
        var response = eval("(" + req.responseText + ")");        
        
        if(response.errors && response.errors.length > 0){
            rock.amazon.Items.showErrors(response.errors, $(uuid));
        }else{
	    if(response.children){     		
		    // push the expanded node
		    var expandedNode = {nodeName:response.nodeName, nodeId: response.nodeId};
		    if(expandedNodes.length == 0 ||
			    expandedNode.nodeId != expandedNodes[expandedNodes.length-1].nodeId){
			    // push in the newly expanded node
			    //jmaki.log(name + ": push node " + expandedNode.nodeName);
			    expandedNodes[expandedNodes.length] = expandedNode;
		    }

		    // update current browseNodeId
		    browseNodeId = response.nodeId;

		    showNodes(response.nodeName, response.children);
	    }
        }
    }	
	    
      function onBrowseNodeLookupFailed(req) {
	  jmaki.log(name + ": onBrowseNodeLookupException");
	  rock.hideLoadingIcon($(uuid));
	  var msg = "Http error. Status: " + req.status;
	  if(req.statusText){
	      msg += " - " + req.statusText;
	  }
	  if(req.responseText){
	      msg += ", Response: " + req.responseText;
	  }
	  rock.showErrorMsg(msg, $(uuid)); 
      }

    function onBrowseNodeLookupException(req, exception) {
	jmaki.log(name + ": onBrowseNodeLookupException");
	rock.hideLoadingIcon($(uuid));
	var msg = "Application exception: " + exception; 
	rock.showErrorMsg(msg, $(uuid));
    }		         

    // subscribe to tab clicked event   	
    jmaki.subscribe(topicOnTabClicked, onTabClicked); 
   	             
    function onTabClicked(menu){
	jmaki.log(name + ": onTabClicked: received tab clicked evt.");
	var categoryLabel = menu.value;
	jmaki.log(name + ": onTabClicked: category label: " + categoryLabel);
	if(categoryLabel){
	    // show category
	    expandCategory(categoryLabel);
	}
    }

    function getNodeIdByCategoryLabel(categoryLabel){
	    var categoryLabelLC = categoryLabel.toLowerCase();
	if( categoryLabelLC == 'home' || 
	    categoryLabelLC.toLowerCase() == 'blended' ||
	    categoryLabelLC == 'all'){
	    categoryLabel = HOME_CATEGORY;
	}
	var nodeId = 1000;
	var cat = rootCategories[categoryLabel];
	if(cat){
	    nodeId = cat.nodeId;
	}

	return nodeId;
    }
   	
	/**
	 * Given a json object of categories, display it in the widget container.
	 */
	function showRootCategories(){        
	    // run browse node search
	    var nid = getNodeIdByCategoryLabel(browseCategoryLabel);
	    var data = {
	      	nodeId: nid, 
	      	category: browseCategoryLabel,
	      	categoryMap: rootCategories
	    };		      
	    jmaki.log(name + ': showRootCategories: executing node search. nodeId: ' + 
	          data.nodeId + ', category: ' + data.category);
	    rock.amazon.browseNodeSearch(data, $(targetId), true);

	    // convert categories json to array of nodes
	    var nodes = [];
	    var idx = 0;
	    for(label in rootCategories){
		    var node = {};		
		    node.nodeName = label;
		    node.nodeId = rootCategories[label].nodeId;
		    nodes[idx] = node;
		    //jmaki.log(name + ": showRootCategories: " + idx + ' added: ' + node.nodeName + ' ' + node.nodeId);
		    idx++;
	    }

	    showNodes(CATEGORORIES_LABEL, nodes);			      		
	}
		    
	function showNodes(expandedNodeName, nodes){
		var container = Builder.node('div', {className:'categoryContainer'});
		var header = Builder.node('div', {className:'categoryHeader'}, expandedNodeName);
		container.appendChild(header);
		
		// add back link
		if(expandedNodes.length > 0){
			var backLink = Builder.node('span', {className:'categoryBackLink'}, '<< go up');
			backLink.onclick = onBackLinkClicked;			
			container.appendChild(backLink);		
		}
		
		var list = Builder.node('ul', {className:'categoryList'});	
		container.appendChild(list);	
		for(var i=0; i<nodes.length; i++){		
			var nodeLabel = Builder.node('a', {nodeId:nodes[i].nodeId, nodeName:nodes[i].nodeName}, nodes[i].nodeName);			
			nodeLabel.onclick = onNodeClicked;			
			var item = Builder.node('li', [ nodeLabel ]);					
			list.appendChild(item);
		}
		
		rock.util.DomUtil.removeAllChildren($(uuid));
		$(uuid).appendChild(container);
	}
	
    /**
     * Event handler when the "back to parent category" is clicked.
     */	
    function onBackLinkClicked(){
      if(expandedNodes.length < 1){
      	return;
      }
      
      // pop out the last expanded node
      var popedOutNode = expandedNodes.pop();
      //rock.debug.msg("pop node " + popedOutNode.nodeName);
            
      if(expandedNodes.length == 0){
      	// show root categories
      	showRootCategories();
      }else{        	            
	      var parentNode = expandedNodes[expandedNodes.length-1];
	      //rock.debug.msg('back to node ' + parentNode.nodeName);
	      expand(parentNode.nodeId);
      }
    }
    	
    /**
     * Event handler when a browse node is clicked.
     */
    function onNodeClicked(){
      var nodeId = this.getAttribute('nodeId');	
	            
      expand(nodeId);
      return false;
    }				       	                       
}

