<script lang="ts">
import {defineComponent, PropType} from 'vue';
import LeafTile from './LeafTile.vue';
import NonLeafTile from './NonLeafTile.vue';
import {LayoutNode} from '../layout';
import type {LayoutOptions} from '../layout';

// Component holds a tree-node structure representing a tile or tile-group to be rendered
export default defineComponent({
	props: {
		layoutNode: {type: Object as PropType<LayoutNode>, required: true},
		lytOpts: {type: Object as PropType<LayoutOptions>, required: true},
		uiOpts: {type: Object, required: true},
		nonAbsPos: {type: Boolean, default: false}, // Don't use absolute positioning (only applies for leaf nodes)
	},
	data(){
		return {
			clickHoldTimer: 0, // Used to recognise a click-and-hold event
			highlight: false,
			inTransition: false,
		};
	},
	computed: {
		isLeaf(){
			return this.layoutNode.children.length == 0;
		},
		isExpandable(){
			return this.layoutNode.tolNode.children.length > this.layoutNode.children.length;
		},
		collapseFailFlag(){
			return this.layoutNode.collapseFailFlag;
		},
		expandFailFlag(){
			return this.layoutNode.expandFailFlag;
		},
	},
	watch: {
		expandFailFlag(newVal){
			this.triggerAnimation('animate-expand-shrink');
		},
		collapseFailFlag(newVal){
			this.triggerAnimation('animate-shrink-expand');
		},
	},
	methods: {
		// Click handling
		onMouseDown(){
			this.highlight = false;
			clearTimeout(this.clickHoldTimer);
			this.clickHoldTimer = setTimeout(() => {
				this.clickHoldTimer = 0;
				this.onClickHold();
			}, this.uiOpts.clickHoldDuration);
		},
		onMouseUp(){
			if (this.clickHoldTimer > 0){
				clearTimeout(this.clickHoldTimer);
				this.clickHoldTimer = 0;
				this.onClick();
			}
		},
		onClick(){
			if (this.isLeaf && !this.isExpandable){
				console.log('Ignored click on non-expandable node');
				return;
			}
			this.prepForTransition();
			if (this.isLeaf){
				this.$emit('leaf-clicked', this.layoutNode);
			} else {
				this.$emit('header-clicked', this.layoutNode);
			}
		},
		onClickHold(){
			if (this.isLeaf && !this.isExpandable){
				console.log('Ignored click-hold on non-expandable node');
				return;
			}
			this.prepForTransition();
			if (this.isLeaf){
				this.$emit('leaf-click-held', this.layoutNode);
			} else {
				this.$emit('header-click-held', this.layoutNode);
			}
		},
		prepForTransition(){
			this.inTransition = true;
			setTimeout(() => {this.inTransition = false}, this.uiOpts.transitionDuration);
		},
		// For coloured outlines on hover
		onMouseEnter(evt: Event){
			if (!this.isLeaf || this.isExpandable){
				this.highlight = true;
			}
		},
		onMouseLeave(evt: Event){
			if (!this.isLeaf || this.isExpandable){
				this.highlight = false;
			}
		},
		// Child event propagation
		onInnerLeafClicked(data: LayoutNode){
			this.$emit('leaf-clicked', data);
		},
		onInnerHeaderClicked(data: LayoutNode){
			this.$emit('header-clicked', data);
		},
		onInnerLeafClickHeld(data: LayoutNode){
			this.$emit('leaf-click-held', data);
		},
		onInnerHeaderClickHeld(data: LayoutNode){
			this.$emit('header-click-held', data);
		},
		onInnerInfoIconClicked(data: LayoutNode){
			this.$emit('info-icon-clicked', data);
		},
		// Other
		triggerAnimation(animationClass: string){
			this.$el.classList.remove(animationClass);
			this.$el.offsetWidth; // Triggers reflow
			this.$el.classList.add(animationClass);
		},
	},
	emits: ['leaf-clicked', 'header-clicked', 'leaf-click-held', 'header-click-held', 'info-icon-clicked'],
	components: {LeafTile, NonLeafTile, },
});
</script>

<template>
<component :is="isLeaf ? LeafTile : NonLeafTile"
	:layoutNode="layoutNode" :lytOpts="lytOpts" :uiOpts="uiOpts" :nonAbsPos="nonAbsPos"
	:highlight="highlight" :inTransition="inTransition"
	@tile-mouse-enter="onMouseEnter" @tile-mouse-leave="onMouseLeave"
	@tile-mouse-down="onMouseDown" @tile-mouse-up="onMouseUp"/>
</template>
