(function($){

	function _initTimeline(target){
		var opts = $.data(target,"timeline").options;
		$(target).css("position","relative").css("border","1px solid").css("width",opts.cellPerDay+opts.formatCell).css("height",opts.height+opts.formatCell);
		$(target).addClass("timeline");

		_adjustTimeZone(target);
	}

	function _adjustTimeZone(target , newOpts){
		var opts = $.data(target,"timeline").options;
		$.extend(true,opts,newOpts || {});
		var spacHeight = 5;
		var sumTopLine = 0;
		for(var i = 0;opts.timezone && i<opts.timezone.length;i++){
			sumTopLine = _getInt(sumTopLine) + spacHeight;
			var mangeLine = {
				top:sumTopLine
			}
			var optsTZ = $.extend(true,{},$.fn.timeline.defaults,opts.timezone[i],mangeLine);
			_addTimeZone(target , optsTZ);
			sumTopLine = _getInt(sumTopLine) + _getInt(opts.height);
		}
		sumTopLine = _getInt(sumTopLine) + spacHeight;
		$(target).css("height",sumTopLine+opts.formatCell);
	}

	function _getInt(number){
		try{
			if(!isNaN(number)){
				return parseInt(number,10);
			}else{
				return 0;
			}
		}catch (err){
			return 0;
		}
	}

	function _getPxPerCell(target,isCal){
		var opts = $.data(target,"timezone").options;
		var recal = isCal || false;
		if(opts.pxPerCell && !recal){
			return opts.pxPerCell;
		}else{
			var px = _getInt(opts.cellPerDay)/(24*(60/_getInt(opts.timescale)));
			opts.pxPerCell = px;
			return px;
		}
	}

	function _addTimeZone(target , opts){
		var newTZ = $("<div></div>");
		$(newTZ).attr("keyGen",new Date().getTime());
		opts.id = (target.id || target.name) +"-"+ (opts.id || $(newTZ).attr("keyGen"));

		$(newTZ).attr("id",opts.id);

		$(target).append($(newTZ));

		if(opts.top){
			$(newTZ).css("top",opts.top);
		}

		_updateTimeZone($(newTZ) , opts);
	}

	function _updateTimeZone(target , opts){
		$(target).each(function(){
			$.data(this,"timezone",{
				options:opts
			});

			var px = _getPxPerCell(this);

			$(this).addClass("draggle").addClass("resize").addClass("object-move").addClass("write-time").addClass("timezone");

			$(this).css("width",px+opts.formatCell).css("height",opts.height+opts.formatCell).css("position","absolute").css("background-color",opts.color);

			_initTimeZone(this);
		});
	}

	function _initTimeZone(target){
		var opts = $.data(target,"timezone").options;
		if(opts.draggable){
			_setDraggle(target);
		}
		
		if(opts.resizable){
			_setResize(target);
		}

		if(_genCalendar(target)){
			_setZoneByTime(target);
		}

		if(opts.mapValue){
			_mapValue(target);
		}
	}

	function _setZoneByTime(target){
		var opts = $.data(target,"timezone").options;
		var px = _getPxPerCell(target);
		$(target).css("left",_CastTimeToPosition(opts.start_time , opts.timescale , px));
		if(opts.CalendarStart && opts.CalendarEnd){
			var w = opts.CalendarEnd.subForTime(opts.CalendarStart.getTimeStamp());
			$(target).css("width",_CastTimeToPosition(w , opts.timescale , px));
		}
	}

	function _CastTimeToPosition(time,scale,px){
		var min = _TimeToMin(time);
		return (_getInt(min)/_getInt(scale))*_getInt(px);
	}

	function _TimeToMin(time){
		var tmp = time.split(".");
		if(tmp.length == 2){
			var min = parseInt(tmp[1],10);
			min += parseInt(tmp[0],10)*60;
			return min;
		}
		return 0;
	}

	function _getCalendarStart(target , isCal){
		var opts = $.data(target,"timezone").options;
		var reCal = isCal || false;
		if(opts.CalendarStart && !reCal){
			return opts.CalendarStart;
		}else{
			if(_genCalendar(target)){
				return opts.CalendarStart;
			}
		}
	}

	function _getCalendarEnd(target , isCal){
		var opts = $.data(target,"timezone").options;
		var reCal = isCal || false;
		if(opts.CalendarEnd && !reCal){
			return opts.CalendarEnd;
		}else{
			if(_genCalendar(target)){
				return opts.CalendarEnd;
			}
		}
	}
	//mode = default = false ������ҧ������ҡ�͹ true ���ҧ��� position
	function _genCalendar(target , mode){
		try{
			var opts = $.data(target,"timezone").options;
			var width = target.offsetWidth;
			var left = target.offsetLeft;
			var end = _getInt(left)+_getInt(width);
			var px = _getPxPerCell(target);

			var sttime = opts.start_time;
			var entime = opts.end_time;
			if(mode){
				sttime = _CastPositionToTime(left , opts.timescale , px);
				entime = _CastPositionToTime(end , opts.timescale , px);
			}

			var st = opts.CalendarStart || new CscCalendar();
			st.setCscCalendar(opts.start_date || "");
			st.setCscTime(sttime);

			var en = opts.CalendarEnd || new CscCalendar();
			en.setCscCalendar(opts.end_date || "");
			en.setCscTime(entime);

			opts.CalendarStart = st;
			opts.CalendarEnd = en;

			opts.start_date = st.getDDMMYYYY();
			opts.start_time = st.getTime();

			opts.end_date = en.getDDMMYYYY();
			opts.end_time = en.getTime();

			if(opts.toolTip && typeof opts.toolTip == "function"){
				var title = opts.toolTip.call(target,opts);
				$(target).attr("title",title);
			}
			return true;
		}catch (err){
			return false;
		}
	}

	function _CastPositionToTime(position,scale,px){
		var data = (_getInt(position)/_getInt(px))*_getInt(scale);
		var hh = Math.floor(data/60);
		var mm = data%60;
		if(mm.toString().length == 1)mm = mm+"0";
		return hh+"."+mm;
	}

	function _setResize(target , newOpts){
		var opts = $.data(target,"timezone").options;
		var px = _getPxPerCell(target);
		var reSizeDefaults = {
			maxWidth: opts.cellPerDay,
			maxHeight: opts.height,
			minWidth: px,
			minHeight: 25,
			grid: [ px, px ],
			handles: "e, w",
			containment: "parent"
		}
		/* ���ҧ �¡�͡�� ��������������ö�� property �ҷѺ��*/
		var fnDefaults = {
			resize:function(event, ui ){
				var opts = $.data(ui.element[0],"timezone").options;
				if(opts.onResize){
					opts.onResize.call(ui.element[0],opts);
				}
				_genCalendar(ui.element[0],true);
				_mapValue(ui.element[0]);
			},
			stop:function(event, ui ){
				var opts = $.data(ui.element[0],"timezone").options;
				if(opts.onStopResize){
					opts.onStopResize.call(ui.element[0],opts);
				}
				_genCalendar(ui.element[0],true);
				_mapValue(ui.element[0]);
			}
		}
		var optResize = $.extend({}, reSizeDefaults , newOpts || {} , fnDefaults);

		$("#"+opts.id).resizable(optResize);
	}

	function _setDraggle(target , newOpts){
		var opts = $.data(target,"timezone").options;
		var px = _getPxPerCell(target);
		var dragDefaults = {
			containment: "parent",
			axis: "x",
			grid: [ px,px ]
		}

		var fnDefaults = {	
			drag:function(event, ui ){
				var opts = $.data(ui.helper[0],"timezone").options;
				if(opts.onDrag){
					opts.onDrag.call(ui.helper[0],opts);
				}
				_genCalendar(ui.helper[0],true);
				_mapValue(ui.helper[0]);
			}
		}

		var optDrag = $.extend({}, dragDefaults , newOpts || {} , fnDefaults);

		$("#"+opts.id).draggable(optDrag).bind({
			mouseover:function(){
				$(this).addClass("mouse-over");
			},
			mouseout:function(){
				$(this).removeClass("mouse-over");
			}
		});		
	}

	function _mapValue(target){
		var opts = $.data(target,"timezone").options;
		if(opts.mapValue){
			var m = opts.mapValue;
			for(var key in m){
				var selector = m[key];
				var data = opts[key] || "";
				if($(selector).is("div")){
					$(selector).text(data);
				}else if($(selector).is("input")){
					$(selector).val(data);
				}
			}
		}
	}

	function _getOptionTimeLine(target){
		var opts =	$.data(target,"timeline").options;
		var timezone = [];
		$(target).children(".timezone").each(function(){
			timezone.push($.data(this,"timezone").options);
		});
		$.extend(true,opts.timezone,timezone);
		return opts;
	}

	function _manageTimeZone(target , opts , isClear){
		var clear = isClear || true;
		if(clear){
			$(target).children(".timezone").each(function(){
				$(this).remove();
			});
			_adjustTimeZone(target[0] , opts);
		}
	}

	$.fn.timeline = function(opts1,opts2){
		if(typeof opts1=="string"){
			return $.fn.timeline.methods[opts1](this,opts2);
		}
		return this.each(function(){
			var data_opts = $.data(this,"timeline");
			var opts;
			if(data_opts){
				opts=$.extend(data_opts.options,opts1);
				data_opts.options=opts;
			}else{
				opts=$.extend(true,{},$.fn.timeline.defaults,opts1);
				$.data(this,"timeline",{
					options:opts
				});
			}
			_initTimeline(this);
		});
	}

	$.fn.timeline.methods = {
		getOption : function(target){
			return _getOptionTimeLine(target[0]);
		},

		updateTimeZone : function(target ,opts){
			return _manageTimeZone(target , opts);
		}
	}

	$.fn.timeline.defaults = {
		timescale:'15',
		color:'#CCC',
		height:'15',
		formatCell:'px',
		cellPerDay:'480',
		cellPerMin:'3',
		draggable:true,
		resizable:true
	}


})(jQuery);