<template>
	<tui-grid
		:ref="['tuigrid' + gridName]"
		:data="chkGridData"
		:columns="chkGridColumns"
		:options="chkGridOptions"
		@click="startEditing"
		@editingFinish="editingFinish"
		@dblclick="dblClick"
		@mouseover="mouseoverEvent"
		@mouseout="mouseoutEvent"
		@focusChange="focusChangeEvt"
	/>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
	props: {
		parentPrgmId: {
			type: String,
			require: true,
		},
		gridName: {
			type: String,
			require: true,
		},
		dataPath: {
			type: Object,
			require: false,
			default: null,
		},
		editorGrid: {
			type: Boolean,
			default: false,
			require: false,
		},
		innerTabGridInfo: {
			type: Object,
			default: null,
		},
		selectedRowDataWatchFlag: {
			type: Boolean,
			require: false,
			default: false,
		},
		preventFocusChangeEventFlag: {
			type: Boolean,
			require: false,
			default: false,
		},
		// gridInstance Array
		preventFocusChangeEventTargetGridList: {
			type: Array,
			require: false,
			default: null,
		},
		columnClickEventFlag: {
			type: Boolean,
			require: false,
			default: false,
		},
		mouseoverEvent: {
			type: Function,
			default() {
				return 'Default Function';
			},
		},
		mouseoutEvent: {
			type: Function,
			default() {
				return 'Default Function';
			},
		},
	},
	data() {
		return {
			gridInstance: null,
			gridHeight: null,
			selecrRowKey: null,
			originData: [],
			editorStartKey: null,
			editorEndKey: null,
			scrollBody: null,
			gridScrollTop: 0,
			gridScrollLeft: 0,
		};
	},
	computed: {
		...mapState({
			pageData: state => state.pageData,
			gridData(state) {
				return this.dataPath
					? this.dataPath[this.gridName]
					: state.pageData[this.parentPrgmId][this.gridName];
			},
			drawer: state => state.drawer,
			activePrgmId(state) {
				return state.activeMenuInfo.prgmId;
			},
		}),
		chkGridData() {
			// return this.pageData[this.parentPrgmId][this.gridName].data;
			return this.gridData.data;
		},
		chkGridColumns() {
			return this.gridData.column;
		},
		chkGridOptions() {
			const options = {
				...this.gridData.option,
			};
			options.treeColumnOptions = {
				useIcon: false,
				...options.treeColumnOptions,
			};

			return options;
		},
		defaultRow() {
			return this.gridData.defaultRow;
		},
	},
	watch: {
		chkGridData(val) {
			this.$refs['tuigrid' + this.gridName].invoke('resetData', val);
		},
		innerTabGridInfo(val) {
			const _this = this;
			setTimeout(() => {
				_this.refreshLayout();
			}, 500);
		},
		activePrgmId(val) {
			const _this = this;
			setTimeout(() => {
				_this.refreshLayout();
			}, 700);
			if (val == this.parentPrgmId) {
				setTimeout(() => {
					if (!_this.innerTabGridInfo) {
						//_this.refreshLayout();
						_this.scrollBody.scrollTop = _this.gridScrollTop;
						_this.scrollBody.scrollLeft = _this.gridScrollLeft;
					} else {
						if (_this.innerTabGridInfo.tab == _this.innerTabGridInfo.idx) {
							//_this.refreshLayout();
							_this.scrollBody.scrollTop = _this.gridScrollTop;
							_this.scrollBody.scrollLeft = _this.gridScrollLeft;
						}
					}
				}, 1000);
			}
		},
		drawer() {
			const _this = this;
			setTimeout(() => {
				_this.refreshLayout();
			}, 500);
		},
	},
	created() { },
	async mounted() {
		if (this.gridName) {
			this.gridInstance = this.$refs['tuigrid' + this.gridName];

			this.scrollBody = document
				.getElementsByClassName('tui-grid-rside-area')
			[
				document.getElementsByClassName('tui-grid-rside-area').length - 1
			].getElementsByClassName('tui-grid-body-area')[0];

			this.scrollBody.addEventListener('scroll', e => {
				this.gridScrollTop = e.target.scrollTop;
				this.gridScrollLeft = e.target.scrollLeft;
			});
			if (this.scrollBody.scrollHeight > this.scrollBody.clientHeight) {
				this.gridInstance.$el.getElementsByClassName('tui-grid-content-area')[0].classList.remove('tui-grid-no-scroll-y');
			} else {
				this.gridInstance.$el.getElementsByClassName('tui-grid-content-area')[0].classList.add('tui-grid-no-scroll-y');
			}
		}
	},
	methods: {
		...mapMutations({
			setPageData: 'setPageData',
			setGridData: 'setGridData',
		}),
		// true : 현재 행 혹은 연결된 그리드가 수정중인 상태
		checkGridState() {
			const rowStatList = ['I', 'U', 'D'];
			const row = this.gridInstance.invoke('getFocusedCell');

			if (row) {
				const rowData = this.gridInstance.invoke('getRow', row.rowKey);
				if (rowData) {
					const rowStat = rowData['rowStat'];
					if (rowStatList.includes(rowStat)) {
						return true;
					}
				}
			}

			if (this.preventFocusChangeEventTargetGridList) {
				for (let gridInstance of this.preventFocusChangeEventTargetGridList) {
					const dataArr = gridInstance.save();

					if (dataArr.length > 0) {
						return true;
					}
				}
			}

			return false;
		},
		preventFocusChangeEvent(e) {
			var result = false;

			if (this.preventFocusChangeEventFlag) {
				if (this.checkGridState()) {
					e.stop();
					return true;
				}
			}

			return result;
		},
		columnClickEvent(e) {
			var result = false;

			if (this.columnClickEventFlag) {
				return true;
			}
			return result;
		},
		getCheckedRowsEvt() {
			const checkedRowDataList = this.gridInstance.invoke('getCheckedRows');
			return checkedRowDataList;
		},
		dblClick(nativeEvent) {
			if (this.preventFocusChangeEvent(nativeEvent)) {
				return;
			}
			this.$emit(
				'dblClick',
				this.gridInstance.invoke('dblclick'),
				nativeEvent,
				this.gridName,
			);
		},
		uncheckEvt(rowData, instance) {
			this.gridInstance.invoke('uncheck', rowData.rowKey, instance);
		},
		checkEvt(rowData, instance) {
			this.gridInstance.invoke('check', rowData.rowKey, instance);
		},
		setSelectionRange(rowKey) {
			const rowDatas = this.gridInstance.invoke('getData');
			rowDatas.forEach(item => {
				if (item.rowKey == rowKey) {
					this.gridInstance.invoke(
						'addRowClassName',
						item.rowKey,
						'row-selected',
					);
				} else {
					this.gridInstance.invoke(
						'removeRowClassName',
						item.rowKey,
						'row-selected',
					);
				}
			});
		},
		focusChangeEvt(e) {
			if (this.preventFocusChangeEvent(e)) {
				return;
			}
			// cell 선택시 row 선택 method
			if (e.rowKey > -1) {
				this.$emit(
					'getRowsData',
					this.gridInstance.invoke('getRow', e.rowKey),
					this.gridName,
					e.columnName,
				);
				this.selecrRowKey = e.rowKey;
				this.setSelectionRange(e.rowKey);
			}
			this.sendSelectedRowData(e.rowKey);
		},
		startEditing(e) {
			if (this.preventFocusChangeEvent(e)) {
				return;
			}

			if (this.columnClickEvent(e)) {
				this.$emit('columnClick', e, this.gridName);
				return;
			}

			if (this.editorGrid && e.rowKey >= 0) {
				this.editorStartKey = e.rowKey;
				this.gridInstance.invoke('startEditing', e.rowKey, e.columnName, 'row-modify');
				this.$emit(
					'getRowsData',
					this.gridInstance.invoke('getRow', e.rowKey),
					this.gridName,
					e.columnName,
				);
				this.setSelectionRange(e.rowKey);
			}
		},
		async editingFinish(e) {
			// editor 간 이동시 수정되는 문제 수정
			// e.rowEditingFg: grid의 한 row를 한번에 수정할 시 각각의 cell 마다 click 이벤트가 발생하지 않아 this.editorStartKey값이 제대로 입력 되지 않는 경우를 대비하여 만든 Fg
			if (this.editorGrid) {
				this.editorEndKey = Number.isInteger(e.rowKey) ? e.rowKey : null;
				if (e.rowEditingFg == undefined && this.editorStartKey >= 0) {
					if (this.editorStartKey != this.editorEndKey) {
						this.editorStartKey = null;
						this.editorEndKey = null;
						return false;
					}
				}
			}
			const rowIdxKey = this.editorGrid ? this.editorEndKey : this.gridInstance.invoke('getFocusedCell').rowKey
			// editor 간 이동시 수정되는 문제 수정 끝

			const columnName = e.columnName;
			const value = e.value;
			const editingData = {
				...e,
				rowKey: rowIdxKey,
			};
			const isBaseRow = this.isBaseDataRow(rowIdxKey);
			const rowStat = this.gridInstance.invoke('getRow', rowIdxKey).rowStat;
			if (rowStat == 'D') {
				this.gridInstance.invoke(
					'removeRowClassName',
					rowIdxKey,
					'row-removed',
				);
			}

			await this.gridInstance.invoke(
				e.rowEditingFg != undefined ? 'setValue' : this.editorGrid ? 'finishEditing' : 'setValue',
				rowIdxKey,
				columnName,
				value,
			);


			if (isBaseRow) {
				const isSameData = await this.compareData(editingData);
				if (isSameData) {
					this.gridInstance.invoke(
						'removeRowClassName',
						rowIdxKey,
						'row-modify',
					);
					this.updateData('clear', rowIdxKey);
				} else {
					this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-modify');
					this.updateData('modify', rowIdxKey);
				}
			}
			if (
				e.ignoreUpdateDataInfoFlag === undefined ||
				e.ignoreUpdateDataInfoFlag === false
			) {
				this.$emit('updateDataInfo', {
					rowIdxKey: rowIdxKey,
					rowStat: rowStat,
					columnName: columnName,
					value: value,
					rowData: this.gridInstance.invoke('getRow', rowIdxKey),
				});
			}
			this.sendSelectedRowData();
		},
		async addRow(setData, argRowKey) {
			// 그리드가 수정중인 상태면 addRow를 하지 않음
			if (this.preventFocusChangeEventFlag) {
				if (this.checkGridState()) {
					return true;
				}
			}
			const addData = !setData
				? this.defaultRow
				: Object.assign(this.defaultRow, setData);
			// 열 앞에 데이터 추가
			// if (argRowKey != undefined && argRowKey != null) {
			this.gridInstance.invoke('appendRow', addData, {
				focus: true,
			});
			// } else {
			// 	this.gridInstance.invoke('prependRow', addData, {
			// 		focus: true,
			// 	});
			// }
			// this.gridInstance.invoke('prependRow', addData, {
			// 	focus: true,
			// });
			this.$nextTick(() => {
				var addRowKey = this.gridInstance.invoke('getFocusedCell').rowKey;
				if (argRowKey) {
					addRowKey = argRowKey;
				}
				this.gridInstance.invoke(
					'removeRowClassName',
					addRowKey,
					'row-removed',
				);
				this.gridInstance.invoke('addRowClassName', addRowKey, 'row-insert');
				this.updateData('insert', addRowKey);
			});
		},
		async appendRow() {
			this.gridInstance.invoke('appendRow', {
				focus: true,
			});
		},
		async addTreeRow(setData) {
			// tree append의 경우 무한루프가 발행하는 버그현상으로 appendRows로 추가
			const addData = !setData
				? this.defaultRow
				: Object.assign(this.defaultRow, setData);

			this.gridInstance.invoke('appendRows', [addData]);
			this.$nextTick(() => {
				const rowDatas = this.gridInstance.invoke('getData');
				const addRowKey = rowDatas[rowDatas.length - 1].rowKey;
				this.gridInstance.invoke(
					'removeRowClassName',
					addRowKey,
					'row-removed',
				);
				this.gridInstance.invoke('addRowClassName', addRowKey, 'row-insert');
				this.updateData('insert', addRowKey);
				this.gridInstance.invoke('focus', addRowKey);
			});
		},
		async removeRow(delType, argRowKey) {
			var rowIdxKey = this.gridInstance.invoke('getFocusedCell').rowKey;
			if (typeof argRowKey == 'number') {
				rowIdxKey = argRowKey;
			}
			const rowStat = this.gridInstance.invoke('getRow', rowIdxKey).rowStat;
			if (rowStat === 'D') {
				this.gridInstance.invoke(
					'removeRowClassName',
					rowIdxKey,
					'row-removed',
				);
				this.updateData('clear', rowIdxKey);
			} else {
				if (!this.isBaseDataRow(rowIdxKey)) {
					this.gridInstance.invoke('removeRow', rowIdxKey);
					let nextFocus = Number(rowIdxKey) - 1;
					if (!this.isBaseDataRow(nextFocus)) nextFocus = 0;
					this.gridInstance.invoke('focus', nextFocus);
				} else {
					this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-removed');
					this.updateData('delete', rowIdxKey);

					if (delType == 'immediately')
						this.gridInstance.invoke('removeRow', rowIdxKey);
				}
			}
		},
		async removeTreeRow(delType) {
			const rowIdxKey = this.gridInstance.invoke('getFocusedCell').rowKey;
			const rowStat = this.gridInstance.invoke('getRow', rowIdxKey).rowStat;
			if (rowStat === 'D') {
				this.gridInstance.invoke(
					'removeRowClassName',
					rowIdxKey,
					'row-removed',
				);
				this.updateData('clear', rowIdxKey);
			} else {
				if (!this.isBaseDataRow(rowIdxKey)) {
					this.updateData('clear', rowIdxKey);
					this.gridInstance.invoke('removeRow', rowIdxKey);
					let nextFocus = Number(rowIdxKey) - 1;
					if (!this.isBaseDataRow(nextFocus)) nextFocus = 0;
					this.gridInstance.invoke('focus', nextFocus);
				} else {
					this.gridInstance.invoke('addRowClassName', rowIdxKey, 'row-removed');
					this.updateData('delete', rowIdxKey);

					if (delType == 'immediately')
						this.gridInstance.invoke('removeRow', rowIdxKey);
				}
			}
		},
		isBaseDataRow(rowKey) {
			// 기존데이터 여부 확인 (추가된 데이터 X)
			const findRow = this.gridInstance.invoke('findRows', { rowKey: rowKey });
			return findRow && findRow[0] && findRow[0].rowStat != 'I' ? true : false;
		},
		compareData(data) {
			// rowStat key값 제거
			const dataKeyArr = Object.keys(this.defaultRow);
			const rowStatIdx = dataKeyArr.indexOf('rowStat');
			dataKeyArr.splice(rowStatIdx, 1);
			// rowStat key값 제거 끝

			const selectedRowData = this.gridInstance.invoke('getRow', data.rowKey);
			this.getOriginData();

			const rowData = this.originData.find(item => {
				return item.rowKey == data.rowKey;
			});
			let count = 0;
			for (let i = 0; i < dataKeyArr.length; i++) {
				if (selectedRowData[dataKeyArr[i]] == rowData[dataKeyArr[i]]) {
					count++;
				}
			}
			return dataKeyArr.length == count ? true : false;
		},
		getOriginData() {
			this.chkGridData.forEach(item => {
				this.originData.push(item);
				if (item._children) {
					this.getChildrenData(item._children);
				}
			});
		},
		getChildrenData(children) {
			children.forEach(item => {
				this.originData.push(item);
				if (item._children) {
					this.getChildrenData(item._children);
				}
			});
		},
		updateData(updateType, rowIdxKey) {
			let type = '';
			switch (updateType) {
				case 'insert':
					type = 'I';
					break;
				case 'modify':
					type = 'U';
					break;
				case 'delete':
					type = 'D';
					break;
				case 'clear':
					type = null;
					break;
			}
			this.gridInstance.invoke('setValue', rowIdxKey, 'rowStat', type);
		},
		// 지정 로우 선택상태
		focus(rowInfo) {
			this.gridInstance.invoke(
				'focus',
				rowInfo.rowKey,
				rowInfo.columnName,
				rowInfo.setScroll,
			);
		},
		// 트리 전체 접기
		expandAll() {
			this.gridInstance.invoke('expandAll');
		},
		// 트리 전체 펼치기
		collapseAll() {
			this.gridInstance.invoke('collapseAll');
		},
		save() {
			const saveTargetRows = this.gridInstance.invoke('getModifiedRows');
			// createdRows | deletedRows | updatedRows
			const createdRows = saveTargetRows.createdRows;
			const deletedRows = saveTargetRows.deletedRows;
			const updatedRows = saveTargetRows.updatedRows;
			const dataArr = [...createdRows, ...deletedRows, ...updatedRows]
				.filter(item => item.rowStat)
				.map(item => {
					delete item.rowKey;
					return item;
				});
			return dataArr;
		},
		getData() {
			return this.gridInstance.invoke('getData');
		},
		getCheckedRows() {
			return this.gridInstance.invoke('getCheckedRows');
		},
		getCheckedRowKeys() {
			return this.gridInstance.invoke('getCheckedRowKeys');
		},
		setCheck(list) {
			list.map(item => this.gridInstance.invoke('check', item));
		},
		refreshLayout() {
			setTimeout(() => {
				this.gridInstance.invoke('refreshLayout');
			}, 150);
			// this.gridInstance.invoke('refreshLayout');
		},
		refreshGrid() {
			var store = this.$refs['tuigrid' + this.gridName].gridInstance.store;
			var containerEl = this.$refs['tuigrid' + this.gridName].$el;
			// var containerEl = document.querySelector('.tui-grid-container')
			var parentEl = containerEl.parentElement;

			// 	function refreshLayout(store, containerEl, parentEl) {
			var dimension = store.dimension;
			var autoWidth = dimension.autoWidth, fitToParentHeight = dimension.fitToParentHeight;
			var clientHeight = containerEl.clientHeight, clientWidth = containerEl.clientWidth, scrollTop = containerEl.scrollTop, scrollLeft = containerEl.scrollLeft;
			var _a = containerEl.getBoundingClientRect(), top = _a.top, left = _a.left;
			this.setOffsetTop(store, top + scrollTop);
			// store.dimension.setOffsetTop = top + scrollTop;
			this.setOffsetLeft(store, left + scrollLeft);
			// store.dimension.headerHeight = left + scrollLeft;
			this.setWidth(store, clientWidth, autoWidth);
			// store.dimension.autoWidth = autoWidth;
			// store.dimension.width = clientWidth;
			if (parentEl && parentEl.clientHeight !== clientHeight) {
				var _b = getComputedStyle(parentEl), paddingTop = _b.paddingTop, paddingBottom = _b.paddingBottom;
				this.setHeight(store, parentEl.clientHeight - (parseFloat(paddingTop) + parseFloat(paddingBottom)));
			}
			// }
		},
		setOffsetTop(store, offsetTop) {
			store.dimension.offsetTop = offsetTop;
		},
		setWidth(_a, width, autoWidth) {
			var dimension = _a.dimension;
			dimension.autoWidth = autoWidth;
			dimension.width = width;
		},
		setHeaderHeight(store, height) {
			store.dimension.headerHeight = height;
		},
		setOffsetLeft(store, offsetLeft) {
			store.dimension.offsetLeft = offsetLeft;
		},
		setHeight(_a, height) {
			var dimension = _a.dimension;
			var headerHeight = dimension.headerHeight, summaryHeight = dimension.summaryHeight, tableBorderWidth = dimension.tableBorderWidth;
			dimension.bodyHeight = height - headerHeight - summaryHeight - tableBorderWidth;
		},
		sendSelectedRowData(eventRowKey) {
			if (this.selectedRowDataWatchFlag) {
				var rowKey =
					eventRowKey === undefined
						? this.gridInstance.invoke('getFocusedCell').rowKey
						: eventRowKey;
				var rowData = this.gridInstance.invoke('getRow', rowKey);
				this.$emit('sendSelectedRowStatInfo', rowData);
			}
		},
		disableRow(rowKey, withCheckBox = false) {
			this.gridInstance.invoke('disableRow', rowKey, withCheckBox);
		},
		async disabledRow(addRowKey) {
			this.$nextTick(() => {
				this.gridInstance.invoke(
					'removeRowClassName',
					addRowKey,
					'row-removed',
				);
				this.gridInstance.invoke('addRowClassName', addRowKey, 'row-disabled');
			});
		},
		// resetData() {
		//   this.$refs.tuigrid.invoke("resetData", this.tuigridProps.data);
		// },
	},
};
</script>

<style scoped lang="scss">
::v-deep .tui-grid-container {
	.tui-grid-content-area {
		.tui-grid-cell-content {
			input[type='number'] {
				width: 100%;
			}
		}
	}
}
</style>
