( function($) {
	$.fn.square = function( opt ) {
		var _set = {
			target : "square",
			targetWrapName : ".sukaiSquareWrap",
			inner : ".inner",
			scaleSplit : "_",
			size : 150,
			space : 10,
			speed : 700,
			ease : "easeOutQuad"
		}
		if( opt ) $.extend( _set, opt );
		
		var _parent = $(this).css( {position:"relative"} );
		var _target_child = _parent.find( "*[class^="+_set.target+"]" ).wrap( $("<div>").addClass( _set.targetWrapName.replace(".", "") ) );
		var _target = $(_set.targetWrapName).css({position:"absolute"});
		var _resizeInter;
		var _prevWidth = _parent.outerWidth();
		setSize();
		setPosition( 0 );
		$(window).bind("resize",resizeStart);

		function resizeStart() {
			$(window).unbind("resize")
			_resizeInter = setInterval( resizeCheck, 500);
		}
		function resizeCheck() {
			_prevWidth = _parent.outerWidth();
			if( _prevWidth == _parent.outerWidth() ) {
			clearInterval( _resizeInter );
			$(window).bind("resize",resizeStart);
				resizeEnd();
			}
		}
		function resizeEnd() {
			setPosition( _set.speed );
		}
		
		function setSize() {
			_target.each( function(i) {
				var scale = getScale( $(this).children().attr("class") );
				var xsize = _set.size*scale.x+_set.space*(scale.x-1);
				var ysize = _set.size*scale.y+_set.space*(scale.y-1);

				$(this).css( { width:xsize, height:ysize } );
				
				var child = $(this).children();
				child.height( ysize ).data( "height", ysize );
				if( child.outerHeight() > ysize ) {
					var height = child.height()-( child.outerHeight()-ysize );
					child.height( height ).data( "height", height );
				}

				if( child.find(_set.inner).length > 0 ) {
					child.each( setScroll );
				}
			} );
		}
		
		function setPosition( sp ) {
			var matrix = new Array();
			var mpos = new Object();
			var tHeight = 0;
			_target.each( function(i) {
				mpos = blankMatrix( matrix );
				
				var scale = getScale( $(this).children().attr("class") );
				var sizex = _set.size*scale.x+_set.space*(scale.x-1);
				var sizey = _set.size*scale.y+_set.space*(scale.y-1);
				var flag = true;
				
				if( checkSize( mpos.x, scale ) ) {
					mpos.x = 0;
					mpos.y ++;
				}
				while( matrixCheck( matrix, mpos.x, mpos.y, scale ) ) {
					mpos.x++;
					if( checkSize( mpos.x, scale ) ) {
						mpos.x = 0;
						mpos.y ++;
					}
				}
				
				for( var x=0; x<scale.x; x++ ) {
					for( var y=0; y<scale.y; y++ ) {
						if( !matrix[mpos.x+x] ) matrix[mpos.x+x] = new Array();
						matrix[mpos.x+x][mpos.y+y] = true;
					}
				}
				
				var pos = {
					x:_set.space+_set.size*mpos.x+_set.space*mpos.x,
					y:_set.space+_set.size*mpos.y+_set.space*mpos.y
				};
				if( sp > 0 ) {
					goTween( $(this), { left:pos.x, top:pos.y }, sp );
				} else {
					$(this).css( { left:pos.x, top:pos.y } );
				}
				
				tHeight = pos.y+sizey+_set.space > tHeight ? pos.y+sizey+_set.space : tHeight;
			} );
			if( sp > 0 ) {
				goTween( _parent, { height:tHeight }, sp );
			} else {
				_parent.css( { height:tHeight } );
			}
		}
		
		function getScale( clsName ) {
			var tmp = clsName.split(" ");
			for( i in tmp ) {
				if( tmp[i].match( _set.scaleSplit ) ) {
					var xNum = tmp[i].split( _set.scaleSplit )[1];
					var yNum = tmp[i].split( _set.scaleSplit )[2];
					if( xNum ) {
						if( yNum )
							return {x:xNum, y:yNum};
						else
							return {x:xNum, y:xNum};
					}
				}
			}
			return { x:1, y:1 };
		}
		
		function matrixCheck( matrix, x, y, scale ) {
			if( !matrix ) {
				return false;
			}
			for( var i=0; i<scale.x; i++ ) {
				for( var j=0; j<scale.y; j++ ) {
					if( !matrix[x+i] ) {
						continue;
					} else if( !matrix[x+i][y+j] ) {
						continue;
					}
					return matrix[x+i][y+j];
 				}
			}
			return false;
		}
		function blankMatrix( matrix ) {
			var pos = {x:0, y:0};
			while( matrixCheck( matrix, pos.x, pos.y, 1 ) ) {
				pos.x++;
				if( checkSize( pos.x, 1 ) ) {
					pos.x = 0;
					pos.y++;
				}
			}
			return pos;
		}
		function checkSize( x, scale ) {
			var size = _set.size*scale.x+_set.space*(scale.x-1);
			var tsize = _set.size*x+_set.space*(x+2) + size;
			return tsize >= _parent.outerWidth();
		}
		
		function goTween( jObj, prop, sp ) {
			try{
				jObj.animate( prop, sp, _set.ease );
			} catch(e) {
				jObj.animate( prop, sp );
			}
		}
		return $(this);
	}

	function setScroll() {
		var _oHeight, _cHeight, _cDuration, _sHeight, _sDuration, _wStep, _wStepDur = 15, _bar;

		$(this).wrapInner($("<div>"));
		var _that = $(this).children().height( $(this).data( "height" ) );
		_that.wrapInner($("<div>"));
		var _thatInn = _that.children();

		if( !_mobile ) {			
			_that.css( {"overflow":"hidden", "position":"relative"} )
			_thatInn.css( {"position":"absolute", "left":0, "top":0, "padding-right":10} );
	
			_oHeight	= _that.height();
			_cHeight	= _thatInn.height();
			_cDuration	= _cHeight-_oHeight;
			_sHeight	= _oHeight*(_oHeight/_cHeight);
			_sDuration	= _oHeight-_sHeight;
			_wStep		= (_sDuration*_wStepDur) / _cDuration;
			
			_bar = $("<div>");
			
			if( _cDuration > 0 ) {
				_that.append( _bar );
				// マウスホイールエラー中
				_that.append( _bar ).mousewheel( mouseWheel );
				_bar.css( {
					"height"		:_sHeight,
					"width"			:3,
					"position"		:"absolute",
					"right"			:3,
					"top"			:0,
					"background"	:"#ccc",
					"border-radius"	:1,
					"cursor"		:"pointer"
				} ).fadeTo( 1, 0.5 ).mousedown( dragStart );
				$("body").mousemove( dragStep ).mouseup( dragEnd );
				rovEnabled();
			}
		} else {
			_that.css("-webkit-overflow-scrolling", "touch");
		}

		function rovEnabled() {
			_bar.hover( function() {
				$(this).stop(true, false).fadeTo( 200, 1 );
			}, function() {
				$(this).stop(true, false).fadeTo( 200, 0.5 );
			} ).trigger("mouseleave");
		}
		function rovDisabled() {
			_bar.trigger("mouseenter").unbind( "mouseenter" ).unbind( "mouseleave" );
		}
		
		var _draggable = false;
		var _sPos = 0;
		function dragStart( e ) {
			_draggable = true;
			_sPos = e.pageY;
			_bPos = pxToNum( _bar.css("top") );
			e.preventDefault();
			
			rovDisabled();
		}
		function dragStep(e) {
			if( _draggable ) {
				/* ScrollBar */
				gotoPos( _bPos+(e.pageY-_sPos) );
			}
			e.preventDefault();
		}
		function dragEnd(e) {
			_draggable = false;
			e.preventDefault();
			rovEnabled();
		}
		
		function gotoPos( toPos ) {
			var flag = true;
			if( toPos < 0 ) {
				toPos = 0;
				flag = false;
			} else if( toPos > _sDuration ) {
				toPos = _sDuration;
				flag = false;
			}
	
			/* ScrollBar */
			_bar.css("top", toPos );
			/* Contents */
			_thatInn.css("top", -_cDuration*(toPos/_sDuration) );
			
			return flag;
		}
		
		function mouseWheel(e, d) {
			var flag = true;
			if( d > 0 ) {
				flag = gotoPos( pxToNum( _bar.css("top") )-_wStep );
			} else if( d < 0 ) {
				flag = gotoPos( pxToNum( _bar.css("top") )+_wStep );
			}
			if( flag ) {
				e.preventDefault();
			}
		}
	}
	
	var _mobile = (function(){
		return /android|iphone|ipad|ipod/i.test(navigator.userAgent.toLowerCase());
	})();
	function pxToNum( px ) {
		return parseInt(px.replace("px", ""));
	}
} )(jQuery);
