text: import Promise from 'bluebird'
  import PropTypes from 'prop-types'
  import React, { Component } from 'react'
  import ReactDOM from 'react-dom'
  import assign from 'lodash/assign'
  import Pane from './Pane'
  import Resizer from './Resizer'
  
  class SplitPane extends Component {
    constructor (props) {
      super(props)
  
      this.windows = {}
  
      this.splitPaneRef = React.createRef()
      this.resizerRef = React.createRef()
      this.pane1Ref = React.createRef()
      this.pane2Ref = React.createRef()
  
      this.state = {
        active: false,
        resized: false
      }
  
      this.collapse = this.collapse.bind(this)
      this.cancel = this.cancel.bind(this)
      this.onMouseDown = this.onMouseDown.bind(this)
      this.onMouseMove = this.onMouseMove.bind(this)
      this.onMouseUp = this.onMouseUp.bind(this)
    }
  
    static propTypes = {
      primary: PropTypes.oneOf(['first', 'second']),
      minSize: PropTypes.number,
      defaultSize: PropTypes.string,
      size: PropTypes.number,
      allowResize: PropTypes.bool,
      resizerClassName: PropTypes.string,
      split: PropTypes.oneOf(['vertical', 'horizontal']),
      onDragStarted: PropTypes.func,
      onDragFinished: PropTypes.func,
      onCollapsing: PropTypes.func,
      onDocking: PropTypes.func,
      onUndocking: PropTypes.func,
      onUndocked: PropTypes.func
    }
  
    static defaultProps = {
      split: 'vertical',
      minSize: 50,
      allowResize: true,
      rimary: 'first',
      collapsable: 'second',
      undockeable: false,
      defaultSize: '50%'
    }
  
    componentDidMount () {
      this.setSize(this.props, this.state, (newSize) => {
        if (typeof this.props.onChange === 'function') {
          this.props.onChange(newSize)
        }
  
        if (typeof this.props.onDragFinished === 'function') {
          this.props.onDragFinished()
        }
      })
  
      document.addEventListener('mouseup', this.onMouseUp)
  
      this.windows = {}
    }
  
    setSize (props, state, cb) {
      const ref = this.props.primary === 'first' ? this.pane1Ref.current : this.pane2Ref.current
      let newSize
  
      if (ref) {
        newSize = props.size || (state && state.draggedSize) || props.defaultSize || props.minSize
  
        ref.setState({
          size: newSize
        }, () => cb(newSize))
      }
    }
  
    componentWillUnmount () {
      document.removeEventListener('mouseup', this.onMouseUp)
      this.windows = {}
    }
  
    onMouseDown (event) {
      if (this.props.allowResize && !this.props.size) {
        this.unFocus()
        let position = this.props.split === 'vertical' ? event.clientX : event.clientY
        if (typeof this.props.onDragStarted === 'function') {
          this.props.onDragStarted()
        }
        this.setState({
          active: true,
          position: position
        })
  
        document.addEventListener('mousemove', this.onMouseMove)
      }
    }
  
    onMouseMove (event, force) {
      if (this.props.allowResize && !this.props.size && !this.state.collapsed) {
        if (this.state.active || force) {
          this.unFocus()
          const ref = this.props.primary === 'first' ? this.pane1Ref.current : this.pane2Ref.current
          if (ref) {
            const node = ref.node
  
            if (node.getBoundingClientRect) {
              const width = node.getBoundingClientRect().width
              const height = node.getBoundingClientRect().height
              const current = this.props.split === 'vertical' ? event.clientX : event.clientY
              const size = this.props.split === 'vertical' ? width : height
              const position = this.state.position
              const newPosition = this.props.primary === 'first' ? (position - current) : (current - position)
  
              let newSize = size - newPosition
  
              if (newSize < this.props.minSize) {
                newSize = this.props.minSize
              } else {
                this.setState({
                  position: current,
                  resized: true
                })
              }
  
              if (this.props.onChange) {
                this.props.onChange(newSize)
              }
  
              this.setState({
                draggedSize: newSize
              })
  
              ref.setState({
                size: newSize
              })
            }
          }
        }
      }
    }
  
    onMouseUp () {
      document.removeEventListener('mousemove', this.onMouseMove)
  
      if (this.props.allowResize && !this.props.size) {
        if (this.state.active) {
          if (typeof this.props.onDragFinished === 'function') {
            this.props.onDragFinished()
          }
          this.setState({
            active: false
          })
        }
      }
    }
  
    unFocus () {
      if (document.selection) {
        document.selection.empty()
      } else {
        window.getSelection().removeAllRanges()
      }
    }
  
    merge (into, obj) {
      for (let attr in obj) {
        into[attr] = obj[attr]
      }
    }
  
    openWindow (opts) {
      let defaultWindowOpts = {
        directories: false,
        toolbar: false,
        titlebar: false,
        location: false,
        copyhistory: false,
        status: false,
        menubar: false,
        scrollbars: true,
        resizable: true
      }
  
      let windowOptsStr
  
      if (this.windows[opts.id] != null) {
        if (this.windows[opts.id].closed === true) {
          delete this.windows[opts.id]
        } else {
          return this.windows[opts.id]
        }
      }
  
      if (!opts.tab) {
        let windowOpts = assign({}, defaultWindowOpts, opts.windowOpts)
  
        let dualScreenLeft = window.screenLeft != null ? window.screenLeft : window.screen.left
        let dualScreenTop = window.screenTop != null ? window.screenTop : window.screen.top
  
        let width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : window.screen.width
        let height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : window.screen.height
        let windowWidth = width / 2
        let windowHeight = height / 1.3
  
        let left = ((width / 2) - (windowWidth / 2)) + dualScreenLeft
        let top = ((height / 2) - (windowHeight / 2)) + dualScreenTop
  
        windowOpts.top = top
        windowOpts.left = left
        windowOpts.width = windowWidth
        windowOpts.height = windowHeight
  
        windowOptsStr = (
          Object.keys(windowOpts)
            .map((opt) => `${opt}=${typeof windowOpts[opt] === 'boolean' ? (windowOpts[opt] ? 'yes' : 'no') : windowOpts[opt]}`)
            .join(',')
        )
      }
  
      let nWindow = window.open(
        opts.url || '',
        opts.name || '_blank',
        opts.tab ? undefined : windowOptsStr
      )
  
      this.windows[opts.id] = nWindow
  
      if (nWindow.focus) {
        nWindow.focus()
      }
  
      return nWindow
    }
  
    collapse (v, undockeable, undocked) {
      let shouldCollapseAsync
  
      shouldCollapseAsync = (this.props.onCollapsing != null) ? this.props.onCollapsing(v) : true
  
      Promise.resolve(shouldCollapseAsync).then((shouldCollapse) => {
        let ref1 = this.props.collapsable === 'first' ? this.pane2Ref.current : this.pane1Ref.current
        const ref2 = this.props.collapsable === 'first' ? this.pane1Ref.current : this.pane2Ref.current
  
        let stateToUpdate
  
        if (!shouldCollapse) {
          return
        }
  
        if (!v) {
          if (ref1) {
            ref1.setState({
              size: this.lastSize
            })
          }
  
          if (ref2) {
            ref2.setState({
              size: this.lastSize2
            })
          }
  
          stateToUpdate = {
            resized: true,
            collapsed: v,
            draggedSize: this.lastSize,
            position: this.lastSize,
            undocked: undocked
          }
  
          if (undockeable && undocked === false) {
            this.props.onDocking && this.props.onDocking()
          }
  
          this.setState(stateToUpdate, () => {
            this.props.onCollapseChange && this.props.onCollapseChange()
          })
        } else {
          if (ref1) {
            this.lastSize = ref1.state.size
          }
  
          if (ref2) {
            this.lastSize2 = ref2.state.size
          }
  
          stateToUpdate = {
            collapsed: v,
            resized: true,
            draggedSize: undefined,
            position: undefined,
            undocked: undocked
          }
  
          if (undockeable && undocked === true) {
            let windowOpts = (this.props.onUndocking != null) ? this.props.onUndocking() : null
  
            if (!windowOpts) {
              return
            }
  
            if (ref1) {
              ref1.setState({
                size: undefined
              })
            }
  
            if (ref2) {
              ref2.setState({
                size: 0
              })
            }
  
            this.setState(stateToUpdate, () => {
              // opening the window when setState is done..
              // giving it the chance to clear the previous iframe
              const nWindow = this.openWindow(windowOpts)
  
              this.props.onUndocked && this.props.onUndocked(windowOpts.id, nWindow)
  
              this.props.onCollapseChange && this.props.onCollapseChange()
            })
          } else {
            if (ref1) {
              ref1.setState({
                size: undefined
              })
            }
  
            if (ref2) {
              ref2.setState({
                size: 0
              })
            }
  
            this.setState(stateToUpdate, () => {
              this.props.onCollapseChange && this.props.onCollapseChange()
            })
          }
        }
  
        if (typeof this.props.onDragFinished === 'function') {
          this.props.onDragFinished()
        }
      })
    }
  
    cancel () {
      if (this.props.onCancel) {
        this.props.onCancel()
      }
    }
  
    renderPane (type, undockeable, pane) {
      const { collapsable } = this.props
      const { undocked } = this.state
  
      if (collapsable === type) {
        if (!undockeable) {
          return pane
        }
  
        if (undocked) {
          return null
        }
  
        return pane
      } else {
        return pane
      }
    }
  
    render () {
      const {
        split,
        allowResize,
        resizerClassName,
        collapsedText,
        collapsable,
        undockeable,
        cancellable
      } = this.props
  
      const { collapsed, undocked } = this.state
      let disabledClass = allowResize ? '' : 'disabled'
  
      let style = {
        display: 'flex',
        flex: 1,
        outline: 'none',
        overflow: 'hidden',
        MozUserSelect: 'text',
        WebkitUserSelect: 'text',
        msUserSelect: 'text',
        userSelect: 'text'
      }
  
      if (split === 'vertical') {
        this.merge(style, {
          flexDirection: 'row'
        })
      } else {
        this.merge(style, {
          flexDirection: 'column',
          width: '100%'
        })
      }
  
      const children = this.props.children
      const classes = ['SplitPane', this.props.className, split, disabledClass]
      const undockSupported = (typeof undockeable === 'function' ? undockeable() : undockeable)
      const cancelSupported = (typeof cancellable === 'function' ? cancellable() : cancellable)
  
      return (
        <div className={classes.join(' ')} style={style} ref={this.splitPaneRef}>
          {this.renderPane(
            'first',
            undockSupported,
            <Pane ref={this.pane1Ref} key='pane1' className='Pane1' split={split}>{children[0]}</Pane>
          )}
          <Resizer
            ref={this.resizerRef}
            key='resizer'
            collapsable={collapsable}
            collapsedText={collapsedText}
            className={disabledClass + ' ' + resizerClassName}
            onMouseDown={this.onMouseDown}
            collapsed={collapsed}
            split={split}
            collapse={this.collapse}
            undockeable={undockSupported}
            cancellable={cancelSupported}
            cancel={this.cancel}
            undocked={undocked}
          />
          {this.renderPane(
            'second',
            undockSupported,
            <Pane ref={this.pane2Ref} key='pane2' className='Pane2' split={split}>{children[1]}</Pane>
          )}
        </div>
      )
    }
  }
  
  export default SplitPane
  