/*
 * NAME
 *     SlideController スライダーコントロールオブジェクト
 *     $Id: SlideController.js,v 1.3 2007/07/04 08:41:28 ito Exp $
 * 
 * SYNOPSIS
 *     最も簡単な例
<html>
<head>
<script type="text/javascript" charset="UTF-8" src="./scripts/jswidget/jswidget.js"></script>
<script type="text/javascript" charset="UTF-8" src="./scripts/jswidget/SlideController.js"></script>
<script type="text/javascript">
// オブジェクト作成
var slider = new SlideController().setProperties({
    // 各種設定
    targetId   : "sliderControll",
    width  : 100,
    points : 11//,
}).addOnloadListener();
</script>
</head>
<body>
<div id="sliderControll"></div>
</body>
</html>
 * 現在、部品画像のサイズは固定です
 */

/*
 * SlideController オブジェクト
 * @version $Revision: 1.3 $
 * @author Katsuhiko Ito
 */
function SlideController(targetId, width, points) {
	this.targetId = targetId || 0;// 左位置（ピクセル）
	this.width    = width    || null;// 横幅（ピクセル）size length
	this.points   = points   || 3;// ノブが止まる位置の数
	this.offset = 0;  // ノブのオフセット位置

	this.enableDrag = true;
	this.useDefauleLane = true;//thinking...

	this.initialValue = null;
	// 値が変化したときに実行するファンクション
	this.onchange = null;
	// マウスアップ時に実行するファンクション
	this.onmouseup = null;
	// option
	this.offsetX      = 0;// レーン左位置（ピクセル）
	this.offsetY      = 0;// レーン上位置（ピクセル）
	this.images    = null;// 部品の画像名（連想配列）［省略時デフォルト画像］
	this.imageBase = null;// 部品画像までのパス［省略時自動取得］
	this.target    = null;
	this.direction = "lr";// lr:left-right | rl:right-left | tb:top-bottom | bt:bottom-top
}

/*
 * 設定
 */
SlideController.prototype.setProperties = function (props) {
	for (var key in props) {
		if (typeof this[key] != "undefined") this[key] = props[key];
		else throw new Error("invalid property [" + prop + "]");
	}
	return this;
};

/*
 * 初期化
 */
SlideController.prototype.initialize = function () {
	if (! this.target) this.target = document.getElementById(this.targetId);
	if (! this.width) this.width = this.target.style["width"].replace(/px/, "");
	if (! this.width) this.width = 100;
//console.log("initialize() "
//	+ "client:" + this.target.clientWidth + " | "
//	+ "offset:" + this.target.offsetWidth + " | "
//	+ "scroll:" + this.target.scrollWidth + " | "
//);
	this.resourcePath = SlideControllerImage.getBase();
	if (this.points < 3) this.points = 3;
	this.max = this.points - 1;
	this.width -= 11;// 11:ノブの幅
	if (this.width < 1) this.width = 1;
	if (! this.onmouseup) this.onmouseup = function () {};
	if (! this.onchange) this.onchange = function () {};
	if (! this.images) this.images = SlideControllerImage.getImages();
	if (! this.imageBase) this.imageBase = this.resourcePath;

	this.value  = 0;       // 値
	this.lastV  = 0;       // 直前の値
	this.unit   = this.width / this.max; // 1単位の幅
};
SlideController.createCount = 0;
/*
 * スライダー作成
 */
SlideController.prototype.create = function (value) {
	value = value || this.initialValue || 0;
	this.initialize();

	if (this.useDefauleLane) {
		this.lane = this.createLane();
		this.target.innerHTML = "";//クリーンアップ
	} else {
		this.lane = this.createDummyLane();
		this.initializeTarget();
//		this.lane.id = "asdfasdfasdf";
//		this.target.style.position = 'absolute';
	}

	this.knob = this.createKnob();
	this.setEventListener();
//	this.target.appendChild(this.lane);
//	this.lane.appendChild(this.knob);
//console.log("create:" + SlideController.createCount++)
//	document.body.appendChild(this.lane);
//	document.body.appendChild(this.knob);
	this.setValue(value);
};

/*
 * ピクセルを値に変換
 */
SlideController.prototype.toValue = function (px) {
	var value = parseInt((px - this.offset) / this.unit + 0.5);
	if (value < 0) value = 0;
	else if (value > this.max) value = this.max;
	return value;
};

/*
 * 値をピクセルに変換
 */
SlideController.prototype.toPixel = function (value) {
	if (value < 0) value = 0;
	else if (value > this.max) value = this.max;
	return parseInt(value * this.unit + 0.5) + this.offset;
};

/*
 * 値をセット
 */
SlideController.prototype.setValue = function (value) {
	if (value < 0) value = 0;
	else if (value > this.max) value = this.max;
	if (this.value == value) return false;
	this.lastV = this.value;
	this.value = value;
	var px = this.toPixel(value);
//	this.knob.offsetLeft = px;
	this.knob.style.left = px + "px";
	return true;
};

