<commit_before>_ = require 'underscore'
$ = require 'jquery'
Bacon = require 'bacon.model'
Q = require 'q'
URI = require 'URIjs'
moment = require 'moment'
React = require 'react'
dsl = require './dsl'
modules = require './modules'
graphite_function_names = require './functions'
http = require './http'
docs = require './graphite_docs'
parser = require './graphite_parser'
Builtins = require './builtins'
Html = require './html'
Documentation = require './documentation'
Context = require './context'
Components = require './components'

class ServerError
  constructor: (@error) ->

ServerExceptionDetailsComponent = React.createClass
  render: ->
    React.DOM.div {},
      React.DOM.div {},
        React.DOM.strong {}, @props.exception.message
        if @props.exception.details?.message
          React.DOM.div {}, @props.exception.details?.message

ServerErrorComponent = React.createClass
  render: ->
    if _.isArray @props.error
      body = _.map @props.error, (exception) -> ServerExceptionDetailsComponent {exception}
    else if @props.error['unhandled-exception']
      body = ServerExceptionDetailsComponent {exception: @props.error['unhandled-exception']}

    React.DOM.div {},
      React.DOM.strong {}, 'Server Error',
        body
        Components.ToggleComponent {title: 'Details'},
          Builtins.ObjectBrowserComponent {object: @props.error, showProto: false}


server = modules.export exports, 'server', ({fn, component_fn, cmd, component_cmd, settings, doc}) ->
  functions_promise = null
  function_names = null
  server_option_names = null

  build_function_doc = (ctx, doc) ->
    FunctionDocsComponent {ctx, docs: docs.function_docs[doc.function_name]}

  build_parameter_doc = (ctx, doc) ->
    ParameterDocsComponent {ctx, docs: docs.parameter_docs[doc.parameter_name]}

  initDocs = ->
    _.each _.sortBy(function_names, _.identity), (n) ->
      d = docs.function_docs[n]
      if d?
        value = function_name: n, summary: d.signature, complete: build_function_doc
      else
        value = summary: '(undocumented)'
      Documentation.register_documentation ['server', 'functions', n], value

    _.each _.sortBy(server_option_names, _.identity), (n) ->
      d = docs.parameter_docs[n]
      if d?
        value = parameter_name: n, summary: 'A server parameter', complete: build_parameter_doc
      else
        value = summary: '(undocumented)'
      Documentation.register_documentation ['server', 'parameters', n], value

  Documentation.register_documentation ['server', 'functions'], index: true
  Documentation.register_documentation ['server', 'parameters'], index: true

  args_to_server_params = (context, args) ->
    server.args_to_params({args, default_options: context.options()}).server

  default_target_command = 'graph'

  doc 'q',
    'Escapes a metric query'
    """
    Use `q` to reference a metric name in the DSL.

    The Graphite API uses unquoted strings to specify metric names and patterns.
    The string argument to `q` will be passed directly to the API.

    For example, `sumSeries(q('twitter.*.tweetcount'))` will be sent as `sumSeries(twitter.*.tweetcount)`.
    """

  fn 'q', (ctx, targets...) ->
    for t in targets
      unless _.isString t
        throw new TypeError "#{t} is not a string"
    Context.value new dsl.type.q targets.map(String)...

  FunctionDocsComponent = React.createClass
    render: ->
      React.DOM.div {className: 'graphite-sphinx-docs'},
        React.DOM.div {className: 'tip'},
          React.DOM.code({}, @props.docs.signature)
          ' is a Graphite function. The text below was extracted from the '
          React.DOM.a {href: 'http://graphite.readthedocs.org/en/0.9.12/functions.html'}, 'Graphite documentation'
          '. Most Graphite functions are supported by the Lead server and lead.js DSL.'
        React.DOM.div dangerouslySetInnerHTML: __html: @props.docs.docs
        _.map @props.docs.examples, (example, i) =>
          Builtins.ExampleComponent value: "#{default_target_command} #{JSON.stringify example}", run: true, key: i

  ParameterDocsComponent = React.createClass
    render: ->
      React.DOM.div {className: 'graphite-sphinx-docs'},
        React.DOM.div {className: 'tip'},
          'This'
          ' is a Graphite parameter. The text below was extracted from the '
          React.DOM.a {href: 'http://graphite.readthedocs.org/en/0.9.12/render_api.html'}, 'Graphite documentation'
          '. Some Graphite parameters are supported by the '
          # TODO format
          Documentation.DocumentationLinkComponent {key: 'graphing.graph'}, 'graph'
          ' function'
        React.DOM.div {ref: 'docs'}
    componentDidMount: ->
      ctx = @props.ctx
      # TODO
      $docs = $(@refs.docs.getDOMNode()).append @props.docs
      $docs.find('a').on 'click', (e) ->
        e.preventDefault()
        href = $(this).attr 'href'
        if href[0] is '#'
          ctx.run "help 'server.parameters.#{decodeURI href[1..]}'"

  doc 'params',
    'Generates the parameters for a render API call'
    '''
    `params` interprets its arguments in the same way as [`get_data`](help:server.get_data),
    but simply returns the arguments that would be passed to the API.

    For example:
    ```
    options areaMode: 'stacked'
    object params sumSeries(q('twitter.*.tweetcount')), width: 1024, height: 768
    ```
    '''

  fn 'params', (ctx, args...) ->
    result = args_to_server_params ctx, args
    Context.value result

  component_fn 'url', 'Generates a URL for a graph image', (ctx, args...) ->
    params = args_to_server_params ctx, args
    url = server.render_url params
    React.DOM.pre {}, React.DOM.a {href: url, target: 'blank'}, url

  component_fn 'img', 'Renders a graph image', (ctx, args...) ->
    params = args_to_server_params ctx, args
    url = server.render_url params
    deferred = Q.defer()
    promise = deferred.promise.fail -> Q.reject 'Failed to load image'
    Context.AsyncComponent {promise},
      Builtins.ComponentAndError {promise},
        React.DOM.img onLoad: deferred.resolve, onError: deferred.reject, src: url
      Builtins.PromiseStatusComponent {promise, start_time: new Date}


  component_fn 'browser', 'Browse metrics using a wildcard query', (ctx, query) ->
    finder = server.context_fns.find.fn(ctx, query)._lead_context_fn_value # FIXME ew
    finder.clicks.onValue (node) =>
      if node.is_leaf
        ctx.run "q(#{JSON.stringify node.path})"
      else
        ctx.run "browser #{JSON.stringify node.path + '.*'}"
    finder.component


  component_fn 'tree', 'Generates a browsable tree of metrics', (ctx, root) ->
    server.MetricTreeComponent {root}

  FindResultsComponent = React.createClass
    render: ->
      query_parts = @props.query.split '.'
      React.DOM.ul {className: 'find-results'}, _.map @props.results, (node) =>
        text = node.path
        text += '.*' unless node.is_leaf
        node_parts = text.split '.'
        React.DOM.li {className: 'cm-string', onClick: => @props.on_click node}, _.map node_parts, (segment, i) ->
          s = segment
          s = '.' + s unless i == 0
          React.DOM.span {className: if segment == query_parts[i] then 'light' else null}, s

  fn 'find', 'Finds metrics', (ctx, query) ->
    promise = server.find(query)
    .then (r) =>
      results.set r.result
      r
    .fail (reason) =>
      Q.reject 'Find request failed'<commit_msg>add some missing keys<commit_after>_ = require 'underscore'
