<template>
	<foreignObject :x="data.design.x" :y="data.design.y" :width="width" :height="height">
		<div ref="node" :class="{active: active}" class="node" style="margin-top: 20px;" @mousedown="onMouseDown"
		     @mouseenter="onMouseEnter"
		     @mouseleave="onMouseLeave" @click="onClick" @dblclick="onDblclick">
			<div class="top-bar" v-if="meta.id !== 'entry' && editable">
				<el-link icon="el-icon-magic-stick" :underline="false" v-if="meta.type !== 'builtin'" @mousedown.stop.prevent @click.stop="onClickTransform"/>
				<el-link icon="el-icon-delete" :underline="false" @mousedown.stop.prevent @click.stop="onClickDelete"/>
				<el-link icon="el-icon-edit" :underline="false" v-if="meta.type !== 'builtin' && !meta.isDivider"
				         @mousedown.stop.prevent @click.stop="onClickEdit"/>
				<el-link icon="el-icon-document-copy" :underline="false" @mousedown.stop.prevent @click.stop="onClickCopy"/>
			</div>
			<div class="header">
				<i v-if="meta.isInline">i</i>
				<span class="title">{{data.alias || meta.name}}</span>
			</div>
			<div class="body">
				<div v-if="meta.isDivider">
					<el-select v-model="meta.dividerType" size="mini" placeholder="选择类型">
						<el-option
							v-for="(item, key) in dividerTypes"
							:key="key"
							:label="item"
							:value="key">
						</el-option>
					</el-select>
					<el-button size="mini" icon="el-icon-plus" circle @click="outputPointModify('add')"></el-button>
					<el-button size="mini" icon="el-icon-minus" circle @click="outputPointModify('remove')"></el-button>
				</div>
				<div v-else class="field-item" v-for="(param, key, index) in meta.props" :key="index">
					<span class="key">{{param.alias || key}}</span>:
					<span class="linked-value" v-if="typeof data.props[key] === 'object'">
						<span class="string-value">
							<template v-if="data.props[key].type === 'link'">
								{{data.props[key].alias || ''}}
								<i class="el-icon-link tag"></i>
							</template>
							<template v-else>
								{{objToString(data.props[key].value)}}
								<i class="tag">{{dynamicIconMapping[data.props[key].type]}}</i>
							</template>
						</span>
					</span>
					<template v-else>
						<div v-if="param.type === 'color'">
							<div class="color-value" :style="{'background-color': valueToString(param, data, key)}"></div>
						</div>
						<span v-else class="string-value">{{valueToString(param, data, key)}}</span>
					</template>
				</div>
			</div>
			<div ref="inputDock" class="dock input">
				<dock-pin v-if="meta.id !== 'entry'" v-for="(pin, key, index) in inputMeta" :key="index"></dock-pin>
			</div>
			<div ref="outputDock" class="dock output">
				<dock-pin v-for="(pin, key, index) in meta.output" :key="index" :data="pin"
				          @mouseenter="onPinHover"
				          @mouseleave="onPinLeave"
				          @mousedown="onPinDown"
				></dock-pin>
			</div>
      <!-- 判断是否有子节点 -->
      <i class="sub-mark el-icon-s-tools" v-show="meta.sub && meta.from === 'custom' &&  Object.keys(meta.sub).length > 0" style="color:#9b82e3;text-align: center;"></i>
		</div>
	</foreignObject>
</template>

