###
 * coffeescript-ui - Coffeescript User Interface System (CUI)
 * Copyright (c) 2013 - 2016 Programmfabrik GmbH
 * MIT Licence
 * https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org
###

class CUI.StickyHeaderControl extends CUI.Element
	constructor: (opts) ->
		super(opts)

		# destroy old instances, in case we are re-initialized
		# on an .empty()ied element
		CUI.dom.data(@_element, "stickyHeaderControl")?.destroy()

		CUI.dom.data(@_element, "stickyHeaderControl", @)

		@__control = CUI.dom.div("cui-sticky-header-control")

		CUI.Events.listen
			instance: @
			type: "viewport-resize"
			node: @_element
			call: =>
				@__positionControl()

		@__positionControl()

		CUI.dom.append(@_element, @__control)

		@headers = []
		@newStickyHeaders = []
		@__hiddenHeaders = []
		@__positioned = false

		CUI.Events.listen
			node: @_element
			type: "scroll"
			instance: @
			call: (ev) =>
				# console.time "scroll"
				@position()
				# console.timeEnd "scroll"
				return

	initOpts: ->
		super()
		@addOpts
			element:
				mandatory: true
				check: (v) ->
					CUI.util.isElement(v)

	__positionControl: ->
		dim = CUI.dom.getDimensions(@_element)
		CUI.dom.setStyle @__control,
			left: dim.clientBoundingRect.left
			top: dim.clientBoundingRect.top

		CUI.dom.setDimension(@__control, "marginBoxWidth", dim.clientWidth)
		# console.error "__positionControl", @_element, @__control
		return

	isInDOM: ->
		@__control and CUI.dom.isInDOM(@__control)

	addStickyHeader: (stickyHeader) ->
		CUI.util.assert(not @__positioned or CUI.dom.isInDOM(@__control), "#{@__cls}.addStickyHeader", "StickyHeaderControl is not in DOM tree anymore. Cannot add a new CUI.StickyHeader.")

		CUI.util.assert(stickyHeader instanceof CUI.StickyHeader, "#{@__cls}.addStickyHeader", "Needs to be instance of StickyHeader but is #{CUI.util.getObjectClass(stickyHeader)}", stickyHeader: stickyHeader)
		@newStickyHeaders.push(stickyHeader)

	initNewStickyHeaders: ->
		measure_headers = []
		for nsh in @newStickyHeaders
			dom = nsh.DOM

			header =
				stickyHeader: nsh
				level: nsh.getLevel()
				node: dom.cloneNode(true)

			@headers.push(header)

			measure_headers.push(header)
			header.node.style.visiblity = "hidden"
			CUI.dom.prepend(@__control, header.node)

		@newStickyHeaders.splice(0)

		for header in measure_headers
			header.dimInControl = CUI.dom.getDimensions(header.node)
			@__control.removeChild(header.node)
			header.node.style.visiblity = ""
		@

	destroy: ->
		# console.warn "destroying sticky header control"
		CUI.dom.removeData(@_element, "stickyHeaderControl")
		CUI.Events.ignore
			instance: @

		CUI.dom.remove(@__control)
		@__headers = null
		@newStickyHeaders = null

	position: ->
		if not @isInDOM()
			return

		@__positioned = true
		@initNewStickyHeaders()

		scrollTop = @_element.scrollTop
		slots = []
		extraTop = 0
		for header, idx in @headers
			extraTop = 0
			for i in [0...header.level] by 1
				slot = slots[i]
				if slot == null
					break
				extraTop += slots[i].dimInControl.marginBoxHeight

			if header.stickyHeader.DOM.offsetTop < scrollTop + extraTop + header.dimInControl.marginTop
				slots[header.level] = header
				for i in [header.level+1...slots.length] by 1
					slots[i] = null
			else
				next_header = header
				top_space = 0
				for slot in slots
					if slot == null
						break
					top_space += slot.dimInControl.marginBoxHeight
				break

		if next_header
			cut = next_header.stickyHeader.DOM.offsetTop - scrollTop - top_space
			cut = cut - next_header.dimInControl.marginTop
			# console.debug cut, next_header.stickyHeader.DOM[0], next_header.stickyHeader.DOM[0].offsetTop, scrollTop, top_space
		else
			cut = 0

		for hiddenHeader in @__hiddenHeaders
			hiddenHeader.style.visibility = ""

		@__hiddenHeaders.splice(0)

		CUI.dom.empty(@__control)

		top = 0
		for slot, idx in slots
			if slot == null
				break

			CUI.dom.prepend(@__control, slot.node)

			if cut < 0 and slot.level == next_header.level
				top += cut

			hideHeader = slot.stickyHeader.DOM
			hideHeader.style.visibility = "hidden"

			@__hiddenHeaders.push(hideHeader)

			slot.node.style.top = top+"px"
			top += slot.dimInControl.marginBoxHeight

		CUI.dom.setStyle(@__control,
			height: top
		)

		@
