<commit_before>"use strict";

import _            from 'lodash';
import React        from 'react';
import { connect }  from 'react-redux';

import { startApp }                       from '../actions/app';
import { offerAssessment, clearSnippet }  from '../actions/assessment_offered';
import assets                             from '../libs/assets';


const select = (state) => (state);

class Home extends React.Component {

  constructor(){
    super();
    this.state = {
      assessmentClicked: {},
      openIframe: false,
      isOpen: false,
      expandedBanks: new Set(),
      selectedBanks: new Set(),
      itemChecked: {},
      assessments: {}
    };
    Object.freeze(this.state);
  }

  componentWillMount() {
    let p = this.props;
    if(p.auth.authenticated && !p.application.started) {
      p.startApp(p.auth.auth_token, this.props.settings.qBankHost);
    }
  }

  onMessage(message) {
    let data = JSON.parse(message.data);
    switch(data.open_assessments_msg){
      case 'open_assessments_resize':
        let iframe = document.getElementById('openassessments_container');
        let height = data.payload.height;
        iframe.style.height = height + "px";
        break;
    }
  }

  componentDidUpdate() {
    let iframe = document.getElementById('openassessments_container');

    if(!iframe){ return; }

    window.addEventListener("message", this.onMessage, false);
    iframe.contentWindow.postMessage({
      'open_assessments_msg': 'open_assessments_size_request',
      'payload': {}
    }, '*');
  }

  gatherBreadcrumbs(breadcrumbs, banks) {
    banks.forEach((b) => {
      if(this.state.selectedBanks.has(b.id)) {
        breadcrumbs.push(
          <div className="c-breadcrumb" key={b.id}>
            <span>{b.displayName.text}</span>
            <a href="#" onClick={() => { this.onSelectBank(b, false); }}>
              <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
                <path d="M29.17 16l-5.17 5.17-5.17-5.17-2.83 2.83 5.17 5.17-5.17 5.17 2.83 2.83 5.17-5.17 5.17 5.17 2.83-2.83-5.17-5.17 5.17-5.17-2.83-2.83zm-5.17-12c-11.05 0-20 8.95-20 20s8.95 20 20 20 20-8.95 20-20-8.95-20-20-20zm0 36c-8.82 0-16-7.18-16-16s7.18-16 16-16 16 7.18 16 16-7.18 16-16 16z"/>
              </svg>
            </a>
          </div>
        );
      }
      this.gatherBreadcrumbs(breadcrumbs, b.childNodes);
    });
  }

  renderBreadcrumbs(hierarchy) {
    let breadcrumbs = [];
    this.gatherBreadcrumbs(breadcrumbs, hierarchy);
    return breadcrumbs;
  }

  onExpandBank(bank, value) {
    let expandedBanks = new Set(this.state.expandedBanks);

    if(value) {
      expandedBanks.add(bank.id);
    } else {
      this.resetExpansion(bank, expandedBanks);
    }

    this.setState({expandedBanks});
  }

  onSelectBank(bank, value) {
    let selectedBanks = new Set(this.state.selectedBanks);

    if(value) {
      selectedBanks.add(bank.id);
    } else {
      selectedBanks.delete(bank.id);
    }

    this.setState({selectedBanks});
  }

  /**
   * Clears the hierarchy selection for the given bank and all of its
   * descendants.
   */
  resetExpansion(bank, set) {
    set.delete(bank.id);
    bank.childNodes.forEach((bc) => {
      this.resetExpansion(bc, set);
    });
  }

  renderItem(bank) {
    let itemClass = "c-filter__item";
    if(bank.childNodes.length == 0){
      itemClass = itemClass + " c-filter__item--dropdown";
    }
    let expanded = this.state.expandedBanks.has(bank.id);
    let selected = this.state.selectedBanks.has(bank.id);
    let renderedChildren;
    if(expanded) {
      renderedChildren = this.renderChildren(bank.childNodes);
    }
    // TODO: Clean up the markup.
    return (
      <li key={bank.id} className={itemClass}>
        <input type="checkbox"
               checked={expanded}
               disabled={bank.childNodes.length == 0}
               onChange={(e) => this.onExpandBank(bank, e.target.checked)}/>
        <input type="checkbox"
               checked={selected}
               onChange={(e) => this.onSelectBank(bank, e.target.checked)}/>
        <span>{bank.displayName.text}</span>
        {renderedChildren}
      </li>
    );
  }

