<commit_before>###
context_fns: context functions collected from all modules. unbound
imported_context_fns: context_fns + the fns from all modules listed in imports
fns: imported_context_fns, bound to the scope.ctx
###

_ = require 'underscore'
Q = require  'q'
Bacon = require 'bacon.model'
React = require 'react/addons'
ContextComponents = require './contextComponents'
Components = require './components'
Builtins = require './builtins'
Modules = require './modules'

ignore = new Object

running_context_binding = null

value = (value) -> _lead_context_fn_value: value

# statement result handlers. return truthy if handled.
ignored = (ctx, object) -> object == ignore

handle_cmd = (ctx, object) ->
  if (op = object?._lead_context_fn)?
    if op.cmd_fn?
      op.cmd_fn.call null, ctx
      true
    else
      add_component ctx, React.DOM.div null,
        "Did you forget to call a function? \"#{object._lead_context_name}\" must be called with arguments."
        Builtins.help_component ctx, object
      true

handle_module = (ctx, object) ->
  if object?._lead_context_name
    add_component ctx, React.DOM.div null,
      "#{object._lead_context_name} is a module."
      Builtins.help_component ctx, object
    true

handle_using_extension = (ctx, object) ->
  handlers = collect_extension_points ctx, 'context_result_handler'
  _.find handlers, (handler) -> handler ctx, object

handle_promise = (ctx, object) ->
  if Q.isPromise object
    add_component ctx, Builtins.PromiseComponent {promise: object}

handleObservable = (ctx, object) ->
  if object instanceof Bacon.Observable
    add_component ctx, Builtins.ObservableComponent observable: object

handleComponent = (ctx, object) ->
  if React.isValidComponent object
    add_component ctx, object

handle_any_object = (ctx, object) ->
  add_component ctx, Builtins.ObjectBrowserComponent {object}
  true

# TODO make this configurable
result_handlers = [
  ignored
  handle_cmd
  handle_module
  handle_using_extension
  handle_promise
  handleObservable
  handleComponent
  handle_any_object
]

display_object = (ctx, object) ->
  for handler in result_handlers
    return if handler ctx, object

# extension point
resolve_documentation_key = (ctx, o) ->
  if name = o?._lead_context_name
    if fn = o._lead_context_fn
      [fn.module_name, fn.name]
    else
      name

collect_extension_points = (context, extension_point) ->
  Modules.collect_extension_points context.modules, extension_point

collect_context_vars = (context) ->
  module_vars = (module, name) ->
    vars = module.context_vars
    if _.isFunction vars
      vars = vars.call context
    [name, vars]

  _.object _.filter _.map(context.modules, module_vars), ([n, f]) -> f

collect_context_fns = (context) ->
  _.object _.filter _.map(context.modules, (module, name) -> [name, module.context_fns]), ([n, f]) -> f

is_run_context = (o) ->
  o?.component_list?

bind_fn_to_context = (ctx, fn) ->
  (args...) ->
    args.unshift ctx
    fn.apply ctx, args

bind_context_fns = (target, scope, fns, name_prefix='') ->
  for k, o of fns
    do (k, o) ->
      if _.isFunction o.fn
        name = "#{name_prefix}#{k}"
        wrapped_fn = ->
          o.fn.apply(null, arguments)?._lead_context_fn_value ? ignore

        bind = ->
          bound = bind_fn_to_context scope.ctx, wrapped_fn
          bound._lead_context_fn = o
          bound._lead_context_name = name
          bound
        Object.defineProperty target, k, get: bind, enumerable: true
      else
        target[k] = bind_context_fns {_lead_context_name: k}, scope, o, k + '.'

  target

find_in_scope = (ctx, name) ->
  ctx.scope[name]

AsyncComponent = React.createClass
  displayName: 'AsyncComponent'
  mixins: [ContextComponents.ContextAwareMixin]
  componentWillMount: ->
    register_promise @state.ctx, @props.promise
  componentWillUnmount: ->
    # FIXME should unregister
  render: ->
    React.DOM.div null, @props.children


ContextComponent = React.createClass
  displayName: 'ContextComponent'
  mixins: [ContextComponents.ContextRegisteringMixin]
  propTypes:
    ctx: (c) -> throw new Error("context required") unless is_run_context c['ctx']
  render: ->
    ContextLayoutComponent {ctx: @props.ctx}


