import React from 'react';
import ReactDOM from 'react-dom';

import Quill from 'quill';
import Delta from 'quill-delta';

import _ from 'lodash';

const toolbarOptions = [
  ['bold', 'italic', 'underline'],
  [{ list: 'ordered' }, { list: 'bullet' }],
  [{ script: 'sub' }, { script: 'super' }],
  [{ header: [1, 2, 3, 4, 5, 6, false] }],
  [{ color: [] }, { background: [] }],
  // [{ 'font': [] }],
  // ['blockquote', 'code-block'],
  // [{ 'header': 1 }, { 'header': 2 }],
  // [{ 'indent': '-1'}, { 'indent': '+1' }],
  // [{ 'direction': 'rtl' }],
  // [{ 'size': ['small', false, 'large', 'huge'] }],
  // [{ 'align': [] }],
  // ['clean'],
];

export default class QuillEditor extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      // Editor contents
      value: props.value,
    };

    this.theme = props.theme;
    if (!props.theme || props.theme === '') this.theme = 'snow';

    this.readOnly = true;
    if (!props.disabled || props.disabled === false) this.readOnly = false;

    this.height = props.height;
    if (!props.height || props.height === '') this.height = '230px';

    this.toolbar = (props.toolbarSymbol || []).map(x => x.name);

    this.editor = false;
    this.id = _.uniqueId('quill-editor-');

    this.getContents = this.getContents.bind(this);
    this.updateEditorValue = this.updateEditorValue.bind(this);
    this.debouncedOnChange = _.debounce(this.props.onChange.bind(this), 300);
    this.onChange = this.onChange.bind(this);
  }

  componentWillMount() {
  }

  componentDidMount() {
    this.initQuill();
  }

  componentWillReceiveProps(nextProps) {
    const nextVal = nextProps.value;
    const oldContents = this.editor ? this.getContents() : null;

    if (oldContents && nextVal &&
      !_.isEqual(nextVal.ops, oldContents.ops)) {
      this.setState({ value: nextVal });
      const sel = this.editor.getSelection();
      this.editor.setContents(nextVal);
      if (sel) this.editor.setSelection(sel);
    }
  }

  componentWillUpdate() {
    this.componentWillUnmount();
  }

  componentDidUpdate() {
    this.componentDidMount();
  }

  componentWillUnmount() {
    // Don't set the state to null, it would generate a loop.
  }

  onChange(val) {
    this.props.onChange(val);
  }

  getContents() {
    if (this.editor) return this.editor.getContents();

    return null;
  }

  updateEditorValue(contents, bounce = true) {
    this.setState({
      value: contents,
    }, bounce ? this.debouncedOnChange(contents) : this.onChange(contents));
  }

  initQuill() {
    if (!this.editor) {
      const quillEditor = ReactDOM.findDOMNode(this.refs[this.id]);

      const quillOptions = {
        modules: {
          toolbar: `#toolbar-${this.id}`,
        },
        theme: this.theme,
        readOnly: this.readOnly,
      };

      // init Quill
      this.editor = new Quill(quillEditor, quillOptions);
      const { value } = this.state;
      if (value) this.editor.setContents(value);

      // Resolve compability with Grammarly Chrome add-on
      // Fromm https://github.com/quilljs/quill/issues/574
      // let GrammarlyInline = Quill.import('blots/inline');
      // GrammarlyInline.tagName = 'G';
      // GrammarlyInline.blotName = 'grammarly-inline';
      // GrammarlyInline.className = 'gr_';
      // Quill.register({'formats/grammarly-inline': GrammarlyInline})

      this.editor.on('text-change', (delta, oldDelta, source) => {
        if (source === 'user' && this.props.onChange) {
          const contents = this.getContents();
          this.updateEditorValue(contents);
        }
      });

      const updateEditorValue = this.updateEditorValue;
      const editor = this.editor;
      const id = this.id;
      const toolbarSymbol = this.props.toolbarSymbol;

      this.toolbar.forEach((element) => {
        const selector = `#toolbar-${id} #${element}_id`;
        const btn = document.querySelector(selector);

        btn.addEventListener('click', () => {
          const range = editor.getSelection();

          if (range) {
            let contents = editor.getContents();
            let elementOps = toolbarSymbol.find(x => x.name === element).ops;
            const insertDelta = new Delta(elementOps);
            elementOps = [{ retain: range.index }].concat(elementOps);
            const elementDelta = new Delta(elementOps);
            contents = contents.compose(elementDelta);

            editor.setContents(contents);

            range.length = 0;
            range.index += insertDelta.length();
            editor.setSelection(range);

            updateEditorValue(contents, false);
          }
        });
      });
    }
  }

  renderQuillToolbarGroup() {
    if (this.theme !== 'snow') return (<span />);

    const quillToolbar = toolbarOptions.map((formatGroup, index) => {
      const groupElement = formatGroup.map((element) => {
        if (typeof element === 'string') {
          return (
            <button
              className={`ql-${element}`}
              key={`btnKey_${element}`}
            />
          );
        } else if (typeof element === 'object') {
          const elementName = Object.getOwnPropertyNames(element)[0];
          const elementValue = element[elementName];

          if (typeof elementValue === 'string') {
            return (
              <button
                className={`ql-${elementName}`}
                key={`btnKey_${elementValue}`}
                value={elementValue}
              />
            );
          } else if (Array.isArray(elementValue)) {
            const options = elementValue.map(e => <option value={e} key={`opt_${e}`} />);
            return (
              <select
                className={`ql-${elementName}`}
                key={`btnKey_${elementName}`}
              >
                {options}
              </select>
            );
          }
        }

        return (<span />);
      });

      return (
        <span
          className="ql-formats"
          key={`sp_${index}`}
        >
          {groupElement}
        </span>
      );
    });

    return quillToolbar;
  }

  renderCustomToolbar() {
    if (this.theme !== 'snow' || !this.toolbar || this.toolbar.length === 0) {
      return (<span />);
    }

    const customToolbarElement = this.toolbar.map(element => (
      <button
        className={`icon-${element}`}
        key={`${element}_key`}
        id={`${element}_id`}
        style={{ margin: '0px 3px 3px 3px' }}
      />
    ));

    return (
      <span
        className="ql-formats"
        style={{ fontSize: '25px', display: 'block', height: '35px' }}
      >
        { customToolbarElement }
      </span>
    );
  }

  render() {
    const quillToolbar = this.renderQuillToolbarGroup();

    return (
      <div>
        <div id={`toolbar-${this.id}`}>
          {quillToolbar}
          {this.renderCustomToolbar()}
        </div>
        <div
          ref={this.id}
          style={{ height: this.height }}
        />
      </div>
    );
  }
}

QuillEditor.propTypes = {
  value: React.PropTypes.object,
  toolbarSymbol: React.PropTypes.array,
  theme: React.PropTypes.string,
  height: React.PropTypes.string,
  disabled: React.PropTypes.bool,
  onChange: React.PropTypes.func
}

@@ -7249,11 +7249,152 @@
 pes.func
+,
 %0A%7D
+;%0A%0AQuillEditor.defaultProps = %7B%0A  value: %7B%7D,%0A  toolbarSymbol: %5B%5D,%0A  theme: 'snow',%0A  height: '230px',%0A  disabled: true,%0A  onChange: null,%0A%7D;
 %0A

Update QuillEditor propTypes and defaultProps