<script>
	import {mapState, mapGetters} from "vuex";
	import DockPin from "./DockPin";
	import events from "../../../../global-events";
	import {dynamicIconMapping, nodeScheme} from "../../../../utils";

	export default {
		name: "ProcessNode",
		components: {DockPin},
		props: ['process'],
		data() {
			this.prepare();
			const inputMeta = this.process.meta.id === 'entry' ? [] : ['default'];
			return {
				width: 130,
				height: 100,
				inputMeta,
				active: false,
				dynamicIconMapping,
				dividerTypes: this.$t('dividerTypes'),
			}
		},
		mounted() {
			this.updateSize();

			events.$on('update-dock-pin-pos', this.updateDockPointPos);
		},
		destroyed() {
			events.$off('update-dock-pin-pos', this.updateDockPointPos);
		},
		computed: {
			meta() {
				return this.process.meta;
			},
			data() {
				return this.process.data;
			},
			...mapState({
				drawState: state => state.behavior.drawState,
				editable: state => state.behavior.editable,
			}),
			...mapGetters([
				'behavior_searchViewNode'
			]),
		},
		watch: {
			process(v) {
				this.active = false;
				this.prepare();
				this.updateSize();
			},
		},
		methods: {
			valueToString(param, data, key) {
				if (param.type === 'asset') {
					if (data.props.hasOwnProperty(key)) {
						let asset = this.$store.getters.behavior_getAssetByUUID(data.props[key]);
						return asset.name;
					}
				} else if (param.type === 'node') {
					let uuid = data.props[key] ? data.props[key].replace(nodeScheme, '') : null;
					let searchResult = this.behavior_searchViewNode(uuid);
					if (searchResult) {
						return searchResult.node.name;
					}
				} else {
					return data.props.hasOwnProperty(key) ? data.props[key] : param.default;
				}

				return '';
			},
			objToString(value) {
				return typeof value === 'object' ? '' : (value || '');
			},
			prepare() {
				let {design, props, output} = this.process.data;
				if (!design) {
					this.$set(this.process.data, 'design', {});
					design = this.process.data.design;
				}
				if (!design.x) {
					this.$set(design, 'x', 0);
				}
				if (!design.y) {
					this.$set(design, 'y', 0);
				}
				if (!props) {
					this.$set(this.process.data, 'props', {});
				}
				if (!output) {
					this.$set(this.process.data, 'output', {});
				}
			},
			onClick(e) {
				this.$emit('click', e);
			},
			onDblclick(e) {
				this.$emit('dblclick', e);
			},
			setActive(active) {
				this.active = active;
			},
			onMouseEnter(e) {
				if (this.drawState.drawing && this.meta.id !== 'entry') {
					this.drawState.targetUUID = this.data.uuid;
				}
			},
			onMouseLeave(e) {
				if (this.drawState.drawing) {
					this.drawState.targetUUID = null;
				}
			},
			onMouseDown(e) {
				const {x, y} = this.data.design;
				this.mouseDownPos = {x: e.screenX, y: e.screenY, dx: x, dy: y};
				document.addEventListener("mousemove", this.onMouseMove);
				document.addEventListener("mouseup", this.onMouseUp);
			},
			onMouseMove(e) {
				const {x, y, dx, dy} = this.mouseDownPos;
				const offset = this.offset = {x: e.screenX - x, y: e.screenY - y};

				const tx = offset.x / this.drawState.boardScale + dx;
				const ty = offset.y / this.drawState.boardScale + dy;

				this.data.design.x = tx;
				this.data.design.y = ty;

				this.$emit('changing-position', this, {x: tx, y: ty});
			},
			onMouseUp(e) {
				document.removeEventListener("mousemove", this.onMouseMove);
				document.removeEventListener("mouseup", this.onMouseUp);

				if (this.offset) {
					this.offset = null;

					this.$emit('change-position', this, this);
				}
			},
			updateSize() {
				this.$nextTick(() => {
					let bounds = this.$refs.node.getBoundingClientRect();
					this.width = bounds.width + 18;
					this.height = bounds.height + 20;
				});
			},
			updateDockPointPos() {
				const {x: dx, y: dy} = this.process.data.design;
				const {x: offX, y: offY} = this.drawState.boardOffset;
				for (let side of ['input', 'output']) {
					let container = this.$refs[side + 'Dock'];
					let sideMeta = side === 'input' ? this.inputMeta : this.meta[side];

					let dockPointPos = {};
					if (sideMeta) {
						for (let i = 0, li = sideMeta.length; i < li; i++) {
							const key = sideMeta[i];

							let posArr = [];
							dockPointPos[key] = posArr;
							let dockPin = container.children[i];
							const {x, y} = dockPin.getBoundingClientRect();
							posArr.push({
								x: x - dx - offX + 4.5,
								y: y - dy - offY,
							});
						}
					}
					this.$set(this.process.data.design, side, dockPointPos);
				}
			},
			onPinHover(e, pin) {
				const {x, y} = e.target.getBoundingClientRect();
				this.$emit('hover-pin', x, y, pin);
			},
			onPinLeave(e, pin) {
				const {x, y} = e.target.getBoundingClientRect();
				this.$emit('leave-pin', x, y, pin);
			},
			onPinDown(e, pin) {
				let output = this.data.output[pin];
				if (!output || output.length === 0) {
					this.$emit('down-pin', e, this.data, pin);
				}
			},
			onClickTransform() {
				this.$emit('transform', this.process);
			},
			onClickDelete() {
				this.$confirm(this.$t('Are you sure to delete this process?'))
					.then(()=>{
						this.$emit('delete', this.data, this.meta);
					}).catch(e=>{});
			},
			onClickEdit() {
				this.$emit('edit-meta', this.meta);
			},
			onClickCopy() {
				this.$emit('copy', this.data, this.meta);
			},
			outputPointModify(action) {
				let output = this.meta.output;
				let count = output.length;
				switch (action) {
					case 'add':
						count++;
						break;
					case 'remove':
						count--;
						if (count < 0) {
							count = 0;
						}
						break;
				}
				output.splice(0);
				for (let i = 0; i < count; i++) {
					output.push('p' + i);
				}

				this.$emit('meta-modified', this.data, this.meta);
				this.$nextTick(() => {
					this.updateDockPointPos();
				});
			}
		}
	}
</script>

<style scoped>

</style>