  renderChildren(children) {
    if(_.isUndefined(children)) { return; }
    return (
      <ul className="c-filter__dropdown">
        {children.map((child) => this.renderItem(child))}
      </ul>
    );
  }

  renderBankHierarchy(hierarchy) {
    if(_.isEmpty(hierarchy)) {
      return <div className="loader">{this.spinner()}</div>;
    }
    return (
      <ul className="c-filter-scroll">
        {hierarchy.map((child) => this.renderItem(child))}
      </ul>
    );
  }

  renderAssessmentList(hierarchy) {
    let assessmentList = [];
    hierarchy.forEach((bank) => {
      this.gatherAssessments(assessmentList, [], bank);
    });
    return assessmentList;
  }

  spinner(){
    return (
      <div className="c-assessment-loading">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 92 92">
          <path d="M46.1,82.3H41.9l-3.1-.3-3.8-.8-2.1-.7L31.7,80l-1.1-.5A35.7,35.7,0,0,1,21,73.7,37.8,37.8,0,0,1,7.6,49.1l-.2-2V41A32.7,32.7,0,0,1,8,36.8l.4-2.1c.1-.7.4-1.4.6-2a40.3,40.3,0,0,1,8.7-15,41,41,0,0,1,14.5-10l2.1-.8,2.1-.6a34.1,34.1,0,0,1,4.3-1L41.9,5h1.1l2.2-.2h6.3l2.2.3,2.1.4,2,.4,2,.6,2,.6,1.9.7,1.8.8a42.5,42.5,0,0,1,12.2,8.7,41.3,41.3,0,0,1,7.5,10.5l.7,1.3.5,1.3,1,2.4c.5,1.6.9,3.1,1.3,4.4l.7,3.7c.2,1.1.2,2,.3,2.8L90,46a7.5,7.5,0,1,1-15,1.2q0-.3,0-.6V44.5a17.6,17.6,0,0,0,0-1.8l-.2-2.5c-.2-.9-.4-1.9-.6-3.1l-.5-1.7-.3-.9-.4-.9a28.1,28.1,0,0,0-4.5-7.7,30.3,30.3,0,0,0-8.2-7l-1.3-.7-1.3-.7-1.4-.6-1.4-.5-1.5-.5-1.5-.4-1.4-.3-.7-.2h-.9l-1.9-.2H42a25,25,0,0,0-3.4.5l-1.7.3-1.7.5a32.8,32.8,0,0,0-12.2,6.9,33.5,33.5,0,0,0-8.2,11.8c-.2.6-.5,1.1-.7,1.7l-.5,1.7a27.4,27.4,0,0,0-.8,3.4l-.2.8v1l-.2,1.9v3.5a33.9,33.9,0,0,0,3.1,13.2A34.9,34.9,0,0,0,22.5,72a33.8,33.8,0,0,0,8.6,6.3l1,.6,1.1.4,2,.8,3.7,1.1,3,.6,2.3.3Z"/>
        </svg>
      </div>);
  }

  offerAssessment(bankId, assessment){
    this.setState({ isOpen: true,
                    assessmentClicked: assessment });
    var qBankHost = this.props.settings.qBankHost;
    this.props.offerAssessment(bankId, assessment.id, qBankHost);
  }

  gatherAssessments(assessmentList, path, bank) {
    path = path.concat([bank.displayName.text]);
    if(this.state.selectedBanks.has(bank.id)) {
      assessmentList.push(<h1>{path.join(", ")}</h1>);
      bank.assessments.forEach((a) => {
        assessmentList.push(
          <li className="c-admin-list-item">
            <a href="#" onClick={()=>{this.offerAssessment(bank.id, a);}}>{a.displayName.text}</a>
          </li>
        );
      });
    }
    bank.childNodes.forEach((b) => this.gatherAssessments(assessmentList, path, b));
  }

