<commit_before>React = require 'react'
BS = require 'react-bootstrap'

{PinnedHeaderFooterCard} = require 'openstax-react-components'
{ExerciseStore, ExerciseActions} = require '../../flux/exercise'

Icon = require '../icon'
ExerciseControls = require './exercise-controls'
ExerciseDetails  = require '../exercises/details'
ExerciseCards    = require '../exercises/cards'
ScrollSpy        = require '../scroll-spy'
Sectionizer      = require '../exercises/sectionizer'
NoExercisesFound = require './no-exercises-found'
ExerciseHelpers  = require '../../helpers/exercise'
Dialog           = require '../tutor-dialog'
CourseGroupingLabel = require '../course-grouping-label'

ExercisesDisplay = React.createClass

  propTypes:
    courseId:    React.PropTypes.string.isRequired
    sectionIds:  React.PropTypes.array
    ecosystemId: React.PropTypes.string.isRequired
    helpTooltip: React.PropTypes.string.isRequired

  getInitialState: -> {
    filter: ''
    currentView: 'cards'
    showingCardsFromDetailsView: false
  }
  componentWillMount:   -> ExerciseStore.on('change',  @update)
  componentWillUnmount: -> ExerciseStore.off('change', @update)
  update: -> @forceUpdate()


  onFilterChange: (filter) ->
    @setState({filter})

  renderControls: (exercises) ->

    sections = _.keys exercises.all.grouped

    if @props.showingDetails
      sectionizerProps =
        currentSection: @state.currentSection
        onSectionClick: @setCurrentSection

    <ExerciseControls
      filter={@state.filter}
      courseId={@props.courseId}
      currentView={@state.currentView}
      onFilterChange={@onFilterChange}
      onSectionSelect={@scrollToSection}
      onShowCardViewClick={@onShowCardViewClick}
      onShowDetailsViewClick={@onShowDetailsViewClick}
      exercises={exercises}
    >
      <ScrollSpy dataSelector='data-section' >
        <Sectionizer
          ref="sectionizer"
          {...sectionizerProps}
          nonAvailableWidth={600}
          onScreenElements={[]}
          chapter_sections={sections} />
      </ScrollSpy>
    </ExerciseControls>

  # called by sectionizer and details view
  setCurrentSection: (currentSection) ->
    @setState({currentSection})

  onShowDetailsViewClick: (ev, exercise) ->
    exercise ||= _.first ExerciseStore.get(@props.sectionIds)
    @setState(
      selectedExercise: exercise,
      currentView: 'details'
      currentSection: ExerciseStore.getChapterSectionOfExercise(@props.ecosystemId, exercise)
    )
    @props.onShowDetailsViewClick(ev, exercise)

  onShowCardViewClick: (ev, exercise) ->
    # The pinned header doesn't notice when the elements above it are unhidden
    # and will never unstick by itself.
    @refs.controls.unPin()
    @setState({currentView: 'cards', showingCardsFromDetailsView: true})
    @props.onShowCardViewClick(ev, exercise)

  renderMinimumExclusionWarning: ->
    section = <CourseGroupingLabel courseId={@props.courseId} lowercase />
    [
      <Icon key="icon" type="exclamation" />
      <div key="message" className="message">
        <p>
          Tutor needs at least 5 questions for this {section} to be
          included in spaced practice and personalized learning.
        </p>
        <p>
          If you exclude too many, your students will not get
          to practice on topics in this {section}.
        </p>
      </div>
    ]

  onExerciseToggle: (ev, exercise) ->
    isSelected = not ExerciseStore.isExerciseExcluded(exercise.id)
    if isSelected and ExerciseStore.isExcludedAtMinimum(exercise)
      Dialog.show(
        className: 'question-library-min-exercise-exclusions'
        title: '', body: @renderMinimumExclusionWarning()
        buttons: [
          <BS.Button key='exclude'
            onClick={=>
              ExerciseActions.saveExerciseExclusion(@props.courseId, exercise.id, isSelected)
              Dialog.hide()
            }>Exclude</BS.Button>

          <BS.Button key='cancel' bsStyle='primary'
            onClick={-> Dialog.hide()} bsStyle='primary'>Cancel</BS.Button>
        ]
      )
    else
      ExerciseActions.saveExerciseExclusion(@props.courseId, exercise.id, isSelected)
    @forceUpdate()

  getExerciseActions: (exercise) ->
    actions = {}
    if @getExerciseIsSelected(exercise)
      actions.include =
        message: 'ReInclude question'<commit_msg>Display count returned from store vs hard-coded "5"<commit_after>React = require 'react'
BS = require 'react-bootstrap'

{PinnedHeaderFooterCard} = require 'openstax-react-components'
{ExerciseStore, ExerciseActions} = require '../../flux/exercise'

