content: import React from 'react'
  import { Motion, spring } from 'react-motion'
  import { map, each, min, max, reduce } from 'lodash'
  import svgLine from 'svg-line'
  require('../style/index.css') 
  
  const line = svgLine()  
    .x((d) => d[0])
    .y((d) => d[1])
  
  const springSetting = { stiffness: 130, damping: 25 }
  
  class Stack extends React.Component{
    constructor() {
      super()
      this.state = { index: 0, textLengths: [], textHeights: [] }
      this.labels = {}
  
      this.handleKeyDown = this.handleKeyDown.bind(this)
    }
  
    componentDidMount() {
      window.addEventListener('keydown', this.handleKeyDown)
      this.getTextProps()
    }
  
    getTextProps() {
      const textLengths = reduce(
        this.labels, 
        (memo, label, id) => {
          if (label) memo[id] = label.node.getComputedTextLength()
          return memo
        },
        {}
      )
  
      const textHeights = reduce(
        this.labels,
        (memo, label, id) => {
          if (label) {
            memo[id] = parseInt(window.getComputedStyle(label.node).fontSize, 10)
          }
          return memo
        },
        {}
      )
  
      this.setState({ textLengths, textHeights })
    }
  
    componentWillUnmount() {
      window.removeEventListener('keydown', this.handleKeyDown)
    }
  
    componentDidUpdate(prevProps, prevState) {
      if (prevState.index !== this.state.index) {
        this.getTextProps()
      }
    }
  
    handleKeyDown(e) {
      const index = this.state.index
  
      if (e.code === 'Enter') this.setState({ index: index + 1 })
      if (e.code === 'Backspace') this.setState({ index: index - 1 })
    }
  
    render() {
      console.log(this.state, this.props)
      this.labels = {}
      const { index } = this.state
      const { width, height, radius, padding, layouts, links } = this.props
      const layout = layouts[index]
      const edges = links[index]
      const xs = map(layout, (node) => node[0])
      const ys = map(layout, (node) => node[1])
      const cx = center(max(xs), min(xs))
      const cy = center(max(ys), min(ys))
      const size = radius + padding + 10
      const title = this.props.diagramTitles[index]
  
      return (
        <div>
        <svg 
          id='diagram'
          width={width}
          height={height}
          xmlns="http://www.w3.org/2000/svg" >      
          <defs xmlns="http://www.w3.org/2000/svg">
            <filter id="dropshadow" width='150%' height="150%">
              <feGaussianBlur in="SourceAlpha" stdDeviation="2"/> 
              <feOffset dx="-1" dy="2" result="offsetblur"/> 
              <feMerge> 
                <feMergeNode/>
                <feMergeNode in="SourceGraphic"/> 
              </feMerge>
            </filter>
          </defs>
          <g id='links'>
            {
              map(edges, ([start, end], i) => {
                const [x1, y1] = layout[start]
                const [x2, y2] = layout[end]
  
                const style = {
                  x1: spring(x1, springSetting),
                  x2: spring(x2, springSetting),
                  y1: spring(y1, springSetting),
                  y2: spring(y2, springSetting)
                }
  
                return (
                  <Motion key={i} style={style}>
                    {({x1, x2, y1, y2}) => (
                      <line 
                        x1={x1}
                        x2={x2}
                        y1={y1}
                        y2={y2}
                        strokeWidth={2}
                        stroke="grey" 
                      />
                    )}
                  </Motion>
                )
              })
            }
          </g>
          <g id="entities" >
            {
              map(layout, ([x, y, id]) => {
                const style = {
                  tx: spring(x, springSetting),
                  ty: spring(y, springSetting)
                }
  
                return (
                  <Motion key={id} style={style} >
                    {({tx, ty}) => (
                      <circle 
                        filter='url(#dropshadow)'
                        cx={tx} 
                        cy={ty} 
                        r={radius} 
                        fill='#ff4081' />
                    )}
                  </Motion >
                )
              })
            }
          </g>
          <g id="labels" >
            {
              map(layout, ([x, y, id, text]) => {
                const l = this.state.textLengths[id] || 0
                const h = this.state.textHeights[id] || 0
                const [xO, yO] = getTextOffset(size, x, y, cx, cy, l, h)
                const [
                  [x1, y1], 
                  [x2, y2], 
                  [x3, y3]] = connector(radius, x, y, cx, cy, l)
                
                const style = {
                  tx: spring(x, springSetting),
                  ty: spring(y, springSetting),
                  txO: spring(xO, springSetting),
                  tyO: spring(yO, springSetting),
                  tx1: spring(x1, springSetting),
                  tx2: spring(x2, springSetting),
                  tx3: spring(x3, springSetting),
                  ty1: spring(y1, springSetting),
                  ty2: spring(y2, springSetting),
                  ty3: spring(y3, springSetting)
                }
  
                return (
                  <Motion key={id} style={style} >
                    {({tx, ty, txO, tyO, tx1, tx2, tx3, ty1, ty2, ty3}) => (
                      <g 
                        className='annotation'
                        style={{
                          transform: `translate3d(${tx}px, ${ty}px, 0)`
                        }} >
                        <path d={line([[tx1, ty1], [tx2, ty2], [tx3, ty3]])} />
                         
                        <Label 
                          ref={(label) => { this.labels[id] = label }} 
                          text={text} 
                          x={xO} 
                          y={yO} />
                      </g>
                    )}
                  </Motion>
                )
              })
            }
          </g>
        </svg>
        <h2 
          style={{
            position: 'absolute',
            textAlign: 'center',
            top: 10
          }} >
          { title }
        </h2> 
        </div>
      )
    }
  }
  
  class Label extends React.Component{
    render() {
      const { x, y, text } = this.props
  
      return (
        <g>
          <text 
            x={x}
            y={y}
            ref={(t) => this.node = t } 
            className="label san-serif">
              {text}
          </text>
        </g>
      )
    }
  }
  
  export default Stack
  
  function center (max, min) {
    return (max + min) / 2
  }
  
  function getTextOffset (size, x, y, cx, cy, l, h) {
    let xOffset, yOffset
  
    if (x < cx) {
      xOffset = -size - l - 10
    } else {
      xOffset = size + 10
    }
  
    if (y < cy) {
      yOffset = -size - 5
    } else {
      yOffset = size + h
    }
  
    return [xOffset, yOffset]
  }
  
  function connector (r, x, y, cx, cy, textLength) {
    let x1, y1, x2, y2, x3, y3 
    console.log('textLength', textLength)
  
    if (x < cx) {
      x1 = -r
      x2 = x1 - 20
      x3 = x2 - textLength - 10
    } else {
      x1 = r
      x2 = x1 + 20
      x3 = x2 + textLength + 10
    }
  
    if (y < cy) {
      y1 = -r
      y2 = y3 = y1 - 20
    } else {
      y1 = r
      y2 = y3 = y1 + 20
    }
  
    return [[x1, y1], [x2, y2], [x3, y3]]
  }
  
  
  