

############################################################################################################
# ERROR                     = require 'coffeenode-stacktrace'
# njs_util                  = require 'util'
njs_path                  = require 'path'
# njs_fs                    = require 'fs'
#...........................................................................................................
OPTIONS                   = require 'coffeenode-options'
TYPES                     = require 'coffeenode-types'
TRM                       = require 'coffeenode-trm'
rpr                       = TRM.rpr.bind TRM
badge                     = 'α1/main'
log                       = TRM.get_logger 'plain',    badge
info                      = TRM.get_logger 'info',     badge
whisper                   = TRM.get_logger 'whisper',  badge
alert                     = TRM.get_logger 'alert',    badge
debug                     = TRM.get_logger 'debug',    badge
warn                      = TRM.get_logger 'warn',     badge
help                      = TRM.get_logger 'help',     badge
echo                      = TRM.echo.bind TRM
#...........................................................................................................
express                   = require 'express'
@HTTP                     = require './http'
#...........................................................................................................
app_info                  = OPTIONS.get_app_info()
### Name used to store info on the `request` object: ###
# app_key                   = app_info[ 'name' ]


#===========================================================================================================
# MIDDLEWARE
#-----------------------------------------------------------------------------------------------------------
@get_request_counter = ->
  request_count = 0
  return ( request, response, next ) =>
    request[ 'count' ] = ( request_count += 1 )
    next()

#-----------------------------------------------------------------------------------------------------------
@show_debug_info = ->
  return ( request, response, next ) =>
    log TRM.blue 'show_debug_info'
    debug 'session ID:', request[ 'sessionID' ]
    debug 'cookies:', request[ 'cookies' ]
    if ( session_cookie = request[ 'session' ]?[ 'cookie' ] )?
      debug 'session cookie:', session_cookie
    else
      whisper 'no session or no cookie in session'
    info request[ 'body' ]
    # # debug request[ 'session' ][ 'cookie' ][ 'connect' ]?[ 'sid' ]
    # debug "RQ##{request[ 'count' ]}"
    next()

#-----------------------------------------------------------------------------------------------------------
@show_sid = ( secret ) ->
  throw new Error "middleware `show_sid` must be called with the secret session key" unless secret?
  signature = require 'cookie-signature'
  prefix    = 's:'
  return ( request, response, next ) =>
    debug '©38z', request[ 'cookies' ]
    sid = request[ 'cookies' ][ 'connect.sid' ]
    if sid? then  info "client has SID", rpr signature.unsign ( sid.replace prefix, '' ), secret
    else          info "client has no SID"
    next()

#-----------------------------------------------------------------------------------------------------------
@add_request_options = ->
  ### This middleware adds a plain old dictionary to the request object as `request[ 'alpha-one' ]`; other
  middleware methods may use it to store values and add methods. ###
  return ( request, response, next ) =>
    throw new Error "app key 'A1' already present on request" if request[ 'A1' ]?
    request[ 'A1' ] = {}
    @HTTP._add_options request, response
    #.......................................................................................................
    next()

#-----------------------------------------------------------------------------------------------------------
@page_modifier = ->
  #.........................................................................................................
  return ( request, response, next ) =>
    #.......................................................................................................
    request.on 'page ready', =>
      debug "page ready"
    #.......................................................................................................
    marks = [
      'head-top'
      'head-bottom'
      'body-top'
      'body-bottom' ]
    #.......................................................................................................
    for mark in marks
      matcher     = '<!--#'.concat mark, '-->'
      method_name = 'add-to-'.concat mark
      do ( mark, matcher, method_name ) ->
        method = ( text ) ->
          replacement = if /-top$/.test method_name then matcher.concat text else text.concat matcher
          @[ 'A1' ][ 'page' ] = @[ 'A1' ][ 'page' ].replace matcher, replacement
        request[ 'A1' ][ method_name ] = method.bind request
    #.......................................................................................................
    next()

#-----------------------------------------------------------------------------------------------------------
@flash_notifications = =>
  #.........................................................................................................
  flash_messages  = []
  #.........................................................................................................
  return ( request, response, next ) =>
    #.......................................................................................................
    request.on 'page ready', =>
      response.cookie 'flash-messages', ( JSON.stringify flash_messages ), path: '*'
      flash_messages.length = 0
    #.......................................................................................................
    request[ 'A1' ][ 'flash-messages' ] = flash_messages
    request[ 'A1' ][ 'flash' ] = ( title, text ) ->
      message = [ title, text, ]
      flash_messages.push message
      # request.emit flash_key, message
    #.......................................................................................................
    next()

#-----------------------------------------------------------------------------------------------------------
@get_view_for = ( templates ) ->
  return ( name, options ) =>
    options ?= {}
    remember_location = options[ 'remember-location' ] ? yes
    #.......................................................................................................
    return ( request, response ) =>
      content_already_done  = no
      page_already_done     = no
      #.....................................................................................................
      ### TAINT code duplication; also used by @HTTP.bounce ###
      response.cookie 'comes-from', request[ 'url' ], path: '*' if remember_location
      #.....................................................................................................
      on_error = ( error ) =>
        alert error.stack
        ### TAINT should use dedicated method or static page ###
        @HTTP.server_error request, response unless response.headerSent?
        response.write "an error has occurred"
        response.end()
      #.....................................................................................................
      content_done = ( content ) =>
        log TRM.blue 'content_done'
        throw new Error "content already finished; cannot call `done()` anymore" if content_already_done
        content_already_done = yes
        if content?
          return on_error content if TYPES.isa_jserror content
          page = templates.layout request, response, content, page_done
          if page?
            TYPES.validate_isa_text page
            page_done page
        else
          page_done()
        return null
      #.....................................................................................................
      page_done = ( page ) =>
        log TRM.blue 'page_done'
        throw new Error "page already finished; cannot call `done()` anymore" if page_already_done
        page_already_done = yes
        if ( request.listeners 'page ready' ).length > 0
          request[ 'A1' ][ 'page' ] = page
          request.emit 'page ready'
          page = request[ 'A1' ][ 'page' ]
        return on_error page if TYPES.isa_jserror page
        @HTTP.write_header request, response
        # debug '©22a', response.headerSent
        response.write page if page?
        response.end()
        return null
      #.....................................................................................................
      try
        content = templates[ name ] request, response, content_done
        # debug '©4e', rpr content
        if content?
          TYPES.validate_isa_text content
          content_done content
      #.....................................................................................................
      catch error
        on_error error
      #.....................................................................................................
      return null

#-----------------------------------------------------------------------------------------------------------
@get_restrict_view_for = ( templates ) ->
  return ( condition, name ) =>
    throw new Error "argument 'condition' not yet supported" unless condition is 'user'
    view_method = ( @get_view_for templates ) name
    #.......................................................................................................
    return ( request, response, done ) =>
      if ( session = request[ 'session' ] )?
        if session[ 'user' ]?
          log TRM.blue 'restrict_view: ok'
          return view_method request, response, done
        else
          session[ 'error' ] = "Access denied!"
      log TRM.blue 'restrict_view: not ok'
      @HTTP.bounce request, response, "/login"
      @HTTP.write_header request, response
      debug '©23a', response.headerSent
      response.end()
      return null