/*
 * 値をセット
 */
SlideController.prototype.addValue = function (delta) {
	if (!this.setValue(this.value + delta)) return;
	this.onchange(value);
	this.onmouseup(value);
};

/*
 * 値をセット
 */
SlideController.prototype.setValueExec = function (value) {
	if (!this.setValue(value)) return;
	this.onchange(value);
	this.onmouseup(value);
};

/*
 * イベント処理
 */
SlideController.prototype.setEventListener = function () {
	var slider = this;
	var knob = this.knob;
	var lane = this.lane;
	var isMouseDown = false;
	Event.observe(knob, 'mousedown', function (evt) {
		if (!slider.enableDrag) return;
		isMouseDown = true;
		SlideController.mouseDown(evt, knob, slider);
		Event.stop(evt);
	}, false);
	Event.observe(document, 'mousemove', function (evt) {
		if (!slider.enableDrag) return;
		if (isMouseDown) SlideController.mouseMove(evt, knob, slider);
		return false;
	}, false);
	Event.observe(document, 'mouseup', function (evt) {
		if (!slider.enableDrag) return;
		if (isMouseDown) {
			isMouseDown = false;
			SlideController.mouseUp(evt, knob, slider);
		}
	}, false);

	Event.observe(knob, 'click', function (evt) {
//		Event.stop(evt);
	}, false);
	Event.observe(lane, 'click', function (evt) {
		if (!slider.enableDrag) return;
		SlideController.laneMouseUp(evt, knob, slider);
		knob.knobMouseUp();
	}, false);
};

/*
 * マウスダウン
 */
SlideController.mouseDown = function (evt, target, slider) {
	target.eX = Event.pointerX(evt);//e ? e.pageX : event.clientX;
	target.posX = parseInt(target.style.left);
	target.knobMouseDown();
	slider.lastV = slider.value;
};

/*
 * マウスムーブ
 */
SlideController.mouseMove = function (evt, target, slider) {
	var eX = Event.pointerX(evt);//e ? e.pageX : event.clientX;
	var value = slider.toValue(target.posX + (eX - target.eX));
	if (value < 0) value = 0;
	else if (value > slider.max) value = slider.max;
	var px = slider.toPixel(value);
	if (slider.value != value) slider.onchange(value);
	slider.value = value;
	target.style.left = px + "px";
};

/*
 * マウスアップ
 */
SlideController.mouseUp = function (e, target, slider) {
	target.knobMouseUp();
	if (slider.lastV != slider.value)
		slider.onmouseup(slider.value);
};

/*
 * レーンクリック
 */
SlideController.laneMouseUp = function (evt, target, slider) {
	// ノブをクリックしていないのでtarget.eXに現在のノブの真ん中の位置を設定
	var offsetX = SlideController.getOffsetLeft(target.offsetParent);//parentNode -> offsetParent
	target.posX = parseInt(target.style.left);
	target.eX = offsetX + target.posX + 7;
	// マウスアップしたときのポインタの位置
	var eX = Event.pointerX(evt);//

	var value = slider.toValue(target.posX + (eX - target.eX));
//console.log(slider.style.width + ":" + slider.offsetWidth);
	if (slider.value == value) return false;
	if (slider.setValue(value)) {
		slider.onchange(value);
		slider.onmouseup(value);
	}
};

SlideController.getOffsetLeft = function (node) {
	var offsetLeft = 0;
	if (node.offsetParent) {
		for (var n = node; n != null; n = n.offsetParent) {
			var px = n.offsetLeft;
			if (! isNaN(px)) offsetLeft += px;
		}
	} else {
		offsetLeft = node.offsetLeft
	}
	return offsetLeft;
};

SlideController.getOffsetPosition = function (node) {
	var offsetLeft = 0;
	var offsetTop = 0;
	if (node.offsetParent) {
		for (var n = node; n; n = n.offsetParent) {
			var x = n.offsetLeft;
			var y = n.offsetTop;
			if (! isNaN(x)) offsetLeft += x;
			if (! isNaN(y)) offsetTop  += y;
		}
	} else {
		offsetLeft = node.offsetLeft;
		offsetTop  = node.offsetTop;
	}
	return [offsetLeft, offsetTop];
};

/*****************************************************************************/
/*
 * デフォルト画像
 */
function SlideControllerImage() {
	// 「このファイルがあるフォルダ/拡張子なしファイル名」を取得
	// このフォルダ以下にCSSや画像ファイルを置く
	var baseFolder = CommonBase.getBaseFolder() + "/SlideController";

	var imageBase = null;
	var images    = null;
	SlideControllerImage.getBase = function () {
		if (! imageBase)
			imageBase = baseFolder;
		return imageBase;
	};
	SlideControllerImage.getImages = function () {
		if (! images) {
			images = {// デフォルト画像
				laneLeft   : "slider_lane_l.gif",    // レーン左
				laneCenter : "slider_lane.gif",      // レーン中
				laneRight  : "slider_lane_r.gif",    // レーン右
				knobImage  : "slider_knob.gif",      // ノブ通常
				knobPoint  : "slider_knob_click.gif" // ノブクリック時
			};
		}
		return images;
	};
};
SlideControllerImage();

