<template>
	<div v-if="record !== null" class="card mb-3 shadow">
		<div class="card-header d-flex justify-content-between align-items-center">
			<span>{{record['~.01'] && record['~.01'].description || 'Document'}}</span>
			<a class="widget" @click="() => update(true)">✔</a>
		</div>
		<ul class="list-group list-group-flush">
			<li class="list-group-item"><DateTimePicker v-model="datetime" /></li>
			<li class="list-group-item">
				<div class="input-group">
					<span class="input-group-text">Subject</span>
					<input type="text" class="form-control" v-model="subject" />
				</div>
			</li>
			<li class="list-group-item"><textarea ref="textarea" class="form-control" v-model="text" @keydown.tab.exact.prevent="tab" @keydown.shift.tab.exact.prevent="untab" /></li>
		</ul>
		<div v-if="saved" class="card-footer" style="text-align: right;">Saved at {{saved.toLocaleString()}}</div>
	</div>
</template>

<style scoped>
	a.widget {
		cursor: default;
		text-decoration: none;
	}
	textarea {
		font-family: monospace;
		tab-size: 8;
	}
</style>

<script>
	import { debounce } from './util.mjs';
	import { strptime, strftime } from './fmdatetime.mjs';

	import DateTimePicker from './DateTimePicker.vue';

	function untab({ input, size=8, tab='\t', space=' ', join=true}={}) {
		input = input.split('\n');
		for(var i = input.length - 1; i >= 0; --i) input[i] = untab_line(input[i], size, tab, space);
		return join ? input.join('\n') : input;
	}
	function untab_line(line, size=8, tab='\t', space=' ') {
		var res = '', index = 0, offset = 0, next, count;
		while((next = line.indexOf(tab, index)) >= 0) {
			count = size - (next + offset)%size;
			res += line.substring(index, next) + Array(count + 1).join(space);
			offset += count - 1;
			index = next + 1;
		}
		return res + line.substring(index);
	}

	function retab({ input, size=8, tab='\t', space=' ' }={}) {
		var re_space = new RegExp(space.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '+', 'g');
		return input.replace(re_space, function(m) { return Array(Math.ceil(m.length/size) + 1).join(tab); });
	}

	function wrap({ input, width=80, cut=false, tabsize=8, tab='\t', space=' ', untab=false, join=true }={}) {
		var input = input.split('\n'), lines, res = [];
		if(untab) {
			for(var i = 0; i < input.length; ++i) {
				lines = wrap_line_split(untab_line(input[i], tabsize, tab, space), width, cut);
				for(var j = 0; j < lines.length; ++j) res.push(lines[j].replace(/(\s)\s+$/, '$1'));
			}
			return join ? res.join('\n') : res;
		} else {
			for(var i = 0; i < input.length; ++i) {
				lines = wrap_line_split(untab_line(input[i], tabsize, tab, tab), width, cut);	// replace tabs with placeholder tabs
				for(var j = 0; j < lines.length; ++j) res.push(lines[j].replace(/(\s)\s+$/, '$1'));
			}
			res = retab({ input: res.join('\n'), size: tabsize, tab, space: tab });	// collapse placeholder tabs
			return join ? res : res.split('\n');
		}
	}
	function wrap_line(str, width=80, cut=false, brk='\n') {
		if(!str) return str;
		return str.match(new RegExp('.{1,' + width + '}(\\s+|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s+|$)'), 'g')).join(brk);
	}
	function wrap_line_split(str, width=80, cut=false) {
		if(!str) return [str];
		return str.match(new RegExp('.{1,' + width + '}(\\s+|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s+|$)'), 'g'));
	}

	export default {
		components: {
			DateTimePicker
		},
		props: {
			client: Object,
			dfn: String,
			ien: String
		},
		emits: {
			'accept': null,
			'update': Object
		},
		data() {
			return {
				record: null,
				saved: null
			};
		},
		computed: {
			datetime: {
				get() { return this.record && this.record['~1301'] && this.record['~1301'].value; },
				set(value) { this.record['~1301'].value = strftime(strptime(value)); this.autosave(); }
			},
			subject: {
				get() { return this.record && this.record['~1701'] && this.record['~1701'].value; },
				set(value) { this.record['~1701'].value = this.record['~.07'].value = value; this.autosave(); }
			},
			text: {
				get() { return this.record && this.record.text; },
				set(value) { this.record.text = value; this.autosave(); }
			}
		},
		watch: {
			text() {
				this.resize();
			}
		},
		methods: {
			async tab(evt) {
				var target = event.target, value = target.value, start = target.selectionStart, end = target.selectionEnd;
				if(start == end) document.execCommand('insertText', false, '\t');
				else {
					start = target.selectionStart = value.lastIndexOf('\n', start - 1) + 1;
					end = target.selectionEnd = value.indexOf('\n', end); if(end < 0) end = value.length;
					var selection = value.substring(start, end);
					document.execCommand('insertText', false, selection.replace(/^/gm, '\t'));
					await this.$nextTick();
					target.selectionStart = start;
					target.selectionEnd = end + selection.split('\n').length;
				}
			},
			async untab(evt) {
				var target = event.target, value = target.value;
				var start = target.selectionStart = value.lastIndexOf('\n', target.selectionStart - 1) + 1;
				var end = target.selectionEnd = value.indexOf('\n', target.selectionEnd); if(end < 0) end = value.length;
				var selection = value.substring(start, end);
				document.execCommand('insertText', false, selection.replace(/^\t/gm, ''));
				await this.$nextTick();
				target.selectionStart = start;
				target.selectionEnd = end - (selection.match(/^\t/gm) || []).length;
			},
			async update(accept) {
				var res = this.record.reduce((acc, val) => (acc['"' + val.field + '"'] = val.value, acc), {});
				var text = wrap({input: this.text || '\x01', width: 80, cut: true, untab: false, join: false});
				for(var i = 0; i < text.length; ++i) res['"TEXT","' + (i + 1) + '","0"'] = text[i];
				this.$emit('update', res);
				if(await this.client.TIU_UPDATE_RECORD(this.ien, res, 0)) {
					await this.client.TIU_GET_RECORD_TEXT_FLUSH(this.ien);
					this.saved = new Date();
					if(accept) this.$emit('accept');
				}
			}
		},
		created() {
			this.resize = debounce(async function() {
				var textarea = this.$refs.textarea;
				textarea.style.height = 'auto';
				await this.$nextTick();
				textarea.style.height = textarea.scrollHeight + 4 + 'px';
			}, 50);
			this.autosave = debounce(this.update, 2000);
			this.$watch(
				() => (this.client, this.ien, {}),
				async function() {
					this.record = (this.client) && (this.ien) ? await this.client.TIU_LOAD_RECORD_FOR_EDIT(this.ien, '.01;.06;.07;1301;1204;1208;1701;1205;1405;2101;70201;70202') : [];
					this.resize();
				},
				{ immediate: true }
			);
		}
	};
</script>
