/**
 * @version    2.0.4, 2011-02-09 09:42:35
 * @copyright  Copyright (c) 2011, SOFTBANK MOBILE Corp.
 */

SBM = {
	version: '2.0.4',
	files:   {},
	base:    (function (el) {
		return (el.nodeName == 'SCRIPT')
			? el.src.replace(/[^\/]+$/, '')
			: arguments.callee(el.lastChild || el.previousSibling);
	})(document.body || document),
	
	/**
	 * @return  {string}
	 */
	toString: function () {
		return 'SBM ver.' + this.version + ' (c) SOFTBANK MOBILE Corp';
	},
	
	/**
	 * @param   {string}  ns
	 */
	use: function (ns) {
		var files = [];
		(function (name, module, helper) {
			if (name == 'tpl')
				files.push('hub/nav.js', 'plugin/history.js', 'plugin/tabs.js', 'tpl.js');
			if ((name == 'plugin') && (module == 'tabs'))
				files.push('plugin/history.js');
			
			if (module)
				switch (name) {
					case 'tpl':
						switch (module) {
							case 'product': files.push('plugin/enquete.js'); break;
						}
					default:
						files.push(name + '/' + module + '.js');
				}
			
			if (helper)
				files.push(ns.replace(/\./g, '/') + '.js');
		}).apply(null, ns.split('.'));
		
		this.each(files, function (file) {
			if (!this.files[file] && (this.files[file] = true)) {
				if (/^plugin/.test(file))
					this.plugin.ready();
				document.write('<script src="' + this.base + 'sbm2/' + file + '"></script>');
			}
		});
	},
	
	/**
	 * @param   {*}  obj
	 * @param   {*}  [key]
	 * @return  {boolean}
	 */
	has: function (obj, key) {
		if (arguments.length <= 1)
			return (typeof obj != 'undefined');
		
		if (this.is_str(obj))
			return (obj.indexOf(key) >= 0);
		
		if (this.is_enum(obj)) {
			for (var i = 0, ix = obj.length; i < ix; i++)
				if (obj[i] === key)
					return true;
			return false;
		}
		
		return obj.hasOwnProperty(key);
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_null: function (obj) {
		return (obj === null);
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_bool: function (obj) {
		return (typeof obj == 'boolean');
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_num: function (obj) {
		return (typeof obj == 'number');
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_str: function (obj) {
		return (typeof obj == 'string');
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_fn: function (obj) {
		return (typeof obj == 'function');
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_arr: function (obj) {
		return obj instanceof Array;
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_enum: function (obj) {
		return !!obj && this.has(obj.length);
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_node: function (obj) {
		return !!obj && this.has(obj.nodeType);
	},
	
	/**
	 * @param   {*}  obj
	 * @return  {boolean}
	 */
	is_obj: function (obj) {
		return (typeof obj == 'object')
			&& !this.is_null(obj)
			&& !this.is_enum(obj)
			&& !this.is_node(obj);
	},
	
	/**
	 * @param   {object}  obj
	 * @return  {array}
	 */
	arr: function (obj) {
		try {
			return Array.prototype.slice.call(obj);
		}
		catch (err) {
			var arr = [];
			for (var i = 0, ix = obj.length; i < ix; i++)
				arr.push(obj[i]);
			return arr;
		}
	},
	
	/**
	 * @param   {function}  fn
	 * @return  {function}
	 */
	bind: function (fn) {
		var self = this.self;
		return function () {
			return fn.apply(self, [this].concat(self.arr(arguments)));
		};
	},
	
	/**
	 * @param   {array|object}  items...
	 * @param   {function}      fn
	 */
	each: function () {
		var args = this.arr(arguments);
		var fn   = args.pop();
		for (var items, i = 0; items = args[i]; i++) {
			if (this.is_enum(items))
				for (var key = 0, len = items.length; key < len; key++) {
					var value = items[key];
					if (fn.apply(this.self, (fn.length >= 2) ? [key, value] : [value]) === false)
						return;
				}
			else
				for (var key in items) if (this.has(items, key)) {
					var value = items[key];
					if (fn.apply(this.self, (fn.length >= 2) ? [key, value] : [value]) === false)
						return;
				}
		}
	},
	
	/**
	 * @param   {array|object}  items...
	 * @param   {function}      fn
	 * @return  {array}
	 */
	map: function () {
		var items = [];
		var args  = this.arr(arguments);
		var fn    = args.pop();
		this.each.apply(this, args.concat([function (key, value) {
			var item = fn.apply(this, (fn.length >= 2) ? [key, value] : [value]);
			if (this.has(item))
				items.push(item);
		}]));
		
		return items;
	},
	
	/**
	 * @param   {object}  obj
	 * @return  {array}
	 */
	keys: function (obj) {
		return this.map(obj, function (key, value) {
			return key;
		});
	},
	
	/**
	 * @param   {array|object}  obj
	 * @param   {array|object}  [props]
	 * @return  {array|object}
	 */
	clone: function (obj, props) {
		var clone = this.is_enum(obj) ? [] : {};
		this.each(obj, function (key, prop) {
			clone[key] = prop;
		});
		this.each(props, function (key, prop) {
			clone[key] = prop;
		});
		
		return clone;
	},
	
	/**
	 * @param   {object}  props
	 * @return  {object}
	 */
	extend: function (props) {
		var c = function () {};
		c.prototype = this;
		
		var obj = new c;
		this.each(props, function (key, prop) {
			obj[key] = prop;
		});
		
		return obj;
	}
};

SBM.env = SBM.extend({
	/**
	 * @return  {object}
	 */
	init: function () {
		var ua  = navigator.userAgent;
		var loc = this.location();
		for (var key in loc) if (loc.hasOwnProperty(key)) {
			this[key] = loc[key];
		}
		
		this.os =
			/Windows/.test(ua) ? 'win' : (
			/Mac/.test(ua)     ? 'mac' : null);
		
		this.ua =
			/Opera/.test(ua)          ? 'op' : (
			/MSIE/.test(ua)           ? 'ie' : (
			/Firefox/.test(ua)        ? 'ff' : (
			/Chrome/.test(ua)         ? 'gc' : (
			/Android/.test(ua)        ? 'an' : (
			/Mobile.*Safari/.test(ua) ? 'ip' : (
			/Safari/i.test(ua)        ? 'sf' : null))))));
		
		delete this.init;
		return this;
	},
	
	/**
	 * @param   {string}  [url]
	 * @return  {object}
	 */
	location: function (url) {
		url = url || location.href;
		return (function (url, scheme, host, port, path, query, hash) {
			return {
				url:    url,
				scheme: scheme,
				host:   host,
				port:   port,
				path:   path,
				query:  query,
				hash:   hash,
				root:   scheme + '://' + host + (port ? ':' + port : '')
			};
		}).apply(null, url.match(
			/^(https?):\/\/([^\/:]+):?([^\/]*)([^\?#]+)\??([^#]*)#?(.*)$/
		));
	},
	
	/**
	 * @param   {date}    [date]
	 * @param   {string}  [format]
	 * @return  {object}
	 */
	localtime: function (date, format) {
		date = date || new Date;
		return {
			year:     date.getFullYear(),
			mon:      date.getMonth() + 1,
			day:      date.getDate(),
			hour:     date.getHours(),
			min:      date.getMinutes(),
			sec:      date.getSeconds(),
			time:     date.getTime(),
			format:   format,
			toString: function (format) {
				var self = this;
				if (format = format || self.format)
					return format.replace(/%([YmdHMS])/g, function (str, m) {
						switch (m) {
							case 'Y': return self.year;
							case 'm': return (self.mon  < 10 ? '0' : '') + self.mon;
							case 'd': return (self.day  < 10 ? '0' : '') + self.day;
							case 'H': return (self.hour < 10 ? '0' : '') + self.hour;
							case 'M': return (self.min  < 10 ? '0' : '') + self.min;
							case 'S': return (self.sec  < 10 ? '0' : '') + self.sec;
						}
					});
				return date.toGMTString();
			}
		};
	},
	
	/**
	 * @param   {string}  [format]
	 * @return  {object}
	 */
	servertime: function (format) {
		var servertime;
		this.ajax.load(this.base + 'sbm2/empty', { async: false, cache: false }, function (r) {
			servertime = this.env.localtime(new Date(r.get().getResponseHeader('Date')), format);
		});
		
		return servertime;
	},
	
	/**
	 * @param   {string}  name
	 * @param   {string}  [value]
	 * @param   {object}  [options]
	 * @return  {string|null}
	 */
	cookie: function (name, value, options) {
		if (arguments.length >= 2) {
			options = this.clone(options);
			if (!options.path)
				options.path = '/';
			
			if (this.is_null(value))
				options.days = -1;
			
			if (this.has(options.days)) {
				var exp = new Date;
				exp.setTime(exp.getTime() + (options.days * (1000 * 60 * 60 * 24)));
				options.expires = exp.toGMTString();
				delete options.days;
			}
			
			return document.cookie = name + '=' + value + this.map(options, function (key, value) {
				return '; ' + key + '=' + value;
			}).join('') + ';';
		}
		else {
			value = null;
			this.each(document.cookie.split(/;\s?/), function (cookie) {
				if (cookie.match(/^([^=]+)=(.*)$/) && RegExp.$1 == name) {
					value = RegExp.$2;
					return false;
				}
			});
			
			return value;
		}
	}
}.init());

SBM.ajax = SBM.extend({
	cache: {},
	
	/**
	 * @param   {string}    url
	 * @param   {object}    [options]
	 * @param   {function}  fn
	 * @return  {object}
	 */
	load: function () {
		var args    = this.arr(arguments);
		var url     = args.shift();
		var fn      = args.pop();
		var options = this.clone(args[0], { url: url });
		
		if (options.once && this.cache[url]) {
			fn.call(this.self, this.cache[url]);
			return this.cache[url].get();
		}
		
		options.beforeSend = this.bind(function (_this, xhr) {
			this.each(options.headers, function (key, header) {
				xhr.setRequestHeader(key, header);
			});
			if (options.onreadystatechange)
				xhr.onreadystatechange = this.bind(function (xhr) {
					options.onreadystatechange.call(this, xhr);
				});
		});
		
		options.complete = this.bind(function (_this, xhr) {
			if (xhr.status != 200)
				return fn.call(this, null, xhr);
			fn.call(this, this.ajax.cache[url] = this.ajax.response(xhr));
		});
		
		return jQuery.ajax(options);
	},
	
	/**
	 * @param   {string}    url
	 * @param   {object}    [options]
	 * @param   {function}  fn
	 * @param   {boolean}   [retry]
	 * @return  {object}
	 */
	loadJSP: function () {
		var args    = this.arr(arguments);
		var url     = args.shift();
		var fn      = args.pop();
		var retry   = !this.is_fn(fn) && (fn = args.pop());
		var options = args[0];
		
		return this.load(url, options, function (r, xhr) {
			var el = r && r.get('xml') ? r.get('xml').documentElement : null;
			if (this.is_null(el) || /^(html|parsererror)$/i.test(el.nodeName)) {
				this.env.cookie('BV_IDS', null, { path: '/scripts' });
				if (retry)
					fn.call(this, null, xhr);
				else
					this.ajax.loadJSP(url, options, fn, true);
			}
			else
				fn.call(this, r);
		});
	},
	
	/**
	 * @param   {xmlhttprequest}  xhr
	 * @return  {function}
	 */
	response: function (xhr) {
		var fn = function (selector) {
			return jQuery(selector, xhr.responseXML);
		};
		
		fn.get = this.bind(function (_this, response) {
			switch (response) {
				default:      return xhr;
				case 'xml':   return xhr.responseXML;
				case 'text':  return xhr.responseText;
				case 'json':  return eval('(' + xhr.responseText + ')');
				case 'array': return this.bind(function (_this, node) {
					var r = { text: jQuery(node).text() };
					this.each(node.attributes, function (attr) {
						r[attr.name] = node.getAttribute(attr.name);
					});
					
					var callee = this.bind(arguments.callee);
					var tags   = [];
					this.each(jQuery(node).children(), function (el) {
						var tag = el.nodeName;
						if (!r[tag] && tags.push(tag))
							r[tag] = [];
						r[tag].push(callee(el));
					});
					
					this.each(tags, function (tag) {
						if (r[tag].length == 1)
							this.each(r[tag][0], function (key, value) {
								r[tag][key] = value;
							});
					});
					
					return r;
				})(xhr.responseXML.lastChild);
			}
		});
		
		return fn;
	}
});

SBM.flash = SBM.extend({
	/**
	 * @return  {number|null}
	 */
	version: function () {
		if (window.ActiveXObject)
			for (var ver = 10; ver >= 3; ver--)
				try {
					new ActiveXObject('ShockwaveFlash.ShockwaveFlash.' + ver);
					return ver;
				}
				catch (err) {}
		else {
			var plugin = navigator.plugins['Shockwave Flash'];
			var mime   = navigator.mimeTypes['application/x-shockwave-flash'];
			if (plugin && mime && mime.enabledPlugin)
				return parseFloat(plugin.description.match(/Flash (\d+)/)[1]);
		}
		
		return null;
	},
	
	/**
	 * @param   {string}         swf
	 * @param   {number|string}  width
	 * @param   {number|string}  height
	 * @param   {object}         [options]
	 */
	create: function (swf, width, height, options) {
		options = this.clone(options);
		var fn  = this.bind(function (_this, html) {
			if (options.callback)
				options.callback.call(this, html);
			else if (options.target)
				jQuery(options.target).html(html);
			else
				document.write(html);
		});
		
		if (!this.version())
			return;
		
		options.id   = options.id   || swf.match(/([^\/]+)\.swf/)[1];
		options.menu = options.menu || 'false';
		
		var attrs  = { id: options.id, width: width, height: height };
		var params = {};
		this.each(options, function (key, value) {
			if (!/^(callback|id|target)$/.test(key))
				params[key] = value;
		});
		
		if (window.ActiveXObject) {
			attrs.classid = 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000';
			params.movie  = swf;
			fn('<object ' + this.map(attrs, function (key, value) {
				return key + '="' + value + '"';
			}).join(' ') + '>' + this.map(params, function (key, value) {
				return '<param name="' + key + '" value="' + value + '" />';
			}).join('') + '</object>');
		}
		else {
			attrs.src  = swf;
			attrs.type = 'application/x-shockwave-flash';
			fn('<embed ' + this.map(attrs, params, function (key, value) {
				return key + '="' + value + '"';
			}).join(' ') + '></embed>');
		}
	}
});

SBM.win = SBM.extend({
	options: {
		width:       800,
		height:      600,
		directories: 0,
		location:    1,
		menubar:     0,
		resizable:   1,
		scrollbars:  1,
		status:      1,
		toolbar:     0
	},
	
	/**
	 * @param   {object}  options
	 * @return  {object}
	 */
	setOptions: function (options) {
		return this.options = this.clone(this.options, options);
	},
	
	/**
	 * @param   {string}  url
	 * @param   {number}  [width]
	 * @param   {number}  [height]
	 * @param   {string}  [name]
	 * @param   {object}  [options]
	 * @param   {string}  [shorthand]
	 * @return  {boolean}
	 */
	open: function () {
		var args    = this.arr(arguments);
		var url     = args.shift();
		var name    = 'w' + new Date().getTime();
		var options = this.clone(this.options);
		
		for (var arg, i = 0; arg = args[i]; i++)
			switch (typeof arg) {
				case 'number':
					options.width  = arg;
					options.height = args[++i];
					break;
				case 'string':
					if (/^[\d,]+$/.test(arg)) {
						var shorthand = arg.split(',');
						this.each(this.keys(options).slice(2), function (key) {
							options[key] = shorthand.shift();
						});
					}
					else
						name = arg;
					break;
				case 'object':
					options = this.clone(options, arg);
					break;
			}
		
		window.open(url, name, this.map(options, function (key, value) {
			return key + '=' + value;
		}).join());
		
		return false;
	},
	
	/**
	 * @param   {string}  url
	 * @return  {boolean}
	 */
	opener: function (url) {
		if (window.opener && !window.opener.closed) {
			window.opener.location.href = url;
			window.opener.focus();
		}
		else
			window.open(url, 'w');
		
		return false;
	},
	
	/**
	 * @param   {string|element}  el
	 * @param   {function}        [fn]
	 * @return  {boolean}
	 */
	scroll: (function () {
		var timer;
		var clear = function () {
			if (timer)
				clearInterval(timer);
			timer = null;
		};
		
		return function (el, fn) {
			clear();
			
			var from = jQuery(window).scrollTop();
			var to   = jQuery(el).position().top;
			
			timer = setInterval(this.bind(function () {
				var move = Math.floor((from - to) / 3);
				if (!move && (from != to))
					move = (from > to) ? 1 : -1;
				from -= move;
				if (from == to) {
					if (fn)
						fn.call(this);
					clear();
				}
				else
					jQuery(window).scrollTop(from);
			}), 50);
			
			var d = document;
			if (this.env.ua == 'ff')
				d.body.addEventListener('DOMMouseScroll', function () {
					clear();
					this.removeEventListener('DOMMouseScroll', arguments.callee, false);
				}, false);
			else
				jQuery(d).one('mousewheel', clear);
			
			return false;
		};
	})()
});

SBM.hub = SBM.extend({
	shared: SBM.base.replace(/[^\/]+\/$/, ''),
	system: SBM.base.replace(/[^\/]+\/[^\/]+\/$/, 'system/')
});

SBM.plugin = SBM.extend({
	/**
	 */
	ready: function () {
		jQuery(this.bind(function (_this) {
			this.each(this.files, function (key, value) {
				var module;
				if (/^plugin\/(\w+)/.test(key) && (module = RegExp.$1))
					if (this.plugin[module].ready)
						this.plugin[module].ready();
			});
		}));
		this.ready = function () {};
	}
});

SBM.extra = SBM.extend({});
SBM.self  = SBM;
SBM.use('lib.jquery');