$ = require 'jquery'
Bacon = require 'bacon.model'
Q = require 'q'
URI = require 'URIjs'
moment = require 'moment'
React = require 'react'
dsl = require './dsl'
modules = require './modules'
graphite_function_names = require './functions'
http = require './http'
docs = require './graphite_docs'
parser = require './graphite_parser'
Builtins = require './builtins'
Html = require './html'
Documentation = require './documentation'
Context = require './context'
Components = require './components'

class ServerError
  constructor: (@error) ->

ServerExceptionDetailsComponent = React.createClass
  render: ->
    React.DOM.div {},
      React.DOM.div {},
        React.DOM.strong {}, @props.exception.message
        if @props.exception.details?.message
          React.DOM.div {}, @props.exception.details?.message

ServerErrorComponent = React.createClass
  render: ->
    if _.isArray @props.error
      body = _.map @props.error, (exception) -> ServerExceptionDetailsComponent {exception}
    else if @props.error['unhandled-exception']
      body = ServerExceptionDetailsComponent {exception: @props.error['unhandled-exception']}

    React.DOM.div {},
      React.DOM.strong {}, 'Server Error',
        body
        Components.ToggleComponent {title: 'Details'},
          Builtins.ObjectBrowserComponent {object: @props.error, showProto: false}


