// Requires prototype.js
// Requires blindspot.com's utilities.js

/* Produces HTML elements:
 * DIV#<prefix_>browser_container
 * DIV#<prefix_>slot_wrapper
 * DIV#<prefix_>browser_container
 * DIV#<item_id(n)> .<prefix_>slot
 * DIV#<prefix_>browser_previous_link
 * DIV#<prefix_>browser_following_link
*/


// constructor
function Browser(dom_add_point, number_of_slots, browser_name) {
	this.dom_add_point    = dom_add_point;
	this.number_of_slots  = number_of_slots;
	this.prefix           = (browser_name != undefined) ? browser_name + "_": "";
	this.first_slot_index = false;
	this.item_array       = $A();
	this.item_hash        = $H();
	this.item_index_hash  = $H();
  this.is_initialized   = false;
  this.active_item      = null;
  
  this.opts = new Object();
}




/* A better way to create a browser,
 * using options hash for clarity
 */
Browser.instantiate = function(opts)
{
    
  var fpo = { 'number_of_slots': 5};  
  var opts = Object.extend(
    fpo,
    opts);
    
  var b = new Browser(opts.dom_add_point,
                     opts.number_of_slots,
                     opts.browser_name);
                     
  b.opts = opts;
  
  return b;
}





Browser.prototype.activate = function(selected_item) {
  if (this.active_item == selected_item) {
    // don't do anything
    return;
  }
	this.active_item = selected_item;
  this.item_array.each(
    function(item) {
    	item.changeState('off');
    });
    selected_item.changeState('on');
 		if (this.cookie_search_name) {
  		writeCookie(this.cookie_search_name, selected_item.id);
  	}
	 	this.trigger("activate", selected_item);
};



Browser.prototype.activateById = function(id) {
	this.active_item = this.item_hash[id];
	this.active_item.current_state = "on";
};


Browser.prototype.addBrowseLinkArrow = function(div, img_name, proc) {
	  div.className = "scroller_control";
    var inner_p = document.createElement("p");
    var img = document.createElement("img");
    img.src = '/images/button/' + img_name;
  	inner_p.appendChild(img);
    div.appendChild(inner_p);
    div.onclick = proc;
};



Browser.prototype.addBrowseLinkContent = function(div, text, proc) {
	  div.className = "scroller_control";
    var inner_p = document.createElement("p");
  	inner_p.appendChild(document.createTextNode(text));
    div.appendChild(inner_p);
    div.onclick = proc;
};


// to do: use options hash to set non-default graphics
Browser.prototype.addBrowsingLinks = function(div) {
	var containing_browser = this;

	var previous_link = document.createElement("div");
  previous_link.setAttribute('id', this.prefix + "browser_previous_link");
  if (this.first_slot_index > 0) {
  	this.addBrowseLinkArrow(previous_link,
  	                        (this.opts.back_button || "arrow_left.gif"),
  													function() {containing_browser.slotPrevious();});
  }
  div.insertBefore(previous_link, div.firstChild);
  
  var following_link = document.createElement("div");
  following_link.setAttribute('id', this.prefix + "browser_following_link");
  if (this.first_slot_index < this.item_array.length - this.number_of_slots) {
  	this.addBrowseLinkArrow(following_link, 
  	                          (this.opts.next_button || "arrow_right.gif"),
															function() {containing_browser.slotFollowing();});
  }
  div.appendChild(following_link);
};



Browser.prototype.addEventListener = function(target_element, event_name, func) {
	if (document.addEventListener) {
  	$(target_element).addEventListener(event_name, func, true);
	} else {
		$(target_element).attachEvent("on" + event_name, func);
	}
};



Browser.prototype.addItem = function(new_item) {
	var new_index = this.item_array.length;
	this.item_array[new_index] = new_item;
	this.item_hash[new_item.id] = new_item;
	this.item_index_hash[new_item.id] = new_index;
	new_item.browser = this; // to make events easier.
};

// to do: addItems(items_array)