ContextLayoutComponent = React.createClass
  displayName: 'ContextLayoutComponent'
  mixins: [Components.ObservableMixin]
  propTypes:
    ctx: (c) -> throw new Error("context required") unless is_run_context c['ctx']
  get_observable: (props) -> props.ctx.component_list.model
  render: ->
    children = _.map @state.value, ({key, component}) ->
      if _.isFunction(component)
        c = component()
      else
        c = component
      React.addons.cloneWithProps c, {key}
    ctx = @props.ctx
    ctx.layout _.extend {children}, ctx.layout_props


ContextOutputComponent = React.createClass
  displayName: 'ContextOutputComponent'
  mixins: [ContextComponents.ContextAwareMixin]
  render: -> ContextLayoutComponent ctx: @state.ctx


TopLevelContextComponent = React.createClass
  displayName: 'TopLevelContextComponent'
  getInitialState: ->
    # FIXME #175 props can change
    ctx = create_standalone_context @props
    {ctx}
  get_ctx: ->
    @state.ctx
  render: ->
    ContextComponents.ComponentContextComponent {children: @props.children, ctx: @state.ctx}


# the base context contains the loaded modules, and the list of modules to import into every context
create_base_context = ({module_names, imports}={}) ->
  modules = Modules.get_modules(_.union _.map(imports, (i) -> i.split('.')[0]) or [], module_names or [], ['context'])
  # TODO find a better home for repl vars
  {modules, imports, repl_vars: {}, prop_vars: {}}

importInto = (obj, target, path) ->
  segments = path.split('.')
  lastSegment = segments[segments.length - 1]
  if lastSegment = '*'
    wildcard = true
    segments.pop()
  value = _.reduce segments, ((result, key) -> result[key]), obj
  if wildcard
    _.extend target, value
  else
    target[lastSegment] = value

# the XXX context contains all the context functions and vars. basically, everything needed to support<commit_msg>error on import failure<commit_after>###
context_fns: context functions collected from all modules. unbound
imported_context_fns: context_fns + the fns from all modules listed in imports
fns: imported_context_fns, bound to the scope.ctx
###

_ = require 'underscore'
Q = require  'q'
Bacon = require 'bacon.model'
React = require 'react/addons'
ContextComponents = require './contextComponents'
Components = require './components'
Builtins = require './builtins'
Modules = require './modules'

ignore = new Object

running_context_binding = null

value = (value) -> _lead_context_fn_value: value

# statement result handlers. return truthy if handled.
ignored = (ctx, object) -> object == ignore

handle_cmd = (ctx, object) ->
  if (op = object?._lead_context_fn)?
    if op.cmd_fn?
      op.cmd_fn.call null, ctx
      true
    else
      add_component ctx, React.DOM.div null,
        "Did you forget to call a function? \"#{object._lead_context_name}\" must be called with arguments."
        Builtins.help_component ctx, object
      true

handle_module = (ctx, object) ->
  if object?._lead_context_name
    add_component ctx, React.DOM.div null,
      "#{object._lead_context_name} is a module."
      Builtins.help_component ctx, object
    true

handle_using_extension = (ctx, object) ->
  handlers = collect_extension_points ctx, 'context_result_handler'
  _.find handlers, (handler) -> handler ctx, object

handle_promise = (ctx, object) ->
  if Q.isPromise object
    add_component ctx, Builtins.PromiseComponent {promise: object}

handleObservable = (ctx, object) ->
  if object instanceof Bacon.Observable
    add_component ctx, Builtins.ObservableComponent observable: object

handleComponent = (ctx, object) ->
  if React.isValidComponent object
    add_component ctx, object

handle_any_object = (ctx, object) ->
  add_component ctx, Builtins.ObjectBrowserComponent {object}
  true

# TODO make this configurable
result_handlers = [
  ignored
  handle_cmd
  handle_module
  handle_using_extension
  handle_promise
  handleObservable
  handleComponent
  handle_any_object
]

display_object = (ctx, object) ->
  for handler in result_handlers
    return if handler ctx, object

# extension point
resolve_documentation_key = (ctx, o) ->
  if name = o?._lead_context_name
    if fn = o._lead_context_fn
      [fn.module_name, fn.name]
    else
      name

