###
 * 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.DataTable extends CUI.DataFieldInput

	@defaults:
		plus_button_tooltip: null
		minus_button_tooltip: null

	initOpts: ->
		super()

		# VALUE can have __class in each row, this sets a class on the tree node

		@addOpts
			fields:
				mandatory: true
				check: (v) ->
					CUI.util.isArray(v) or CUI.util.isFunction(v)
			new_rows:
				default: "edit"
				check: ["edit", "append", "remove_only", "none"]
			no_header:
				check: Boolean
			# autoSizeGridX:
			#	default: false
			#	check: Boolean
			rowMove:
				default: false
				check: Boolean
			# used in DataTableNode
			onBeforeRowRemove:
				check: Function
			# used in DataTableNode
			onRowRemove:
				check: Function
			onRowSelect:
				check: Function
			onRowDeselect:
				check: Function
			onNodeAdd:
				check: Function
			footer_right:
				check: (v) ->
					CUI.util.isContent(v)
			# own buttons
			buttons:
				mandatory: true
				default: []
				check: (v) ->
					CUI.util.isArray(v)
			chunk_size:
				default: 0
				mandatory: true
				check: (v) ->
					v >= 0
			padded:
				check: Boolean
				default: false

	readOpts: ->
		super()
		@__navi_prev = null
		@__navi_next = null
		@__offset = 0
		CUI.util.assert(not (@_chunk_size and @_rowMove), "new CUI.DataTable", "opts.chunk_size and opts.rowMove are mutually exclusive.", opts: @opts)
		@

	getFieldList: ->
		@__fieldList

	getFieldsByName: (name, found_fields = []) ->
		for field in @getFieldList()
			if field.getName() == name
				found_fields.push(field)

			field.getFieldsByName?(name, found_fields)
		found_fields

	debug: ->
		super()
		@listView?.debug()

	getFieldOpts: ->
		field_opts = []
		for _field in @getArrayFromOpt("fields")
			field = CUI.util.copyObject(_field, true)
			if not field.form
				field.form = {}

			if not CUI.util.isString(field.form.label)
				field.form.label = field.name

			field_opts.push(field)

		field_opts

	init: ->
		@__fieldList = []
		for field in @getFieldOpts()
			@__fieldList.push(CUI.DataField.new(field))
		@

	disable: ->
		super()
		@listView?.setInactive(true, null)
		@

	enable: ->
		super()
		@listView?.setInactive(false, null)
		@

	getDefaultValue: ->
		[]

	addRow: (data={}) ->
		@rows.push(data)
		# console.debug "creating new data node"
		new_node = new CUI.DataTableNode
			dataTable: @
			data: data
			dataRowIdx: @rows.length-1
			rows: @rows

		@_onNodeAdd?(node)
		@storeValue(CUI.util.copyObject(@rows, true))
		if @_chunk_size > 0
			@__offset = Math.floor((@rows.length-1) / @_chunk_size) * @_chunk_size
			@displayValue()
		else
			@listView.appendRow(new_node)
		# console.debug "data-changed on CUI.DataTable PLUS storing values:", CUI.util.dump(@rows)
		new_node

	updateButtons: ->
		if @listView.getSelectedRows().length == 0
			@minusButton.disable()
		else
			@minusButton.enable()

	getFooter: ->
		buttons = @_buttons.slice(0)
		if @_new_rows != "none"
			if @_new_rows != "remove_only"
				buttons.push
					icon: "plus"
					tooltip: text: CUI.DataTable.defaults.plus_button_tooltip
					group: "plus-minus"
					onClick: =>
						@addRow()


			@minusButton = new CUI.defaults.class.Button
				icon: "minus"
				group: "plus-minus"
				tooltip: text: CUI.DataTable.defaults.minus_button_tooltip
				disabled: true
				onClick: =>
					for row in @listView.getSelectedRows()
						row.remove()
					@storeValue(CUI.util.copyObject(@rows, true))
					@updateButtons()
					if @_chunk_size > 0
						@displayValue()
					return

			buttons.push(@minusButton)


		if @_chunk_size > 0

			buttons.push
				onConstruct: (btn) =>
					@__navi_prev = btn
				icon: "left"
				disabled: true
				group: "navi"
				onClick: =>
					@__offset = @__offset - @_chunk_size
					@displayValue()

			page_data = {}

			load_page = =>
				@__offset = (page_data.page - 1) * @_chunk_size
				@displayValue()

			@__navi_input = new CUI.NumberInput
				group: "navi"
				placeholder: "henk"
				data: page_data
				name: 'page'
				onBlur: (input) =>
					input.setValue(null)
				onDataChanged: =>
					CUI.scheduleCallback
						ms: 1000
						call: load_page
					return

			.start()

			buttons.push(@__navi_input)

			buttons.push
				onConstruct: (btn) =>
					@__navi_next = btn
				icon: "right"
				disabled: true
				group: "navi"
				onClick: =>
					@__offset = @__offset + @_chunk_size
					@displayValue()

		if buttons.length
			new CUI.Buttonbar(buttons: buttons)
		else
			return null

	render: ->
		super()
		cols = []
		colClasses = []
		maxis = []

		@headerRow = new CUI.ListViewHeaderRow()

		for f, idx in @__fieldList
			if f.getOpt("form")?.column == "maximize" or
				f instanceof CUI.DataTable
					maxis.push(idx)

		if maxis.length == 0
			# push the last as max
			maxis.push(@__fieldList.length-1)

		for f, idx in @__fieldList
			if CUI.util.idxInArray(idx, maxis) > -1
				cols.push("maximize")
			else if f.getOpt("form")?.column
				cols.push(f._form.column)
			else if f.isResizable()
				cols.push("auto")
			else
				cols.push("fixed")

			name = f.getName()
			label = f._form.label

			cls = []
			if name
				cls.push("cui-data-table-column-field-name-"+name)

			cls.push("cui-data-table-column-field-type-"+CUI.util.toDash(f.getElementClass()))
			if f._form?.rotate_90
				cls.push("cui-lv-td-rotate-90")

			colClasses.push(cls)

			@headerRow.addColumn new CUI.ListViewHeaderColumn
				rotate_90: f._form?.rotate_90
				label:
					text: label
					multiline: true

		@listView = new CUI.ListView
			class: "cui-lv--has-datafields"
			selectableRows: @_new_rows != "none"
			padded: @_padded
			onSelect: (ev, info) =>
				@_onRowSelect?(ev, info)
				@updateButtons()
			onDeselect: =>
				@_onRowDeselect?()
				@updateButtons()
			onRowMove: (display_from_i, display_to_i, after) =>
				fr = @listView.fixedRowsCount
				display_from_i = @__offset + display_from_i
				display_to_i = @__offset + display_to_i
				CUI.util.moveInArray(display_from_i-fr, display_to_i-fr, @rows, after)
				CUI.Events.trigger
					type: "data-changed"
					node: @listView

			cols: cols
			fixedRows: if @_no_header then 0 else 1
			footer_left: @getFooter()
			footer_right: @_footer_right
			fixedCols: if @_rowMove then 1 else 0
			colResize: if @_no_header then false else true
			colClasses: colClasses
			rowMove: @_rowMove
			# rowMovePlaceholder: not @_rowMove
			maximize: @_maximize
			maximize_horizontal: @_maximize_horizontal
			maximize_vertical: @_maximize_vertical

		if @isDisabled()
			@listView.setInactive(true, null)

		@replace(@listView.render())

		CUI.Events.listen
			type: "data-changed"
			node: @listView
			call: (ev, info) =>
				# we need hide our internal events and
				# present us as a whole
				ev.stopPropagation()
				# store value triggers a new data-changed
				# console.debug "data-changed on CUI.DataTable storing values:", CUI.util.dump(@rows)

				@storeValue(CUI.util.copyObject(@rows, true))
				return
		@

	displayValue: ->
		@listView.removeAllRows()
		if not @_no_header
			@listView.appendRow(@headerRow)

		@rows = CUI.util.copyObject(@getValue(), true)

		if @_chunk_size > 0
			len = @rows.length

			if @__offset >= len
				@__offset = Math.max(@__offset - @_chunk_size)

			page = Math.floor(@__offset / @_chunk_size)
			last_page = Math.ceil(len / @_chunk_size)-1

			sep = ' / '
			placeholder = (page+1)+sep+(last_page+1)

			@__navi_input.setMin(1)
			@__navi_input.setMax(last_page+1)
			@__navi_input.setValue(null)

			@__navi_input.setPlaceholder(placeholder)
			CUI.dom.setAttribute(@__navi_input.getElement(), "data-max-chars", (""+(last_page+1)).length*2+sep.length)

			if page > 0
				@__navi_prev.enable()
			else
				@__navi_prev.disable()

			if page < last_page
				@__navi_next.enable()
			else
				@__navi_next.disable()

		CUI.util.assert(CUI.util.isArray(@rows), "DataTable.displayValue", "\"value\" needs to be Array.", data: @getData(), value: @getValue())

		if @rows
			if @_chunk_size > 0
				rows_sliced = @rows.slice(@__offset, @__offset + @_chunk_size)
			else
				rows_sliced = @rows

			for row, idx in rows_sliced
				node = new CUI.DataTableNode
					dataTable: @
					data: row
					class: row.__class
					dataRowIdx: idx
					rows: @rows
					check_changed_data: @getInitValue()?[idx]
				@_onNodeAdd?(node)
				@listView.appendRow(node, true)
			@listView.appendDeferredRows()

		@
