<template>

  <g
    class="flow-node"
    :class="{
      'flow-node--dragging':dragging,
      'flow-node--selected': selected
    }"
    @mousedown.stop.prevent="$emit('nodePointerDown',$event)"
    @dblclick="$emit('nodeDoubleClick',$event)"
  >

    <rect
      class="flow-node__selection"
      stroke-dasharray="7,3"
      :x="bodyProps.x-4"
      :y="bodyProps.y-4"
      :width="bodyProps.width+8"
      :height="bodyProps.height+8"
    />

    <!--      <circle
        :r="bodyProps.r+4"
        stroke-dasharray="7,3"
        class="flow-node__selection"
        />-->
    <svg
      v-if="style.shape == 'thing'"
      ref="body"
      viewBox="0 0 100 100"
      preserveAspectRatio="XMinYMin"
      class="flow-node__body"
      :class="{'flow-node__body--dragging':dragging}"
      v-bind="bodyProps"
    >
      <path d=" M 0 0 l 90 0 l 10 50 l -10 50 l -90 0 c 10 -20, 10 -80, 0 -100 Z " />
    </svg>

    <circle
      v-else-if="style.shape == 'circle'"
      ref="body"
      class="flow-node__body"
      :class="{'flow-node__body--dragging':dragging}"
      v-bind="bodyProps"
    />
    <rect
      v-else
      ref="body"
      class="flow-node__body"
      :class="{'flow-node__body--dragging':dragging}"
      v-bind="bodyProps"
    />

    <text
      ref="label"
      class="flow-node__label"
      v-bind="labelProps"
      text-anchor="middle">
      <tspan x="0" dy="1em" v-for="s in labelWrap" >
        {{ s }}
      </tspan>
      <!--{{ label }}-->
    </text>

    <!-- input -->
    <circle
      class="flow-node__socket flow-node__socket--inputs"
      v-for="(inp,i) in inputs"
      v-bind="inputProps(i)"
      :data-nodeid="id"
      :data-in="i"
      :class="{'flow-node__socket--match': match.in && (inp == match.in || match.in == 'any' || inp=='any')}"
      :key="'in'+i"
      @mousedown.stop.prevent="socketPointerDown($event, {in:i})"
    />
    <!-- output -->
    <circle
      v-if="output"
      class="flow-node__socket flow-node__socket--outputs"
      :data-nodeid="id"
      :data-out="0"
      :key="'out'+0"
      :class="{ 'flow-node__socket--match': match.out && (output == match.out || match.out == 'any' || output == 'any'), }"
      v-bind="outputProps(0)"
      @mousedown.stop.prevent="socketPointerDown($event, {out:0})"
    />

    <text
      class="flow-node__socket-detail"
      v-for="(inp,i) in inputs"
      text-anchor="end"
      :x="inputPos(i).x - 13"
      :y="inputPos(i).y+5"
    >{{ inp }}</text>
    <text
      class="flow-node__socket-detail"
      :x="outputPos(0).x + 13"
      :y="outputPos(0).y+5">
      {{ output }}
    </text>

  </g>

</template>

<script>
import utils from '@/utils/utils'
const shapeOpts = {
  'circle': {
    textWrap: 'any'
  },
  default: {
    textWrap: 'white-space'
  }
}
export default {
  name: 'FlowNode',
  props: {
    'id': {type: String, required: true},
    'label': {type: String, default: ''},
    'inputs': {type: Array, default: () => []},
    'output': {type: String, default: ''},
    'match': {type: Object, default: () => {}},
    'dragging': {type: Boolean, default: false},
    'selected': {type: Boolean, default: false},
    'status': {type: String, default: ''},

    'nodeStyle': {type: Object, default: () => {}}
  },
  data () {
    return {
      // maintain reference here?
      labelRect: {x: 0, y: 0, width: 0, height: 0},
      bodyRect: {x: 0, y: 0, width: 0, height: 0}
    }
  },
  computed: {
    style () {
      return this.nodeStyle || {}
    },
    labelWrap () {
      let wrapThreshold = 10 // initial wrap threshold
      const opt = shapeOpts[this.style.shape] || shapeOpts.default
      return utils.textWrap(this.label, wrapThreshold, opt.textWrap)
    },
    labelProps () {
      return {
        x: 0,
        y: 0,
        fill: this.textColor,
        // transform: `translate(${-this.labelRect.width / 2},${-this.labelRect.height / 2})`
        transform: `translate(0,${-this.labelRect.height / 2})`
      }
    },
    bodyProps () {
      let width = this.labelRect.width + 46
      let height = Math.max(this.labelRect.height + 20, 60)
      if (this.style.shape === 'circle') {
        width = height = Math.max(width, height)
      }

      const rect = {
        x: -width / 2,
        y: -height / 2,
        width: width,
        height: height,
        stroke: this.style.color || '#777',
        fill: this.style.color || '#777'
      }
      if (this.style.shape === 'circle') {
        rect.r = Math.max(width / 2, height / 2)
      }
      return rect
    },
    inputProps () {
      return (i) => {
        const {x, y} = this.inputPos(i)
        return {
          transform: `translate(${x} ${y})`,
          r: 5
        }
      }
    },
    outputProps () {
      return (i) => {
        const {x, y} = this.outputPos(i)
        return {
          transform: `translate(${x} ${y})`,
          r: 5
        }
      }
    }
  },
  watch: {
    // the only thing now that affects geometry
    'label' () {
      this.$nextTick(() => {
        this.labelRect = this.$refs.label.getBBox()
      })
    }
  },
  mounted () {
    // After render
    this.$nextTick(() => { // after mount we reupdate with new values
      if (!this.$refs.label) return
      this.labelRect = this.$refs.label.getBBox()
      this.$forceUpdate()
    })
  },
  methods: {
    inputPos (i) {
      const ilen = this.inputs.length
      if (ilen === 0) return {}
      const d = this.bodyProps.height / (ilen * 2)
      return {
        x: this.bodyProps.x + 7,
        y: this.bodyProps.y + d + (i * 2 * d)
      }
    },
    outputPos (i) {
      const rect = this.bodyProps
      return {
        x: rect.x + rect.width - 7,
        y: 0
      }
    },
    socketPointerDown (ev, socket) {
      this.$emit('socketPointerDown', ev, socket)
    }

  }
}
</script>
<style>
.flow-view:not(.activity) .flow-node:hover,
.flow-node--dragging {
  cursor:move;
}

.flow-node__socket {
  pointer-events: none;
  stroke-width:1;
  opacity:0;
  transition: all 0.3s;
}

.flow-node__body {
  transition: all 0.3s;
}

.flow-view:not(.activity) .flow-node__socket:hover {
  stroke-width:10;
  cursor:pointer;
}

.flow-node__socket--match {
  cursor:pointer;
  stroke-width:10;
}

/*
Override flow-node
for hidden
 */
.flow-linking .flow-node__socket {
  opacity:1;
  pointer-events: inherit;
}

.flow-linking .flow-node__socket--match,
.flow-node__socket--match {
  opacity:1;
  pointer-events: inherit;
}

.flow-node__label {
  stroke:none;
  pointer-events:none;
  user-select:none;
  fill:#333 !default;
}

.flow-node__socket-detail {
  pointer-events:none;
  opacity:0;
  fill: #fff !default;
}

.flow-view.flow-detail .flow-node__socket-detail {
  opacity:1;
}

.flow-node .flow-node__selection {
  opacity:0;
  stroke-width:1;
  pointer-events:none;
  transition: 0.3s;
}

.flow-node--selected .flow-node__selection {
  opacity:1;
}

</style>