server = modules.export exports, 'server', ({fn, component_fn, cmd, component_cmd, settings, doc}) ->
  functions_promise = null
  function_names = null
  server_option_names = null

  build_function_doc = (ctx, doc) ->
    FunctionDocsComponent {ctx, docs: docs.function_docs[doc.function_name]}

  build_parameter_doc = (ctx, doc) ->
    ParameterDocsComponent {ctx, docs: docs.parameter_docs[doc.parameter_name]}

  initDocs = ->
    _.each _.sortBy(function_names, _.identity), (n) ->
      d = docs.function_docs[n]
      if d?
        value = function_name: n, summary: d.signature, complete: build_function_doc
      else
        value = summary: '(undocumented)'
      Documentation.register_documentation ['server', 'functions', n], value

    _.each _.sortBy(server_option_names, _.identity), (n) ->
      d = docs.parameter_docs[n]
      if d?
        value = parameter_name: n, summary: 'A server parameter', complete: build_parameter_doc
      else
        value = summary: '(undocumented)'
      Documentation.register_documentation ['server', 'parameters', n], value

  Documentation.register_documentation ['server', 'functions'], index: true
  Documentation.register_documentation ['server', 'parameters'], index: true

  args_to_server_params = (context, args) ->
    server.args_to_params({args, default_options: context.options()}).server

  default_target_command = 'graph'

  doc 'q',
    'Escapes a metric query'
    """
    Use `q` to reference a metric name in the DSL.

    The Graphite API uses unquoted strings to specify metric names and patterns.
    The string argument to `q` will be passed directly to the API.

    For example, `sumSeries(q('twitter.*.tweetcount'))` will be sent as `sumSeries(twitter.*.tweetcount)`.
    """

  fn 'q', (ctx, targets...) ->
    for t in targets
      unless _.isString t
        throw new TypeError "#{t} is not a string"
    Context.value new dsl.type.q targets.map(String)...

  FunctionDocsComponent = React.createClass
    render: ->
      React.DOM.div {className: 'graphite-sphinx-docs'},
        React.DOM.div {className: 'tip'},
          React.DOM.code({}, @props.docs.signature)
          ' is a Graphite function. The text below was extracted from the '
          React.DOM.a {href: 'http://graphite.readthedocs.org/en/0.9.12/functions.html'}, 'Graphite documentation'
          '. Most Graphite functions are supported by the Lead server and lead.js DSL.'
        React.DOM.div dangerouslySetInnerHTML: __html: @props.docs.docs
        _.map @props.docs.examples, (example, i) =>
          Builtins.ExampleComponent value: "#{default_target_command} #{JSON.stringify example}", run: true, key: i

  ParameterDocsComponent = React.createClass
    render: ->
      React.DOM.div {className: 'graphite-sphinx-docs'},
        React.DOM.div {className: 'tip'},
          'This'
          ' is a Graphite parameter. The text below was extracted from the '
          React.DOM.a {href: 'http://graphite.readthedocs.org/en/0.9.12/render_api.html'}, 'Graphite documentation'
          '. Some Graphite parameters are supported by the '
          # TODO format
          Documentation.DocumentationLinkComponent {key: 'graphing.graph'}, 'graph'
          ' function'
        React.DOM.div {ref: 'docs'}
    componentDidMount: ->
      ctx = @props.ctx
      # TODO
      $docs = $(@refs.docs.getDOMNode()).append @props.docs
      $docs.find('a').on 'click', (e) ->
        e.preventDefault()
        href = $(this).attr 'href'
        if href[0] is '#'
          ctx.run "help 'server.parameters.#{decodeURI href[1..]}'"

  doc 'params',
    'Generates the parameters for a render API call'
    '''
    `params` interprets its arguments in the same way as [`get_data`](help:server.get_data),
    but simply returns the arguments that would be passed to the API.

    For example:
    ```
    options areaMode: 'stacked'
    object params sumSeries(q('twitter.*.tweetcount')), width: 1024, height: 768
    ```
    '''

  fn 'params', (ctx, args...) ->
    result = args_to_server_params ctx, args
    Context.value result

  component_fn 'url', 'Generates a URL for a graph image', (ctx, args...) ->
    params = args_to_server_params ctx, args
    url = server.render_url params
    React.DOM.pre {}, React.DOM.a {href: url, target: 'blank'}, url

  component_fn 'img', 'Renders a graph image', (ctx, args...) ->
    params = args_to_server_params ctx, args
    url = server.render_url params
    deferred = Q.defer()
    promise = deferred.promise.fail -> Q.reject 'Failed to load image'
    Context.AsyncComponent {promise},
      Builtins.ComponentAndError {promise},
        React.DOM.img onLoad: deferred.resolve, onError: deferred.reject, src: url
      Builtins.PromiseStatusComponent {promise, start_time: new Date}


  component_fn 'browser', 'Browse metrics using a wildcard query', (ctx, query) ->
    finder = server.context_fns.find.fn(ctx, query)._lead_context_fn_value # FIXME ew
    finder.clicks.onValue (node) =>
      if node.is_leaf
        ctx.run "q(#{JSON.stringify node.path})"
      else
        ctx.run "browser #{JSON.stringify node.path + '.*'}"
    finder.component


  component_fn 'tree', 'Generates a browsable tree of metrics', (ctx, root) ->
    server.MetricTreeComponent {root}

  FindResultsComponent = React.createClass
    render: ->
      query_parts = @props.query.split '.'
      React.DOM.ul {className: 'find-results'}, _.map @props.results, (node, i) =>
        text = node.path
        text += '.*' unless node.is_leaf
        node_parts = text.split '.'
        React.DOM.li {key: i, className: 'cm-string', onClick: => @props.on_click node}, _.map node_parts, (segment, i) ->
          s = segment
          s = '.' + s unless i == 0
          React.DOM.span {key: i, className: if segment == query_parts[i] then 'light' else null}, s

  fn 'find', 'Finds metrics', (ctx, query) ->
    promise = server.find(query)
    .then (r) =>
      results.set r.result
      r
    .fail (reason) =>
      Q.reject 'Find request failed'
{'fraction_non_alphanumeric': 0.1317079723285647, 'fraction_numerical': 0.0024178924037880313, 'mean_word_length': 3.073871409028728, 'pattern_counts': {'":': 0, '<': 3, '<?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': '5727856', 'n_tokens_mistral': 4494, 'n_tokens_neox': 4417, 'n_words': 1233}