Browser.prototype.addTrigger = function(trigger_name, func) {
	if (!(this.triggers)) {
		this.triggers = new Array();
	}
	this.triggers[trigger_name] = func;
}



Browser.prototype.cleanNode = function(node) {
	if ($(node).hasChildNodes()) {
		$A($(node).childNodes).each(
		  function(n) {
		  	$(node).removeChild(n);
		  }
		);
	}
}



Browser.prototype.initializeSlots = function() {

	var id = false;
	
	if (this.cookie_search_name) { // look for cookie that sets id
		requested_id = readCookie(this.cookie_search_name); // returns false if none found
		if (requested_id && this.item_hash[requested_id]) { 
		  id = requested_id;
			// this.activate(this.item_hash[requested_id]);
		}
	}
	if (this.param_search_name) { // look for URL param that sets id
		requested_id = readParam(this.param_search_name); // returns false if none found
		if (requested_id && this.item_hash[requested_id]) { 
		  id = requested_id;
			// this.activate(this.item_hash[requested_id]);
		}
	}
	if (this.requested_id) {
	  requested_id = this.requested_id;
	  if (this.item_hash[requested_id]) {
		  id = requested_id; 
			// this.activate(this.item_hash[requested_id]);
		}
	}
	if (id) {
	  this.activate(this.item_hash[id]);
	} 
	else if (!(this.active_item)) {
		this.activate(this.item_array[0]);
	}
	
  // SET MIN (OR LEFT-MOST) INDEX
  
  if (this.item_array.length < this.number_of_slots) {
  	this.number_of_slots = this.item_array.length;
  }
  
	if (!this.first_slot_index) { // range has not been set. Base it on active item
		
		active_index = this.item_index_hash[this.active_item.id];

		if (active_index < parseInt( (this.number_of_slots + 1) / 2 ) ) {
			this.first_slot_index = 0;
		} else {
			this.first_slot_index = Math.min(active_index - parseInt((this.number_of_slots) / 2), 
			                            this.item_array.length - this.number_of_slots);
		}
	} 
	else { // make sure this.first_slot_index isn't below 0 or above limit of array
		this.first_slot_index = Math.min( Math.max(this.first_slot_index, 0), 
		                             this.item_array.length - this.number_of_slots);
	}
	this.is_initialized = true;
}

Browser.prototype.isActiveItem = function(slotted_item) {
	return (this.active_item && slotted_item.id == this.active_item.id);
}


Browser.prototype.mouseout = function(item, ev) {
  if (!this.isActiveItem(item)) {
	 	if (item.checkForRollout(ev)) {
	 	  item.changeState('off');
	 	  this.trigger("deactivate", item);
	 	}
	 	
  }
};


Browser.prototype.preview = function(slotted_item) {
	this.deactivateOthers(slotted_item);
  if (!this.isActiveItem(slotted_item)) {
   	// slotted_item.setToPreview();
   	slotted_item.changeState('preview');
	 	this.trigger("preview", slotted_item);
  }
};



Browser.prototype.deactivateOthers = function(slotted_item) {
	this.slotted_items.each(function(item) {
		if (item != slotted_item && item.current_state == 'preview') {
			item.changeState('off');
			item.browser.trigger("deactivate", item);
		}
	});
}



Browser.prototype.setActiveItem = function(item) {
	this.item_array.each(function(it, index) {
		it.currentState = "off";
	});
	item.current_state = "on";
	this.active_item = this.item_hash[item.id];
}



