<commit_before>_ = Tower._

# @todo Make this more like a {Tower.Model}
class Tower.NetRoute extends Tower.Class
  @store: ->
    @_store ||= []

  @byName: {}

  @create: (route) ->
    @byName[route.name] = route
    @store().push(route)

  @find: (name) ->
    @byName[name]

  @findByUrl: (url) ->
    for route in @all()
      if route.match(url)
        return route
    null

  # tmp name
  @findByControllerOptions: (options) ->
    for route in @all()
      controller  = route.controller
      success     = true

      for key, value of options
        success = controller[key] == value
        break unless success

      return route if success
      
    null

  @all: ->
    @store()

  @clear: ->
    @_store = []

  @reload: ->
    @clear()
    @draw()

  @draw: (callback) ->
    @_defaultCallback ||= callback
    callback = @_defaultCallback unless callback
    callback.apply(new Tower.NetRouteDSL(@))
    if Tower.isClient
      Tower.router = Tower.Router.create() # @todo make this more robust, it's a hack now

  @findController: (request, response, callback) ->
    routes      = Tower.Route.all()

    for route in routes
      controller = route.toController request
      break if controller

    if controller
      controller.call request, response, ->
        callback(controller)
    else
      callback(null)

    controller

  # tmp hack for client
  toControllerData: (url, params = {}) ->
    match   = @match(url)

    return null unless match
    keys    = @keys
    match   = match[1..-1]

    for capture, i in match
      key = keys[i].name

      if capture && !params[key]?
        capture = decodeURIComponent(capture)
        # need a way to convert :id to integer if it's an integer...
        try
          params[key] = JSON.parse(capture)
        catch error
          params[key] = capture

    controller      = @controller
    params.action   = controller.action if controller
    
    params

  toController: (request) ->
    match = @match(request)

    return null unless match

    method  = request.method.toLowerCase()
    keys    = @keys
    params  = _.extend({}, @defaults, request.query || {}, request.body || {})
    match   = match[1..-1]

    for capture, i in match
      key = keys[i].name

      if capture && !params[key]?
        capture = decodeURIComponent(capture)
        # need a way to convert :id to integer if it's an integer...
        try
          params[key] = if params.format == 'json' then JSON.parse(capture) else capture
        catch error
          params[key] = capture

    controller      = @controller
    params.action   = controller.action if controller
    request.params  = params

    if controller
      controller      = Tower.constant(Tower.namespaced(@controller.className)).create()
    controller

  init: (options) ->
    options     ||= options
    @path         = options.path
    @name         = options.name
    @methods      = _.map _.castArray(options.method || "GET"), (i) -> i.toUpperCase()
    @ip           = options.ip
    @defaults     = options.defaults || {}
    @constraints  = options.constraints
    @options      = options
    @controller   = options.controller
    @keys         = []
    @pattern      = @extractPattern(@path)
    @id           = @path
    @state        = options.state
    if @controller
      @id += @controller.name + @controller.action

    @_super()

  get: (name) ->
    @[name]

  match: (requestOrPath) ->
    if typeof requestOrPath == "string" then return @pattern.exec(requestOrPath)
    path    = requestOrPath.location.path

    return null unless _.indexOf(@methods, requestOrPath.method.toUpperCase()) > -1
    match = @pattern.exec(path)
    return null unless match
    return null unless @matchConstraints(requestOrPath)
    match

  matchConstraints: (request) ->
    constraints = @constraints
    
    switch typeof(constraints)
      when "object"
        for key, value of constraints
          switch typeof(value)
            when "string", "number"
              return false unless request[key] == value
            when "function", "object"
              # regexp?
              return false unless !!request.location[key].match(value)
      when "function"
        return constraints.call(request, request)
      else
        return false

    return true

  urlFor: (options = {}) ->
    result = @path
    result = result.replace(new RegExp(":#{key}\\??", "g"), value) for key, value of options
    result = result.replace(new RegExp("\\.?:\\w+\\??", "g"), "")
    result

  extractPattern: (path, caseSensitive, strict) ->
    return path if path instanceof RegExp
    self = @
    return new RegExp('^' + path + '$') if path == "/"

    path = path.replace(/(\(?)(\/)?(\.)?([:\*])(\w+)(\))?(\?)?/g, (_, open, slash, format, symbol, key, close, optional) ->
      optional = (!!optional) || (open + close == "()")
      splat    = symbol == "*"

      self.keys.push
        name:     key
        optional: !!optional
        splat:    splat

      slash   ||= ""
      result = ""
      result += slash if !optional || !splat
      result += "(?:"
      # result += slash if optional
      if format?
        result += if splat then "\\.([^.]+?)" else "\\.([^/.]+?)"
      else
        result += if splat then "/?(.+)" else "([^/\\.]+)"
      result += ")"
      result += "?" if optional

      result
    )

    new RegExp('^' + path + '$', if !!caseSensitive then '' else 'i')

Tower.Route = Tower.NetRoute

require './route/dsl'

module.exports = Tower.NetRoute
<commit_msg>removing JSON.parse altogether until there's a real need<commit_after>_ = Tower._

