
window.Treeview = React.createClass({
  getInitialState: function() {
    return {
        selectedNode: null,
        mainEvent: null
    };
  },
  componentDidMount: function() {

    // handle history
    window.onpopstate = function(event) {
      this.openLink(window.location.hash?window.location.hash.substring(1):'about.html');
    }.bind(this);

    window.onpopstate();

    // set title
    $.get('about.html').success(function(response) {
      document.title = $(response).filter('title').html();
    });

    //shortcircuit all links in the document
    document.body.onclick = function(e){
      var target = e.target;

      // if target is undefined, try the parent element as there might be elements inside of an anchor <a>
      if (typeof target == "undefined" || typeof target.target == "undefined")
      {
        target = target.parentElement;
      }

      if (target.protocol && target.protocol.indexOf('javascript') == -1 && // if it's not js (expand/collapse)
        target.target != '_blank') { // and not specifically in a new tab

        var tagType = target.tagName.toLowerCase();

        // html or img only and not an internal link (e.g. <a href="index.html#foo"/>
        if (tagType == 'img' || (tagType == 'a' && target.href.indexOf('.html') > -1 && target.href.indexOf('index.html#') == -1)) {

          this.openLink(target.getAttribute('href'));
          return false;
        }
      }
    }.bind(this);
  },
  openLink: function(href) {

    if (href) {
      history.pushState({}, "", 'index.html#' +  href);

      this.updateSelectedNode(href);

      $.get(href).success(function(response) {
        document.getElementById("main-content").innerHTML = response;
        $('html,body').scrollTop(0);

        prettyPrint();

        // have MathJax refresh after the DOM update
        MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
      });
    }

  },
  fireEvent: function(eventName) {

    this.setState({
      mainEvent: eventName
    });

    setTimeout(function() {
      this.setState({
        mainEvent: null
      });
    }.bind(this), 100);
  },
  updateSelectedNode: function(selectedNode) {
    this.setState({
      selectedNode: selectedNode
    });
  },
  render: function() {

    var childrenWithProps = React.Children.map(this.props.children, function(child) {
      return React.cloneElement(child, {
        selectedNode: this.state.selectedNode,
        openLink: this.openLink,
        mainEvent: this.state.mainEvent
      });
    }.bind(this));

    return  <div>
              <div className="treeview-action-container">
                <span className="treeview-action" onClick={this.fireEvent.bind(this, 'expandAll')}>Expand all</span>&nbsp;|&nbsp;
                <span className="treeview-action" onClick={this.fireEvent.bind(this, 'collapseAll')}>Collapse all</span>
              </div>
              <ul className="nav">
                {childrenWithProps}
              </ul>
            </div>;
  }
});

window.Treenode = React.createClass({
  getInitialState: function() {
    return {
      displayChildren: false
    };
  },
  isEqualWithoutFragment: function(selectedNode) {

    if (selectedNode) {
      // this is to remove any fragment part from the link
      var index = selectedNode.indexOf('#');

      if (index > 0) {
        selectedNode = selectedNode.substring(0, index);
      }

      return selectedNode == this.props.href;
    }

  },
  componentWillReceiveProps: function(nextProps) {

    if (nextProps.selectedNode != this.props.selectedNode &&
      this.isEqualWithoutFragment(nextProps.selectedNode) &&
      this.props.openParent) {

      this.props.openParent();
    }

    if (!this.props.mainEvent && nextProps.mainEvent ) {
      if (nextProps.mainEvent == 'collapseAll') {
        this.setState({
          displayChildren: false
        });
      }
      else if (nextProps.mainEvent == 'expandAll') {
        this.setState({
          displayChildren: true
        });
      }
    }
  },
  toggleChildren: function() {
   this.setState({
      displayChildren: !this.state.displayChildren
    });
  },
  openLink: function() {
    this.toggleChildren();
    this.props.openLink(this.props.href);
  },
  openParent: function() {
    this.setState({
      displayChildren: true
    });

    if (this.props.openParent) this.props.openParent();
  },
  render: function() {

    var expandStyle = {
      display: 'inline',
      opacity: this.props.children?'1':'0',
      cursor: this.props.children?'pointer':'default',
      textAlign: 'center',
      verticalAlign: 'top',
      width: '20px',
      padding: '0 5px'
    };

    var childrenStyle = {
      display: this.state.displayChildren?'block':'none'
    };

    var childrenWithProps = React.Children.map(this.props.children, function(child) {
      return React.cloneElement(child, {
        openParent: this.openParent,
        selectedNode: this.props.selectedNode,
        openLink: this.props.openLink,
        mainEvent: this.props.mainEvent
      });
    }.bind(this));

    var activeClass = classNames({
      'active': this.isEqualWithoutFragment(this.props.selectedNode)
    });

    return <li className="treenode-li">
              <span className={activeClass}>
                <span style={expandStyle} onClick={this.toggleChildren}>{this.state.displayChildren?'▼':'►'}</span>
                <span className="treenode-label" onClick={this.openLink} title={this.props.label}>{this.props.label}</span>
             </span>

            <ul className="nav" style={childrenStyle}>
              { childrenWithProps }
            </ul>
          </li>;

  }
});
