Control 	= require './index'
Container 	= window.require 'spine/controller/container'

limit = (value, min, max) -> Math.max Math.min(max, parseInt value), min
$document = $ document
$body = $ 'body'
class Range extends Control
	@include Container
	template: 'core/views/range'
	className: 'control-range'

	elements:
		'.min-thumb' 			: 'minThumb'
		'.max-thumb' 			: 'maxThumb'
		'.min-value' 			: 'minInput'
		'.max-value' 			: 'maxInput'
		'.input-range-track'	: 'track'
		'.input-range-thumbs'	: 'thumbs'
		'.input-range'			: 'input' 

	events:
		'mousedown .input-range-thumb':'dragStart'
		'keydown .min-value,.max-value':'onKeyDown'
		'mousedown .input-range-track':'click'
		
	offsetX: 0
	isMouseDown: false

	position : 
		left: (pageX) ->
			limit pageX - @offsetX + 40, 0, @trackWidth() - @thumbsCss 'right'
		right: (pageX)->
			limit @width - (pageX - @offsetX), 0, @trackWidth() - @thumbsCss 'left'

	constructor: ->
		super
		@options.min	or= 0
		@options.max 	or= 1
		@options.unit 	or= ''

		#Bitwise shift
		@options.min 	>>= 0
		@options.max 	>>= 0

		$body.bind 'mouseenter', @mouseEnterBody

		@minInput.bind 'blur', @blurMin
		@maxInput.bind 'blur', @blurMax

		@el.find('input').bind 'focus', @focus
		@el.find('.min-value, .max-value').bind 'focus', @minMaxFocus

	mouseEnterBody: (e) =>
		return unless @isMouseDown
		@dragStop e if (e.buttons || e.which) isnt 1 

	thumbsCss: (prop, val, forceRead) ->
		@_ or= left: 0, right: 0
		return forceRead? and @thumbs.css(prop) or @_[prop] unless val?

		@thumbs.css prop, @_[prop] = val

	thumbsEase: (prop, val, _clbk = ->) ->
		props = {}
		props[prop] = @_[prop] = val
		@thumbs.animate props, 300, _clbk

	added: =>
		super
		@trackWidth()

		@

	trackWidth: =>
		return @_trackWidth if @width > 0

		@width = @track.width()
		@_trackWidth = @width - 2

	dragStart: (e) ->
		$target = $ e.target		
		@current = if $target.data('thumb') is 'max' then 'right' else 'left'
		@offsetX = @track.offset().left + (@eventX(e) - $target.offset().left)

		@_onMouseDown e

	click: (e) ->
		@current = if @eventX(e)-(@thumbs.offset().left + @thumbs.width()/2) <= 0 then 'left' else 'right'
		$target = @current is 'left' and @minThumb or @maxThumb
		@offsetX = @track.offset().left + 20

		@_onMouseDown e
		@thumbsEase @current, @position[@current].call(@, @eventX(e)), @liveUpdate

	_onMouseDown: (e) =>
		@isMouseDown = true
		e.preventDefault()
		e.stopPropagation()
		
		@input.focus()
		$body.addClass 'thumb-dragging'

		$document.bind('mousemove', @drag).one 'mouseup', @dragStop
		@liveUpdate()

	drag: (e) =>
		@thumbs.stop true, true
		@thumbsCss @current, @position[@current].call @, @eventX(e)
		@updateInputs()
		@timeout = setTimeout @liveUpdate, 100

	dragStop: =>
		$document.unbind 'mousemove', @drag
		clearTimeout @timeout

		$body.removeClass 'thumb-dragging'
		@liveUpdate()
		@isMouseDown = false

	update: (item, type, options={}) =>
		return if options.from and options.from is @
		val = item[@attribute] or {min:0,max:0}
		val.min= parseInt(val.min or 0)>>0
		val.max= parseInt(val.max or 0)>>0
		@minInpVal val.min
		@maxInpVal val.max

		@thumbsCss 'left', ((val.min-@options.min)/(@options.max-@options.min))*@trackWidth()
		@thumbsCss 'right', @trackWidth()-((val.max - @options.min)/(@options.max-@options.min))*@trackWidth()

	focus: =>
		@input.addClass 'active'

	updateInputs: =>
		min = (@thumbsCss('left')/@trackWidth()) * (@options.max - @options.min) + @options.min
		max = (@trackWidth()-@thumbsCss('right'))/(@trackWidth()) * (@options.max - @options.min) + @options.min

		@minInpVal Math.round min
		@maxInpVal Math.round Math.min max, @options.max
		{min, max}

	liveUpdate: =>
		@item.updateAttribute @attribute, @updateInputs(), {@attribute, from: @}

	minMaxFocus: (e) =>
		($input = $ e.target).val parseInt $input.val()

	blurMin: =>
		return @minInpVal @min if @min is val = parseInt @minInpVal null, true
		val = Math.min @options.max,val
		val = Math.max @options.min,val
		val = Math.min val, parseInt @maxInpVal()

		@thumbsCss 'left', ((val - @options.min)/(@options.max-@options.min))*@trackWidth()

		@minInpVal parseInt(val)
		@input.removeClass 'active'
		@liveUpdate()

	blurMax: =>
		return @maxInpVal @max if @max is val = parseInt @maxInpVal null, true
		val = Math.min @options.max,val
		val = Math.max @options.min,val
		val = Math.max val, parseInt @minInpVal()

		@thumbsCss 'right', @trackWidth() - ((val - @options.min)/(@options.max-@options.min))*@trackWidth()

		@maxInpVal parseInt(val)
		@input.removeClass 'active'
		@liveUpdate()

	minInpVal: (val, forceRead) =>
		return @minInput.val (@min = val) + @options.unit if val?
		if forceRead? and !isNaN(v=parseInt(@minInput.val())) then v else @min

	maxInpVal: (val, forceRead) =>
		return @maxInput.val (@max = val) + @options.unit if val?
		if forceRead? and !isNaN(v=parseInt(@maxInput.val())) then v else @max

	onKeyDown: (e) ->
		$(e.target).blur() if e.keyCode is 13

	eventX: (e) => e.pageX || e.clientX

	setWindow: ->
		super

		$document = $ @window.document
		$body = $document.find 'body'

module.exports = Range