  iframeRender(){
    let assessOffered = this.props.assessment_offered;
    if(!_.isEmpty(assessOffered)){
      let qBankHost = this.props.settings.qBankHost ? this.props.settings.qBankHost : "https://qbank-clix-dev.mit.edu";
      let playerHost = this.props.settings.assessmentPlayerUrl; //This will need to be the instance deployed, not localhost.
      let url = encodeURI(`${playerHost}/?unlock_next=ON_CORRECT&api_url=${qBankHost}/api/v1&bank=${assessOffered.bankId}&assessment_offered_id=${assessOffered.id}#/assessment`);

      return (
        <div><commit_msg>Collapsed bank selection into bank expansion<commit_after>"use strict";

import _            from 'lodash';
import React        from 'react';
import { connect }  from 'react-redux';

import { startApp }                       from '../actions/app';
import { offerAssessment, clearSnippet }  from '../actions/assessment_offered';
import assets                             from '../libs/assets';


const select = (state) => (state);

class Home extends React.Component {

  constructor(){
    super();
    this.state = {
      assessmentClicked: {},
      openIframe: false,
      isOpen: false,
      expandedBanks: new Set(),
      itemChecked: {},
      assessments: {}
    };
    Object.freeze(this.state);
  }

  componentWillMount() {
    let p = this.props;
    if(p.auth.authenticated && !p.application.started) {
      p.startApp(p.auth.auth_token, this.props.settings.qBankHost);
    }
  }

  onMessage(message) {
    let data = JSON.parse(message.data);
    switch(data.open_assessments_msg){
      case 'open_assessments_resize':
        let iframe = document.getElementById('openassessments_container');
        let height = data.payload.height;
        iframe.style.height = height + "px";
        break;
    }
  }

  componentDidUpdate() {
    let iframe = document.getElementById('openassessments_container');

    if(!iframe){ return; }

    window.addEventListener("message", this.onMessage, false);
    iframe.contentWindow.postMessage({
      'open_assessments_msg': 'open_assessments_size_request',
      'payload': {}
    }, '*');
  }

  gatherBreadcrumbs(breadcrumbs, banks) {
    banks.forEach((b) => {
      if(this.state.expandedBanks.has(b.id)) {
        breadcrumbs.push(
          <div className="c-breadcrumb" key={b.id}>
            <span>{b.displayName.text}</span>
            <a href="#" onClick={() => { this.onExpandBank(b, false); }}>
              <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
                <path d="M29.17 16l-5.17 5.17-5.17-5.17-2.83 2.83 5.17 5.17-5.17 5.17 2.83 2.83 5.17-5.17 5.17 5.17 2.83-2.83-5.17-5.17 5.17-5.17-2.83-2.83zm-5.17-12c-11.05 0-20 8.95-20 20s8.95 20 20 20 20-8.95 20-20-8.95-20-20-20zm0 36c-8.82 0-16-7.18-16-16s7.18-16 16-16 16 7.18 16 16-7.18 16-16 16z"/>
              </svg>
            </a>
          </div>
        );
      }
      this.gatherBreadcrumbs(breadcrumbs, b.childNodes);
    });
  }

  renderBreadcrumbs(hierarchy) {
    let breadcrumbs = [];
    this.gatherBreadcrumbs(breadcrumbs, hierarchy);
    return breadcrumbs;
  }

  onExpandBank(bank, value) {
    let expandedBanks = new Set(this.state.expandedBanks);

    if(value) {
      expandedBanks.add(bank.id);
    } else {
      this.resetExpansion(bank, expandedBanks);
    }

    this.setState({expandedBanks});
  }

  /**
   * Clears the hierarchy selection for the given bank and all of its
   * descendants.
   */
  resetExpansion(bank, set) {
    set.delete(bank.id);
    bank.childNodes.forEach((bc) => {
      this.resetExpansion(bc, set);
    });
  }

  renderItem(bank) {
    let itemClass = "c-filter__item";
    if(bank.childNodes.length == 0){
      itemClass = itemClass + " c-filter__item--dropdown";
    }
    let expanded = this.state.expandedBanks.has(bank.id);
    let renderedChildren;
    if(expanded) {
      renderedChildren = this.renderChildren(bank.childNodes);
    }
    // TODO: Clean up the markup.
    return (
      <li key={bank.id} className={itemClass}>
        <input type="checkbox"
               checked={expanded}
               onChange={(e) => this.onExpandBank(bank, e.target.checked)}/>
        <span>{bank.displayName.text}</span>
        {renderedChildren}
      </li>
    );
  }

  renderChildren(children) {
    if(_.isUndefined(children)) { return; }
    return (
      <ul className="c-filter__dropdown">
        {children.map((child) => this.renderItem(child))}
      </ul>
    );
  }

  renderBankHierarchy(hierarchy) {
    if(_.isEmpty(hierarchy)) {
      return <div className="loader">{this.spinner()}</div>;
    }
    return (
      <ul className="c-filter-scroll">
        {hierarchy.map((child) => this.renderItem(child))}
      </ul>
    );
  }

  renderAssessmentList(hierarchy) {
    let assessmentList = [];
    hierarchy.forEach((bank) => {
      this.gatherAssessments(assessmentList, [], bank);
    });
    return assessmentList;
  }

  spinner(){
    return (
      <div className="c-assessment-loading">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 92 92">
          <path d="M46.1,82.3H41.9l-3.1-.3-3.8-.8-2.1-.7L31.7,80l-1.1-.5A35.7,35.7,0,0,1,21,73.7,37.8,37.8,0,0,1,7.6,49.1l-.2-2V41A32.7,32.7,0,0,1,8,36.8l.4-2.1c.1-.7.4-1.4.6-2a40.3,40.3,0,0,1,8.7-15,41,41,0,0,1,14.5-10l2.1-.8,2.1-.6a34.1,34.1,0,0,1,4.3-1L41.9,5h1.1l2.2-.2h6.3l2.2.3,2.1.4,2,.4,2,.6,2,.6,1.9.7,1.8.8a42.5,42.5,0,0,1,12.2,8.7,41.3,41.3,0,0,1,7.5,10.5l.7,1.3.5,1.3,1,2.4c.5,1.6.9,3.1,1.3,4.4l.7,3.7c.2,1.1.2,2,.3,2.8L90,46a7.5,7.5,0,1,1-15,1.2q0-.3,0-.6V44.5a17.6,17.6,0,0,0,0-1.8l-.2-2.5c-.2-.9-.4-1.9-.6-3.1l-.5-1.7-.3-.9-.4-.9a28.1,28.1,0,0,0-4.5-7.7,30.3,30.3,0,0,0-8.2-7l-1.3-.7-1.3-.7-1.4-.6-1.4-.5-1.5-.5-1.5-.4-1.4-.3-.7-.2h-.9l-1.9-.2H42a25,25,0,0,0-3.4.5l-1.7.3-1.7.5a32.8,32.8,0,0,0-12.2,6.9,33.5,33.5,0,0,0-8.2,11.8c-.2.6-.5,1.1-.7,1.7l-.5,1.7a27.4,27.4,0,0,0-.8,3.4l-.2.8v1l-.2,1.9v3.5a33.9,33.9,0,0,0,3.1,13.2A34.9,34.9,0,0,0,22.5,72a33.8,33.8,0,0,0,8.6,6.3l1,.6,1.1.4,2,.8,3.7,1.1,3,.6,2.3.3Z"/>
        </svg>
      </div>);
  }

  offerAssessment(bankId, assessment){
    this.setState({ isOpen: true,
                    assessmentClicked: assessment });
    var qBankHost = this.props.settings.qBankHost;
    this.props.offerAssessment(bankId, assessment.id, qBankHost);
  }

  gatherAssessments(assessmentList, path, bank) {
    path = path.concat([bank.displayName.text]);
    if(this.state.expandedBanks.has(bank.id)) {
      assessmentList.push(<h1>{path.join(", ")}</h1>);
      bank.assessments.forEach((a) => {
        assessmentList.push(
          <li className="c-admin-list-item">
            <a href="#" onClick={()=>{this.offerAssessment(bank.id, a);}}>{a.displayName.text}</a>
          </li>
        );
      });
    }
    bank.childNodes.forEach((b) => this.gatherAssessments(assessmentList, path, b));
  }

  iframeRender(){
    let assessOffered = this.props.assessment_offered;
    if(!_.isEmpty(assessOffered)){
      let qBankHost = this.props.settings.qBankHost ? this.props.settings.qBankHost : "https://qbank-clix-dev.mit.edu";
      let playerHost = this.props.settings.assessmentPlayerUrl; //This will need to be the instance deployed, not localhost.
      let url = encodeURI(`${playerHost}/?unlock_next=ON_CORRECT&api_url=${qBankHost}/api/v1&bank=${assessOffered.bankId}&assessment_offered_id=${assessOffered.id}#/assessment`);

      return (
        <div>
{'fraction_non_alphanumeric': 0.19265214018757493, 'fraction_numerical': 0.09117833721176222, 'mean_word_length': 2.5849342770475228, 'pattern_counts': {'":': 0, '<': 68, '<?xml version=': 0, '>': 91, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '493105', 'n_tokens_mistral': 6126, 'n_tokens_neox': 5726, 'n_words': 673}