collect_extension_points = (context, extension_point) ->
  Modules.collect_extension_points context.modules, extension_point

collect_context_vars = (context) ->
  module_vars = (module, name) ->
    vars = module.context_vars
    if _.isFunction vars
      vars = vars.call context
    [name, vars ? {}]

  _.object _.filter _.map(context.modules, module_vars), ([n, f]) -> f

collect_context_fns = (context) ->
  _.object _.filter _.map(context.modules, (module, name) -> [name, module.context_fns ? {}]), ([n, f]) -> f

is_run_context = (o) ->
  o?.component_list?

bind_fn_to_context = (ctx, fn) ->
  (args...) ->
    args.unshift ctx
    fn.apply ctx, args

bind_context_fns = (target, scope, fns, name_prefix='') ->
  for k, o of fns
    do (k, o) ->
      if _.isFunction o.fn
        name = "#{name_prefix}#{k}"
        wrapped_fn = ->
          o.fn.apply(null, arguments)?._lead_context_fn_value ? ignore

        bind = ->
          bound = bind_fn_to_context scope.ctx, wrapped_fn
          bound._lead_context_fn = o
          bound._lead_context_name = name
          bound
        Object.defineProperty target, k, get: bind, enumerable: true
      else
        target[k] = bind_context_fns {_lead_context_name: k}, scope, o, k + '.'

  target

find_in_scope = (ctx, name) ->
  ctx.scope[name]

AsyncComponent = React.createClass
  displayName: 'AsyncComponent'
  mixins: [ContextComponents.ContextAwareMixin]
  componentWillMount: ->
    register_promise @state.ctx, @props.promise
  componentWillUnmount: ->
    # FIXME should unregister
  render: ->
    React.DOM.div null, @props.children


ContextComponent = React.createClass
  displayName: 'ContextComponent'
  mixins: [ContextComponents.ContextRegisteringMixin]
  propTypes:
    ctx: (c) -> throw new Error("context required") unless is_run_context c['ctx']
  render: ->
    ContextLayoutComponent {ctx: @props.ctx}


ContextLayoutComponent = React.createClass
  displayName: 'ContextLayoutComponent'
  mixins: [Components.ObservableMixin]
  propTypes:
    ctx: (c) -> throw new Error("context required") unless is_run_context c['ctx']
  get_observable: (props) -> props.ctx.component_list.model
  render: ->
    children = _.map @state.value, ({key, component}) ->
      if _.isFunction(component)
        c = component()
      else
        c = component
      React.addons.cloneWithProps c, {key}
    ctx = @props.ctx
    ctx.layout _.extend {children}, ctx.layout_props


ContextOutputComponent = React.createClass
  displayName: 'ContextOutputComponent'
  mixins: [ContextComponents.ContextAwareMixin]
  render: -> ContextLayoutComponent ctx: @state.ctx


TopLevelContextComponent = React.createClass
  displayName: 'TopLevelContextComponent'
  getInitialState: ->
    # FIXME #175 props can change
    ctx = create_standalone_context @props
    {ctx}
  get_ctx: ->
    @state.ctx
  render: ->
    ContextComponents.ComponentContextComponent {children: @props.children, ctx: @state.ctx}


# the base context contains the loaded modules, and the list of modules to import into every context
create_base_context = ({module_names, imports}={}) ->
  modules = Modules.get_modules(_.union _.map(imports, (i) -> i.split('.')[0]) or [], module_names or [], ['context'])
  # TODO find a better home for repl vars
  {modules, imports, repl_vars: {}, prop_vars: {}}

importInto = (obj, target, path) ->
  segments = path.split('.')
  lastSegment = segments[segments.length - 1]
  if lastSegment = '*'
    wildcard = true
    segments.pop()
  try
    value = _.reduce segments, ((result, key) -> result[key]), obj
  catch
    value = null
  unless value?
    throw new Error("can't import #{path}")
  if wildcard
    _.extend target, value
  else
    target[lastSegment] = value

# the XXX context contains all the context functions and vars. basically, everything needed to support
{'fraction_non_alphanumeric': 0.1086303482990988, 'fraction_numerical': 0.0008118860112040269, 'mean_word_length': 3.67298937784522, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 91, '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': '463842', 'n_tokens_mistral': 3795, 'n_tokens_neox': 3762, 'n_words': 1039}