Icon = require '../icon'
ExerciseControls = require './exercise-controls'
ExerciseDetails  = require '../exercises/details'
ExerciseCards    = require '../exercises/cards'
ScrollSpy        = require '../scroll-spy'
Sectionizer      = require '../exercises/sectionizer'
NoExercisesFound = require './no-exercises-found'
ExerciseHelpers  = require '../../helpers/exercise'
Dialog           = require '../tutor-dialog'
CourseGroupingLabel = require '../course-grouping-label'

ExercisesDisplay = React.createClass

  propTypes:
    courseId:    React.PropTypes.string.isRequired
    sectionIds:  React.PropTypes.array
    ecosystemId: React.PropTypes.string.isRequired
    helpTooltip: React.PropTypes.string.isRequired

  getInitialState: -> {
    filter: ''
    currentView: 'cards'
    showingCardsFromDetailsView: false
  }
  componentWillMount:   -> ExerciseStore.on('change',  @update)
  componentWillUnmount: -> ExerciseStore.off('change', @update)
  update: -> @forceUpdate()


  onFilterChange: (filter) ->
    @setState({filter})

  renderControls: (exercises) ->

    sections = _.keys exercises.all.grouped

    if @props.showingDetails
      sectionizerProps =
        currentSection: @state.currentSection
        onSectionClick: @setCurrentSection

    <ExerciseControls
      filter={@state.filter}
      courseId={@props.courseId}
      currentView={@state.currentView}
      onFilterChange={@onFilterChange}
      onSectionSelect={@scrollToSection}
      onShowCardViewClick={@onShowCardViewClick}
      onShowDetailsViewClick={@onShowDetailsViewClick}
      exercises={exercises}
    >
      <ScrollSpy dataSelector='data-section' >
        <Sectionizer
          ref="sectionizer"
          {...sectionizerProps}
          nonAvailableWidth={600}
          onScreenElements={[]}
          chapter_sections={sections} />
      </ScrollSpy>
    </ExerciseControls>

  # called by sectionizer and details view
  setCurrentSection: (currentSection) ->
    @setState({currentSection})

  onShowDetailsViewClick: (ev, exercise) ->
    exercise ||= _.first ExerciseStore.get(@props.sectionIds)
    @setState(
      selectedExercise: exercise,
      currentView: 'details'
      currentSection: ExerciseStore.getChapterSectionOfExercise(@props.ecosystemId, exercise)
    )
    @props.onShowDetailsViewClick(ev, exercise)

  onShowCardViewClick: (ev, exercise) ->
    # The pinned header doesn't notice when the elements above it are unhidden
    # and will never unstick by itself.
    @refs.controls.unPin()
    @setState({currentView: 'cards', showingCardsFromDetailsView: true})
    @props.onShowCardViewClick(ev, exercise)

  renderMinimumExclusionWarning: (minExerciseCount) ->
    section = <CourseGroupingLabel courseId={@props.courseId} lowercase />
    [
      <Icon key="icon" type="exclamation" />
      <div key="message" className="message">
        <p>
          Tutor needs at least {minExerciseCount} questions for this {section} to be
          included in spaced practice and personalized learning.
        </p>
        <p>
          If you exclude too many, your students will not get
          to practice on topics in this {section}.
        </p>
      </div>
    ]

  onExerciseToggle: (ev, exercise) ->
    isSelected = not ExerciseStore.isExerciseExcluded(exercise.id)
    minExerciseCount = ExerciseStore.excludedAtMinimum(exercise)
    if isSelected and minExerciseCount isnt false
      Dialog.show(
        className: 'question-library-min-exercise-exclusions'
        title: '', body: @renderMinimumExclusionWarning(minExerciseCount)
        buttons: [
          <BS.Button key='exclude'
            onClick={=>
              ExerciseActions.saveExerciseExclusion(@props.courseId, exercise.id, isSelected)
              Dialog.hide()
            }>Exclude</BS.Button>

          <BS.Button key='cancel' bsStyle='primary'
            onClick={-> Dialog.hide()} bsStyle='primary'>Cancel</BS.Button>
        ]
      )
    else
      ExerciseActions.saveExerciseExclusion(@props.courseId, exercise.id, isSelected)
    @forceUpdate()

  getExerciseActions: (exercise) ->
    actions = {}
    if @getExerciseIsSelected(exercise)
      actions.include =
        message: 'ReInclude question'
{'fraction_non_alphanumeric': 0.1131175468483816, 'fraction_numerical': 0.0009085746734809767, 'mean_word_length': 3.179401993355482, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '2005025', 'n_tokens_mistral': 2541, 'n_tokens_neox': 2476, 'n_words': 513}