/* vim: set tabstop=2 shiftwidth=2 foldmethod=marker: */
/**
 * 
 * VirtuaWave Common JavaScript on jQuery
 *
 * @author      Shogo Kawase <shogo@virtuawave.jp>
 * @copyright   VirtuaWave Inc.
 * @version     CVS: $Id: vw.js,v 1.1.2.2 2009/11/27 06:03:29 yuk Exp $
 *
 */


/** 初期化 **/
var vw = {
	_debug:        false,
	emptyFunction: function(){},
	
	/*** 外部スクリプト読み込み ***/
	include: function(path)
	{
		document.write('<script type="text/javascript" src="' + path + '"><\/script>');
	},
	/*** クラス/オブジェクトの継承 ***/
	extend: function()
	{
		var key, args = $A(arguments), dst = args.shift();
		for (var i = 0; i < args.length; ++i) {
			for (key in args[i]) {
				dst[key] = args[i][key];
			}
		}
		return dst;
	}
};


/** prototype.jsっぽい$関数 **/
$$ = function(element){
	return (typeof(element) == 'string') ? document.getElementById(element) : element;
};


/** prototype.jsっぽい$F関数 **/
$F = function(element){ return $(element).val(); };


/** prototype.jsっぽい$A関数 **/
$A = function(iterable){
	if (!iterable) return [];
	var length = iterable.length || 0, results = new Array(length);
	while (length--) {
		results[length] = iterable[length];
	}
	return results;
};


/** クラス **/
vw.jsClass = {
	/*** クラスの宣言 ***/
	create: function()
	{
		var parent = null;
		if (typeof(arguments[0]) == 'function') {
			parent = arguments.shift();
		}
		
		function klass() {
			this.initialize.apply(this, arguments);
		}
		
		if (parent) {
			var subclass = function(){};
			subclass.prototype = parent.prototype;
			klass.prototype = new subclass;
		}
		
		for (var i = 0; i < arguments.length; i++) {
			klass.prototype = vw.extend(klass.prototype, arguments[i]);
		}
		
		if (!klass.prototype.initialize) {
			klass.prototype.initialize = vw.emptyFunction;
		}
		
		klass.prototype.constructor = klass;
		
		return klass;
	}
};


/** ウィンドウ処理 **/
vw.window = {
	/*** スクロール位置 ***/
	scrollOffset: function()
	{
		return {
			x: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0,
			y: window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop  || 0
		};
	},
	/*** スクロール領域のサイズ ***/
	scrollSize: function()
	{
		return {
			x: document.documentElement.scrollWidth  || document.body.scrollWidth  || 0,
			y: document.documentElement.scrollHeight || document.body.scrollHeight || 0
		};
	},
	/*** クライアント領域のサイズ ***/
	clientSize: function()
	{
		return {
			x: document.documentElement.clientWidth  || document.body.clientWidth  || window.innerWidth  || 0,
			y: document.documentElement.clientHeight || document.body.clientHeight || window.innerHeight || 0
		};
	}
};


/** ブラウザ判別オブジェクト **/
vw.userAgent = {
	/** プロパティ */
	msie:      false,
	msie7:     false,
	opera:     false,
	safari:    false,
	konqueror: false,
	khtml:     false,
	gecko:     false,
	firefox:   false,
	mozilla:   false,
	
	/** ユーザーエージェント判別 */
	detect: function()
	{
		// USER_AGENT取得
		var ua = navigator.userAgent.toLowerCase();
		
		// USER_AGENT判別
		if (window.opera) {
			this.opera = true;
		} else if (ua.indexOf('msie') != -1) {
			if (window.XMLHttpRequest) {
				this.msie = this.msie7 = true;
			} else {
				this.msie = true;
			}
		} else if (ua.indexOf('applewebkit/') != -1) {
			this.khtml = this.safari = true;
		} else if (ua.indexOf('konqueror/') != -1) {
			this.khtml = this.konqueror = true;
		} else if (ua.indexOf('khtml/') != -1) {
			this.khtml = true;
		} else if (ua.indexOf('firefox/') != -1) {
			this.gecko = this.mozilla = this.firefox = true;
		} else if (ua.indexOf('gecko/') != -1) {
			this.gecko = this.mozilla = true;
		} else if (ua.indexOf('mozilla/') != -1) {
			this.mozilla = true;
		}
	},
	toString: function(){ return navigator.userAgent; }
};
vw.userAgent.detect();