/*****************************************************************************/
/*
 * レーン作成
 */
SlideController.prototype.createLane = function () {
	var lane = document.createElement('div'); 
	lane.style.position = 'relative';
	this.layoutLane(lane, this.imageBase, this.images, this.width);
	return lane;
};

/*
 * ダミーレーン作成
 */
SlideController.prototype.createDummyLane = function () {
	var lane = document.createElement('div'); 
	lane.style.position = 'relative';//absolute
	lane.style.width = (this.width + 11) + "px";// 11:ノブの幅
	lane.style.height = 21 + "px";// 21:レーン画像の高さ
	lane.style.left = this.offsetX + "px";
	lane.style.top  = this.offsetY + "px";
	var img = document.createElement("img") 
	img.src = this.resourcePath + "/spacer.gif";
	img.style.width = (this.width + 11) + "px";// 11:ノブの幅
	img.style.height = 21 + "px";// 21:レーン画像の高さ
	lane.appendChild(img);
	return lane;
};

/*
 * レーン画像
 */
SlideController.prototype.layoutLane = function (lane, imageBase, images, width) {
	var imgL = document.createElement("img") 
	imgL.src = imageBase + "/" + images.laneLeft;
	var imgC = document.createElement("img") 
	imgC.src = imageBase + "/" + images.laneCenter;
	imgC.style.width  = width + "px";
	imgC.style.height = 21 + "px";// 21:レーン画像の高さ
	var imgR = document.createElement("img")
	imgR.src = imageBase + "/" + images.laneRight;
	lane.appendChild(imgL); 
	lane.appendChild(imgC);
	lane.appendChild(imgR);
	lane.style.width = (width + 11) + "px";// 11:ノブの幅
	lane.style.height = 21 + "px";// 21:レーン画像の高さ
//	div.imgC = imgC;
};

/*****************************************************************************/
/*
 * ノブ作成
 */
SlideController.prototype.createKnob = function () {
	var knob = document.createElement('div'); 
	knob.style.position = 'absolute';
//	knob.style.left = this.posX;
//	knob.style.top  = this.posY;
	knob.style.left = "0px";
	knob.style.top  = "0px";

	this.layoutKnob(knob, this.imageBase, this.images);
	knob.posX;
	knob.eX;
	return knob;
};

/*
 * ノブ画像
 */
SlideController.prototype.layoutKnob = function (knob, imageBase, images) {
	var knobImage = document.createElement("img")
	knobImage.src = imageBase + "/" + images.knobImage;
	var knobLatest = document.createElement("img")
	knobLatest.src = imageBase + "/" + images.knobLatest;
	var knobPoint = document.createElement("img")
	knobPoint.src = imageBase + "/" + images.knobPoint;

	var img  = document.createElement('img'); 
	img.src  = knobImage.src;
	knob.appendChild(img); 

	knob.knobMouseDown = function () {
		img.src = knobPoint.src;
	};
	knob.knobMouseUp   = function () {
		var imgSrc = "";
		if (knob.isLatest) imgSrc = knobLatest.src;
		else imgSrc = knobImage.src;
		if (img.src != imgSrc) img.src = imgSrc;
	};
	knob.img = img;
};

SlideController.prototype.addOnloadListener = function (value) {
	var that = this;
	var listener = function () {
		that.create(value);
		Event.stopObserving(window, 'load', listener, false);
	};
	Event.observe(window, 'load', listener, false);
	return this;
};

/*
Event.observe(target, 'event', function (evt) {
}, false);
	var eX  = Event.pointerX(evt);//evt.pageX || evt.clientX;
	var eY  = Event.pointerY(evt);//evt.pageY || evt.clientY;
*/

SlideController.prototype.initializeTarget = function () {
	if (! this.target.clientWidth) {
		var width = 0;
		for (var node = this.target.firstChild; node; node = node.nextSibling) {
//			if (node.nodeType != 3) continue;
			if (node.clientWidth  && width  < node.clientWidth)  width  = node.clientWidth;
		}
		this.target.style.width  = width  + "px";
	}
	if (! this.target.clientHeight) {
		var height = 0;
		for (var node = this.target.firstChild; node; node = node.nextSibling) {
//			if (node.nodeType != 3) continue;
			if (node.clientHeight && height < node.clientHeight) height = node.clientHeight;
		}
		this.target.style.height = height + "px";
	}
	for (var node = this.target.firstChild; node; node = node.nextSibling) {
		if (node.style) node.style.position = 'absolute';
	}
};

