import React, { PropTypes, Component } from 'react';


const propTypes = {
  rootComponent: PropTypes.string, // string representation of dom node type to render, e.g. 'ul'
  itemComponent: PropTypes.string, // string representation of dom node type to render, e.g. 'li'
  className: PropTypes.string, // class added to top level element only
  mod: PropTypes.string, // class added to all elements
  useDragHandle: PropTypes.bool, // add a drag handle or not
  listItems: PropTypes.array.isRequired, // listItems array of objects for rendering items.
  onReorder:PropTypes.func.isRequired, //Callback for when the listItems is reordered
}

const defaultProps = {
  className:'',
  mod:'',
  rootComponent: 'div',
  itemComponent: 'div',
  useDragHandle: false,
  onReorder: function(from, to){console.log('onReorder not set.',from,to)},
};

class DragAndDropList extends Component {
  constructor(props) {
    super(props);

    this.state = {
      dropIndex:null,
      startIndex:null,
      okToDrag:true
    }

    const events = [
      'mouseDown',
      'dragStart',
      'dragEnd',
      'dragEnter',
    ].map(e => this[e] = this[e].bind(this));
  };

  mouseDown(e){
    const tgt = e.target;
    const isHandle = tgt.classList.contains('dragondrop-item-draghandle-icon');
    const isHandleParent = tgt.classList.contains('dragondrop-item-draghandle');
    this.setState({ okToDrag: (isHandle || isHandleParent) });
  };

  dragEnter(e, dropIndex){
    this.setState({dropIndex});
  };

  dragStart(e, startIndex){
    !!this.state.okToDrag ? ( this.setState({startIndex}) ) : ( e.preventDefault() );
  };

  dragEnd(e){
    const { dropIndex, startIndex } = this.state;

    this.setState({
      dropIndex:null,
      startIndex:null
    });

    if(dropIndex !== startIndex) {
      this.props.onReorder(startIndex, dropIndex);
    }
  };

  componentWillReceiveProps(newProps) {
    if(newProps.listItems !== this.state.listItems) {
      this.setState({listItems:newProps.listItems});
    }
  };

  render() {
    const { dropIndex, startIndex } = this.state;
    const { mod, className, useDragHandle, listItems } = this.props;

    const items = listItems.map((item, index) => {
      const showHover = ((dropIndex === index ) && (startIndex !== index ));
      return (
        <this.props.itemComponent
          key={index}
          draggable={true}
          onMouseDown={useDragHandle ? this.mouseDown : null}
          onDragEnd={this.dragEnd}
          onDragStart={e => this.dragStart(e, index)}
          onDragEnter={e => this.dragEnter(e, index)}
          className={`dragondrop-item ${mod} ${showHover && 'mod-dragover'}`}>
            {!!useDragHandle &&
              <div
                className={`dragondrop-item-draghandle ${mod}`}
                title={__('Drag to re-order')}
              >
                <i className={`dragondrop-item-draghandle-icon mdi mdi-drag-vertical ${mod}`} />
              </div>
            }
            { item }
        </this.props.itemComponent>
      )
    });

    return (
      <this.props.rootComponent className={`dragondrop ${className} ${mod}`}>
        {items}
      </this.props.rootComponent>
    );
  }

}
DragAndDropList.displayName = 'DragAndDropList';
DragAndDropList.propTypes = propTypes;
DragAndDropList.defaultProps = defaultProps;

export default DragAndDropList;