/** Cookie操作オブジェクト **/
vw.cookie = {
	/** Cookieの読み込み */
	get: function(name)
	{
		var tmp1 = ' ' + document.cookie + ';';
		var tmp2 = '';
		var len  = tmp1.length;
		var x, y, z;
		x = y = z = 0;
		
		while (x < len) {
			y = tmp1.indexOf(';', x);
			tmp2 = tmp1.substring(x + 1, y);
			z = tmp2.indexOf('=');
			if (decodeURIComponent(tmp2.substring(0, z)) == name) {
				return decodeURIComponent(tmp2.substring(z + 1, y - x - 1));
			}
			x = y + 1;
		}
		return null;
	},
	/** Cookieの書き込み */
	set: function(name, data, expires, domain, path, secure)
	{
		var tmp = [encodeURIComponent(name) + '=' + encodeURIComponent(data)];
		if (typeof(expires) != 'undefined') {
			var now = new Date();
			expires = new Date(now.getTime() + (expires - 0));
			tmp.push('expires=' + expires.toGMTString());
		}
		if (typeof(domain) != 'undefined') {
			tmp.push('domain=' + domain);
		}
		if (typeof(path) != 'undefined') {
			tmp.push('path=' + path);
		}
		if (secure) {
			tmp.push('secure');
		}
		document.cookie = tmp.join(';') + ';';
		return null;
	},
	/** Cookieの削除 */
	remove: function(name, domain, path, secure)
	{
		var tmp = [encodeURIComponent(name) + '='];
		if (typeof(expires) != 'undefined') {
			var time    = new Date();
			var expires = new Date(time.getTime() - 8640000);
			tmp.push('expires=' + expires.toGMTString());
		}
		if (typeof(domain) != 'undefined') {
			tmp.push('domain=' + domain);
		}
		if (typeof(path) != 'undefined') {
			tmp.push('path=' + path);
		}
		if (secure) {
			tmp.push('secure');
		}
		document.cookie = tmp.join(';') + ';';
		return null;
	},
	/** Cookieのチェック */
	checkEnabled: function(secure)
	{
		if (typeof(navigator.cookieEnabled) != 'undefined') {
			return navigator.cookieEnabled;
		}
		var dummy = undefined;
		this.set('vw_cookie_check_enabled', 'check', 86400, dummy, dummy, secure);
		if (this.get('vw_cookie_check_enabled') != 'check') {
			return false;
		}
		this.remove('vw_cookie_check_enabled');
		return true;
	}
};

/** フォーム関連処理オブジェクト **/
vw.form = {
	// カーソルをエレメントの末尾に
	cursorMoveToEnd: function(obj)
	{
		if (obj.tagName == 'textarea' || obj.type == 'text') {
			if (obj.createTextRange) {
				var range = obj.createTextRange();
				range.move('character', obj.value.length);
				range.select();
			} else if (obj.setSelectionRange) {
				obj.setSelectionRange(obj.value.length, obj.value.length);
			}
		}
		obj.focus();
		return false;
	},
	// チェックボックスの一斉ON/OFF
	checkAll: function(checked, parent, selector)
	{
		$(parent).find(selector || ':checkbox').each(function(){ this.checked = checked; });
		return false;
	},
	// セレクト部品の内容の書き換え
	updateSelect: function(element, options, selected)
	{
		var s, o, x;
		$(element).each(function(){
			s = $(this).empty();
			$.each(options, function(k, v){
				o = new Option(v, k);
				o.selected = (v == selected);
				s.append(o);
			});
		});
	}
};

/** デバッグ情報出力関数 **/
vw.log = function(msg)
{
	if (!vw._debug) return;
	if (vw.userAgent.opera) {
		opera.postError(msg);
	} else if (window.console && window.console.log) {
		window.console.log(msg);
	} else {
		alert(msg);
	}
};

/** 各種ユーティリティ **/
vw.util = {
	/*** 配列値の最大値を求める ***/
	max: function(arry)
	{
		var result;
		$.each(arry, function(){
			if (result == undefined || this >= result) {
				result = this;
			}
		});
		return result;
	},
	/*** ページ上のオフセット位置を取得する ***/
	pageOffset: function(element)
	{
		var x = 0, y = 0;
		element = $(element)[0];
		do {
			x += element.offsetLeft || 0;
			y += element.offsetTop  || 0;
			element = element.offsetParent;
		} while (element);
		return {left:x, top:y};
	},
	/*** 数値を3桁区切りの文字列にして返す ***/
	numberFormat: function(input)
	{
		return isNaN(input) ? input : String(input).replace(/([0-9]+?)(?=(?:[0-9]{3})+$)/g, '$1,');
	}
};

/** 選択範囲処理クラス **/
vw.selection = vw.jsClass.create({
	start:  0,
	end:    0,
	text:   null,
	length: null,
	
	initialize: function(element)
	{
		element = $(element);
		if (!element || (element.type != 'textarea')) {
			return false;
		} else if (!isNaN(element.selectionEnd)) {
			this.start  = element.selectionStart;
			this.end    = element.selectionEnd;
		} else if (document.selection) {
			var dRange = document.selection.createRange();
			var tRange = document.body.createTextRange();
			tRange.moveToElementText(element);
			
			var eRange = tRange.duplicate();
			eRange.setEndPoint('EndToStart', dRange);
			var x = eRange.text.length;
			
			var eRange = tRange.duplicate();
			eRange.setEndPoint('EndToEnd', dRange);
			var y = eRange.text.length;
			
			while (element.value.charCodeAt(x) <= 0x10) {
				x += 1;
			}
			this.start = x;
			this.end   = y;
		}
		this.text   = element.value.substring(this.start, this.end);
		this.length = this.end - this.start;
	}
});