Browser.prototype.showSlottedItems = function() {
	
	if (!(this.is_initialized)) { this.initializeSlots(); }
	
	dom_add_point = $(this.dom_add_point); // accepts either the element itself or its DOM ID
	var browser_container = document.createElement("div");
	browser_container.setAttribute("id", this.prefix + "browser_container");
	
	this.slotted_items = this.item_array.slice(this.first_slot_index, this.first_slot_index+this.number_of_slots);
	
	var slot_wrapper = document.createElement("div");
	slot_wrapper.setAttribute("id", this.prefix + "slot_wrapper");
	
	this.SLOTS_LOADED = 0;
	
	// var containing_browser = this;
  this.slotted_items.each(
    function(item) {
      var slot = document.createElement("div");
      slot.setAttribute('id', item.id);
     
      Element.addClassName(slot, item.browser.prefix+ "slot"); 
      Element.addClassName(slot, "slot");
      item.browser.addEventListener(slot, "mouseover", function() {item.browser.preview(item);} );
      item.browser.addEventListener(slot, "mouseout", function(ev) {item.browser.mouseout(item, ev);} );
      item.browser.addEventListener(slot, "click", function() {item.browser.activate(item);} );
      item.dom_element = slot;
      
      item.showInitialContent();
      item.applyState(item.current_state);
	    
      slot_wrapper.appendChild(slot);
    }
  );
  
  browser_container.appendChild(slot_wrapper);
  
  this.addBrowsingLinks(browser_container);
  
  // remove existing children at add point
  this.cleanNode(dom_add_point);
  
  dom_add_point.appendChild(browser_container);
  
  this.trigger("show_slots", this.item_array[0]);

}

Browser.prototype.slotPrevious = function() {  // or "rewind"
  this.first_slot_index = Math.max(0, this.first_slot_index - this.number_of_slots);
  this.showSlottedItems();
};

Browser.prototype.slotFollowing = function() {  // or "forward"
  this.first_slot_index = Math.max(0, Math.min(this.item_array.length - this.number_of_slots, this.first_slot_index + this.number_of_slots));
  this.showSlottedItems();
};


Browser.prototype.trigger = function(name, obj) {
	if (this.triggers && this.triggers[name]) {
		this.triggers[name](obj);
	}
};








function Item(id) {
	this.id = id;
	this.current_state = 'off';
	this.state_methods = Object();	
}


// Default (empty) methods for state changes.
// Override in object or extending class.

Item.prototype.showActiveContent = function() {};
Item.prototype.showDefaultContent = function() {};
Item.prototype.showPreviewContent = function() {};
Item.prototype.showInitialContent = function() {};



Item.prototype.applyState = function(state) {
  if (this.dom_element) {
  	if(state == "off" && this.showDefaultContent) { this.showDefaultContent(); }
  	else if (state=="preview" && this.showPreviewContent) {this.showPreviewContent(); }
  	else if (state=="on" && this.showActiveContent) {this.showActiveContent(); }
  	else { this.dom_element.innerHTML = this.state_methods[state](); }
	}
};



Item.prototype.changeState = function(state) {
	if (this.current_state != state) {
	  this.current_state = state;
		this.applyState(state);
	}
};



Item.prototype.checkForRollout = function(ev) {
	var slot = this.dom_element;
	if (slot.hasChildNodes()) {
    cursor = util.getCursorPosition(ev);
    if (Position.within(slot, cursor.x, cursor.y)) {
    	return false;
    } 
  }
  return true;
};


Item.prototype.initializeState = function(state) {
	this.init();
	this.current_state = state;
	this.applyState(state);
};

function imageLoaded() {}

Item.prototype.setStateMethod = function(state, config_array) {

	if (config_array['image']) {

	  var image_info    = config_array['image'];
	  var img_tag_html = '<img src="' + image_info["src"] + '" ' +
	                          'alt="' + image_info["alt"] + '" ';
		if (image_info["onload"]) { // JS to call
	  	img_tag_html += 'onload="' +image_info["onload"]+ '" ';
		}
	  img_tag_html +=             '/>';
	  
    this.state_methods[state] = function() {
    	return img_tag_html;
    };
	  
	} else if (config_array['text']) {
		// var id = this.id;
	  this.state_methods[state] = function() {
	  	// return document.createTextNode(config_array['text']);
	  	return '<div class="text_wrapper">' + config_array['text'] + '</div>';
	  };
	}
};

