/* -------------------------------------------------------------------------- */
/** 
 *    @fileoverview
 *       Image Swap / Rollover Controll
 *
 *    @version rev010.2006-04-06
 *    @requires common.js
 */
/* -------------------------------------------------------------------------- */


/* -------------------- Settings for BARolloverAutoSetup -------------------- */

var BAROLLOVER_AUTOSETUP_ENABLED      = true;
var BAROLLOVER_AUTOSETUP_TARGET_CNAME = 'rollover';
var BAROLLOVER_AUTOSETUP_EXCEPT_CNAME = 'norollover';
var BAROLLOVER_AUTOSETUP_STATUS_SET   = { 'normal' : 'n', 'stay' : 's', 'hover' : 'o' };



/* -------------------- Constructor : BARolloverImage() -------------------- */
/**
 * provide image rollover / image src switcher.
 * this is usually used as unit instance of BARolloverTarget
 * @class single image rollover
 * @constructor
 * @see BARolloverTarget
 * @param {BAElement} node         image element node (img/input type="image") (required)
 * @param {Object}    statusSet    associative array of status and it's suffix sign (required)
 */
function BARolloverImage(node, statusSet) {
	/** image element node.
	    @type BAElement @const */
	this.node      = node;
	/** associative array of pairs of status and it's suffix sign.
	    @type Object @private */
	this.statusSet = statusSet;
	/** current rollover status.
	    @type String */
	this.status    = 'default';
	/** RegExp expression of accept image suffixes.
	    @type RegExp @const @private */
	this.suffixPtn = /\.(jpe?g|gif|png)$/i;
	/** associative array of pairs of status and it's image (Image object).
	    @type Object @private */
	this.images   = {};

	this.init();
}

BARolloverImage.prototype = {
	/** 
	 * initialize, setup nodes.
	 * @private
	 */
	init : function () {
		var statusPtn = '';
		for (var i in this.statusSet) {
			statusPtn += this.statusSet[i];
		}
		statusPtn = new RegExp('_([' + statusPtn + '])$');

		var src     = this.node.getAttributeBA('src');
		var fSuffix = (src && src.match(this.suffixPtn)) ? src.match    (this.suffixPtn    )[0] : null;
		var fName   = (fSuffix)                          ? src.replace  (this.suffixPtn, '')    : null;
		var fStatus = (fName && fName.match(statusPtn))  ? fName.match  (statusPtn         )[1] : null;
		var fRemain = (fStatus)                          ? fName.replace(statusPtn     , '')    : null;

		if (fRemain && fStatus && fSuffix) {
			this.statusSet['default'] = fStatus;
			for (var status in this.statusSet) {
				this.images[status] = BAPreloadImage(fRemain + '_' + this.statusSet[status] + fSuffix);
				if (this.statusSet[status] == fStatus && status != 'default') {
					this.status = status;
				}
			}
		}
	},
	
	/** 
	 * set image status (switch image src by binded status name)
	 * @param {String} status    status text (required)
	 */
	setStatus : function (status) {
		this.status = status;
		if (this.images[status]) {
			this.node.setAttributeBA('src', this.images[status].src);
		}
	}
}



/* -------------------- Constructor : BARolloverTarget() -------------------- */
/**
 * provide image rollover. (this can apply to any elements, not only img element!)
 * @class practical image rollover
 * @constructor
 * @see BARolloverImage
 * @param {BAElement} node            top-level element node of rollover behavior      (required)
 * @param {Object}    statusSet       associative array of status and it's suffix sign (required)
 * @param {String}    exceptCName     className for the image that is not expected to rollover
 */
function BARolloverTarget(node, statusSet, exceptCName) {
	/** top-level element node of rollover behavior.
	    @type BAElement @const */
	this.node        = node;
	/** associative array of pairs of status and it's suffix sign.
	    @type Object @private */
	this.statusSet   = statusSet;
	/** current rollover status.
	    @type String */
	this.status      = 'default';
	/** prefix for 'pseudo className' added according to status.
	    @type String @const @private */
	this.cNamePrefix = 'pseudo-';
	/** className for the image that is not expected to rollover
	    @type String @const @private */
	this.exceptCName = exceptCName;

	this.init();
}

BARolloverTarget.prototype = {
	/** 
	 * initialize, setup nodes.
	 * @private
	 */
	init : function () {
		this.images = [];
		this.node.__BARolloverTarget__ = this;

		if (this.nodeValidate(this.node)) {
			this.images.push(new BARolloverImage(this.node, this.statusSet));
		} else {
			var nodes = BAConcatNodeList(this.node.getElementsByTagNameBA('img'), this.node.getElementsByTagNameBA('input'));
			for (var i = 0, n = nodes.length; i < n; i++) {
				if (this.nodeValidate(nodes[i])) {
					this.images.push(new BARolloverImage(nodes[i], this.statusSet));
				}
			}
		}
	},

	/** 
	 * check node, node is rollover targetted image or not.
	 * @param {BAElement} node    node to check
	 * @return true when node is rollover targetted image
	 * @private
	 * @type Boolean
	 */
	nodeValidate : function(node) {
		if (!node || !node.nodeName) {
			return false;
		} else if (!node.nodeName.match(/^(img|input)$/i)) {
			return false
		} else if (node.nodeName.match(/^input$/i) && !node.getAttributeBA('type').match(/^image$/i)) {
			return false
		} else if (this.exceptCName && node.hasClassNameBA(this.exceptCName)) {
			return false
		} else {
			return true;
		}
	},

	/** 
	 * set rollover status, descendant images of 'this.node' are rollover at once!
	 * @param {String} status    status text (required)
	 */
	setStatus : function(status) {
		this.status = status;
		for (var i = 0, n = this.images.length; i < n; i++) {
			this.images[i].setStatus(status);
		}
		for (var i in this.statusSet) {
			this.node.removeClassNameBA(this.cNamePrefix + i);
		}
		if (this.statusSet[status]) {
			this.node.appendClassNameBA(this.cNamePrefix + status);
		}
	}
};



/* -------------------- Function : BARolloverAutoSetup() -------------------- */
/**
 * auto setup event handlers for BARolloverTarget.
 * @see BARolloverTarget
 * @param {BAElement} baseNode    top-level element node to apply setup (required)
 */
function BARolloverAutoSetup(baseNode) {
	if (BAROLLOVER_AUTOSETUP_ENABLED) {
		if (!baseNode || baseNode.nodeType != 1) {
			baseNode = document;
		}
		var nodes = baseNode.getElementsByClassNameBA(BAROLLOVER_AUTOSETUP_TARGET_CNAME);
		for (var i = 0, n = nodes.length; i < n; i++) {
			if (!nodes[i].__BARolloverTarget__) {
				var node = nodes[i];
				var target = new BARolloverTarget(node, BAROLLOVER_AUTOSETUP_STATUS_SET, BAROLLOVER_AUTOSETUP_EXCEPT_CNAME);
				node.addEventListenerBA('mouseover', function (e) {
					e.currentTarget.__BARolloverTarget__.setStatus('hover');
				});
				node.addEventListenerBA('mouseout',  function (e) {
					e.currentTarget.__BARolloverTarget__.setStatus('default');
				});
			}
		}
	}
}





/* -------------------- Main : register start-up -------------------- */

if (typeof BA == 'object' && BA.ua.DOMok) {
	BAAddOnload(BARolloverAutoSetup);
}