# @todo Make this more like a {Tower.Model}
class Tower.NetRoute extends Tower.Class
  @store: ->
    @_store ||= []

  @byName: {}

  @create: (route) ->
    @byName[route.name] = route
    @store().push(route)

  @find: (name) ->
    @byName[name]

  @findByUrl: (url) ->
    for route in @all()
      if route.match(url)
        return route
    null

  # tmp name
  @findByControllerOptions: (options) ->
    for route in @all()
      controller  = route.controller
      success     = true

      for key, value of options
        success = controller[key] == value
        break unless success

      return route if success
      
    null

  @all: ->
    @store()

  @clear: ->
    @_store = []

  @reload: ->
    @clear()
    @draw()

  @draw: (callback) ->
    @_defaultCallback ||= callback
    callback = @_defaultCallback unless callback
    callback.apply(new Tower.NetRouteDSL(@))
    if Tower.isClient
      Tower.router = Tower.Router.create() # @todo make this more robust, it's a hack now

  @findController: (request, response, callback) ->
    routes      = Tower.Route.all()

    for route in routes
      controller = route.toController request
      break if controller

    if controller
      controller.call request, response, ->
        callback(controller)
    else
      callback(null)

    controller

  # tmp hack for client
  toControllerData: (url, params = {}) ->
    match   = @match(url)

    return null unless match
    keys    = @keys
    match   = match[1..-1]

    for capture, i in match
      key = keys[i].name

      if capture && !params[key]?
        capture = decodeURIComponent(capture)
        # need a way to convert :id to integer if it's an integer...
        try
          params[key] = JSON.parse(capture)
        catch error
          params[key] = capture

    controller      = @controller
    params.action   = controller.action if controller
    
    params

  toController: (request) ->
    match = @match(request)

    return null unless match

    method  = request.method.toLowerCase()
    keys    = @keys
    params  = _.extend({}, @defaults, request.query || {}, request.body || {})
    match   = match[1..-1]

    for capture, i in match
      key = keys[i].name

      if capture && !params[key]?
        capture = decodeURIComponent(capture)
        # need a way to convert :id to integer if it's an integer...
        # try
        #   params[key] = if params.format == 'json' then JSON.parse(capture) else capture
        # catch error
        params[key] = capture

    controller      = @controller
    params.action   = controller.action if controller
    request.params  = params

    if controller
      controller      = Tower.constant(Tower.namespaced(@controller.className)).create()
    controller

  init: (options) ->
    options     ||= options
    @path         = options.path
    @name         = options.name
    @methods      = _.map _.castArray(options.method || "GET"), (i) -> i.toUpperCase()
    @ip           = options.ip
    @defaults     = options.defaults || {}
    @constraints  = options.constraints
    @options      = options
    @controller   = options.controller
    @keys         = []
    @pattern      = @extractPattern(@path)
    @id           = @path
    @state        = options.state
    if @controller
      @id += @controller.name + @controller.action

    @_super()

  get: (name) ->
    @[name]

  match: (requestOrPath) ->
    if typeof requestOrPath == "string" then return @pattern.exec(requestOrPath)
    path    = requestOrPath.location.path

    return null unless _.indexOf(@methods, requestOrPath.method.toUpperCase()) > -1
    match = @pattern.exec(path)
    return null unless match
    return null unless @matchConstraints(requestOrPath)
    match

  matchConstraints: (request) ->
    constraints = @constraints
    
    switch typeof(constraints)
      when "object"
        for key, value of constraints
          switch typeof(value)
            when "string", "number"
              return false unless request[key] == value
            when "function", "object"
              # regexp?
              return false unless !!request.location[key].match(value)
      when "function"
        return constraints.call(request, request)
      else
        return false

    return true

  urlFor: (options = {}) ->
    result = @path
    result = result.replace(new RegExp(":#{key}\\??", "g"), value) for key, value of options
    result = result.replace(new RegExp("\\.?:\\w+\\??", "g"), "")
    result

  extractPattern: (path, caseSensitive, strict) ->
    return path if path instanceof RegExp
    self = @
    return new RegExp('^' + path + '$') if path == "/"

    path = path.replace(/(\(?)(\/)?(\.)?([:\*])(\w+)(\))?(\?)?/g, (_, open, slash, format, symbol, key, close, optional) ->
      optional = (!!optional) || (open + close == "()")
      splat    = symbol == "*"

      self.keys.push
        name:     key
        optional: !!optional
        splat:    splat

      slash   ||= ""
      result = ""
      result += slash if !optional || !splat
      result += "(?:"
      # result += slash if optional
      if format?
        result += if splat then "\\.([^.]+?)" else "\\.([^/.]+?)"
      else
        result += if splat then "/?(.+)" else "([^/\\.]+)"
      result += ")"
      result += "?" if optional

      result
    )

    new RegExp('^' + path + '$', if !!caseSensitive then '' else 'i')

Tower.Route = Tower.NetRoute

require './route/dsl'

module.exports = Tower.NetRoute

{'fraction_non_alphanumeric': 0.13617212012550425, 'fraction_numerical': 0.0008964589870013447, 'mean_word_length': 2.158550396375991, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 47, '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': '7472027', 'n_tokens_mistral': 3323, 'n_tokens_neox': 3237, 'n_words': 913}