class ez5.PdfCreator extends CUI.Element

	# It is necessary to change the version when new methods or the templates could break
	# when having an older version.
	@VERSION = 2

	initOpts: ->
		super()
		@addOpts
			data:
				check: "PlainObject"
				default: {}
			idObjecttype:
				check: "Integer"
				mandatory: true
			idMask:
				check: "Integer"
		return @

	readOpts: ->
		super()

		# Get all node plugins for the pdf creator and skip the ones with duplicated name.
		if not ez5.PdfCreator.nodePlugins
			plugins = {}
			for plugin in ez5.PdfCreator.plugins.getPlugins()
				name = plugin.getName()
				if plugins[name]
					console.warn("PdfCreator :: Skipping plugin with duplicated name: #{name}")
					continue
				plugins[name] = plugin
			ez5.PdfCreator.nodePlugins = plugins

		# Fetch the print CSS, it will be used in the modal.
		# It is necessary to fetch the css so it is used with <style> within the pdf html.
		if not ez5.PdfCreator.fetchPrintCSSPromise
			ez5.PdfCreator.printSyles = ""
			pdfCreatorPlugin = ez5.pluginManager.getPlugin("pdf-creator")
			promiseCssPlugin = new CUI.XHR(
				url: ez5.getAbsoluteURL(pdfCreatorPlugin.getBaseURL() + pdfCreatorPlugin.getWebfrontend().print_css)
				responseType: "text"
			).start().done((styles) =>
				ez5.PdfCreator.printSyles += styles;
			)
			promiseCssPrint = new CUI.XHR(
				url: Start.getCSSUrl("print", ez5.session.getCSSMode())
				responseType: "text"
			).start().done((styles) =>
				ez5.PdfCreator.printSyles += styles;
			)

			ez5.PdfCreator.fetchPrintCSSPromise = CUI.whenAll(promiseCssPlugin, promiseCssPrint)

		# It is necessary to fetch the logo and convert it to Base64 so it is used in the header & footer.
		url = ez5.session.getConfigPicture("logo")?.versions?.original?.url
		if url and not ez5.PdfCreator.logoImage
			promiseCssPlugin = new CUI.XHR
				method: "GET"
				url: url
				responseType: "blob"
			promiseCssPlugin.start().done((blob) =>
				fileReader = new FileReader()
				fileReader.readAsDataURL(blob)
				fileReader.onloadend = ->
					ez5.PdfCreator.logoImage = fileReader.result # Base64 data.
					promiseCssPlugin.destroy()
			)

		if not @_data.templates
			@_data.templates = []
		return @

	# Render a list of pdf templates.
	renderList: ->
		header = ez5.PdfCreator.Template.Row.getHeader()
		cols = []
		for _ in header.getColumns()
			cols.push("auto")

		@__listView = new CUI.ListView
			rowMove: true
			cols: cols
			selectableRows: true
			fixedRows: 1
			onRowMove: (fromIdx, toIdx, after) =>
				# Display indices: row 0 is the fixed header, so shift onto the templates array.
				offset = @__listView.fixedRowsCount
				CUI.util.moveInArray(fromIdx - offset, toIdx - offset, @_data.templates, after)
				CUI.Events.trigger
					type: "data-changed"
					node: @__listView
			onSelect: =>
				minusButton.enable()
				editButton.enable()
				copyButton.enable()
			onDeselect: =>
				minusButton.disable()
				editButton.disable()
				copyButton.disable()

		@__listView.appendRow(header)

		plusButton = new CUI.Button
			icon: "plus"
			group: "plus-minus"
			onClick: =>
				@__showModal()
		minusButton = new CUI.Button
			icon: "minus"
			group: "plus-minus"
			disabled: true
			onClick: =>
				CUI.confirm(text: $$("pdf-creator.list.confirmation.remove-template|text")).done(=>
					selectedRow = @__getSelectedRow()
					data = selectedRow.getData()
					selectedRow.remove()
					CUI.util.removeFromArray(data, @_data.templates)
					CUI.Events.trigger
						type: "data-changed"
						node: @__listView

					minusButton.disable()
					editButton.disable()
					copyButton.disable()
				)
				return
		editButton = new CUI.Button
			icon: "edit"
			group: "edit-copy"
			disabled: true
			onClick: =>
				data = @__getSelectedRow().getData()
				@__showModal(data)
				return

		copyButton = new CUI.Button
			icon: "fa-files-o"
			group: "edit-copy"
			disabled: true
			onClick: =>
				copiedData = CUI.util.copyObject(@__getSelectedRow().getData(), true)
				@__addRow(copiedData)
				@_data.templates.push(copiedData)
				CUI.Events.trigger
					type: "data-changed"
					node: @__listView
				return

		downloadTemplatesButton = new LocaButton
			loca_key: "pdf-creator.list.download-templates.button"
			group: "download-upload"
			onClick: =>
				data =
					version: ez5.PdfCreator.VERSION
					templates: @_data.templates
				CUI.FileReader.save(ez5.session.getEasydbName() + "-pdf-templates.json",
					JSON.stringify(data, null, "    ")
				)

		uploadTemplatesButton = new CUI.FileUploadButton
			fileUpload: new CUI.FileReader
				onDone: (fileReaderResult) =>
					try
						data = JSON.parse(fileReaderResult.getResult())
						if data.version != ez5.PdfCreator.VERSION
							CUI.problem(text: $$("pdf-creator.list.upload-templates.wrong-version-error",
								file_version: data.version
								version: ez5.PdfCreator.VERSION
							))
							return
						if CUI.util.isEmpty(data.templates)
							CUI.problem(text: $$("pdf-creator.list.upload-templates.no-templates-error"))
							return

						for template in data.templates
							@__addRow(template)
							@_data.templates.push(template)

						CUI.Events.trigger
							type: "data-changed"
							node: @__listView
					catch
						CUI.problem(text: $$("pdf-creator.list.upload-templates.json-error"))
					return
			tooltip:
				text: $$("pdf-creator.list.upload-templates.button|tooltip")
			icon: $$("pdf-creator.list.upload-templates.button|icon")
			group: "download-upload"
			multiple: false

		pane = new CUI.SimplePane
			footer_left: new CUI.Buttonbar(buttons: [
				plusButton, minusButton,
				editButton, copyButton,
				downloadTemplatesButton, uploadTemplatesButton
			])
			content: @__listView

		for data in @_data.templates
			@__addRow(data)

		@__listView.render()
		return pane

	__addRow: (data) ->
		template = new ez5.PdfCreator.Template(data: data)
		row = new ez5.PdfCreator.Template.Row(template: template)
		@__listView.appendRow(row)
		return

	__getSelectedRow: ->
		return @__listView.getSelectedRows()[0]

	__showModal: (data) ->
		pdfCreatorModal = new ez5.PdfCreator.Modal
			idObjecttype: @_idObjecttype
			idMask: @_idMask
			data: data
			onSave: (dataSaved) =>
				if not @_data.templates.includes(dataSaved)
					@_data.templates.push(dataSaved)
					@__addRow(dataSaved)
				CUI.Events.trigger
					type: "data-changed"
					node: @__listView
				@__getSelectedRow()?.reload()
				return
		pdfCreatorModal.open()
		return

	getTemplateSelect: (selectOpts = {}) ->
		options = [
			text: $$("pdf-creator.select.option.not-selected|text")
			value: null
		]

		for data in @_data.templates
			template = new ez5.PdfCreator.Template(data: data)
			displayName = template.getDisplayName()
			options.push
				text: displayName
				value: data

		selectOpts.options = options

		defaultOpts =
			name: "pdf_creator_template"
		CUI.util.mergeMap(selectOpts, defaultOpts)

		return new CUI.Select(selectOpts)

	@print: (data, objects, idMask) ->
		pdfCreatorTemplate = new ez5.PdfCreator.Template(data: data)
		return pdfCreatorTemplate.print(objects, idMask)

	@getPlugin: (name) ->
		return @nodePlugins[name]

	# This is a method that can be used from outside to fetch all fields selected in a template.
	# It could fetch fields that are stored in the template but no longer exist in the mask.
	# Since it is used with a FieldsFormNode, non existing fields will not appear, and also will be ignored
	# when rendering the PDF.
	@getTemplateFields: (pdfTemplateData) ->
		pdfTemplateFields = {}
		topNodes = pdfTemplateData.documentData.children
		collectFields = (pdfNodes) ->
			for node in pdfNodes
				if node.data.dataFields
					selectedFields = ez5.PdfCreator.Node.Field.getSelectedFields(node.data)
					for fieldName, fieldValue of selectedFields
						pdfTemplateFields[fieldName] = fieldValue
						pdfTemplateFields[fieldName].display_name = ez5.loca.getBestFrontendValue(fieldValue.label)
				if node.children
					collectFields(node.children)
			return
		collectFields(topNodes)
		return pdfTemplateFields
