# # ajax

do (OJ = (if typeof global isnt 'undefined' and global then global else (if typeof window isnt 'undefined' then window else this)).OJ) ->

  config = {}
  
  # define a standard on success handler, write out the request stats to a table
  config.onSuccess = (opts, data, url) ->
    response = {}
    OJ.extend response, data, true
    opts.onSuccess response
    if OJ.LOG_ALL_AJAX
      OJ.console.table [
        Webservice: opts.ajaxOpts.url
        StartTime: opts.startTime
        EndTime: new Date()
      ] 
    return
  
  # define a standard on error handler, write out the request error conext to a table
  config.onError = (xmlHttpRequest, textStatus, param1, opts = OJ.object()) ->
    if textStatus isnt 'abort'
      if OJ.LOG_ALL_AJAX_ERRORS
        OJ.console.table [
          Webservice: opts.ajaxOpts.url
          Data: opts.ajaxOpts.data
          Failed: textStatus
          State: xmlHttpRequest.state()
          Status: xmlHttpRequest.status
          StatusText: xmlHttpRequest.statusText
          ReadyState: xmlHttpRequest.readyState
          ResponseText: xmlHttpRequest.responseText
        ]

      opts.onError textStatus
    return
  
  # in the case where `opts` is a string, convert it to an object
  optsFromUrl = (opts) ->
    if OJ.is.string opts
      url = opts
      opts = OJ.object()
      opts.add 'ajaxOpts', OJ.object()
      opts.ajaxOpts.add 'url', url
    opts
  
  # define a standard `exec` method to handle all request verbs. Uses the [jQuery.ajax](http://api.jquery.com/category/ajax/) API.
  # `execRequest` returns a promise represent the actual AJAX call.
  
  # - `verb` default value = 'GET'
  # - `opts` object
  # -- `opts.ajaxOpts` object for all jQuery's ajax-specific properties.
  config.execRequest = (verb = 'GET', opts) ->
    defaults =
      ajaxOpts:
        url: ''
        data: {}
        type: verb
        xhrFields:
          withCredentials: true
        dataType: 'json'
        contentType: 'application/json; charset=utf-8'
        
      onSuccess: OJ.noop
      onError: OJ.noop
      onComplete: OJ.noop
      overrideError: false
      watchGlobal: true
      useCache: false
    
    opts = optsFromUrl opts
    OJ.extend defaults, opts, true
    
    defaults.startTime = new Date()
    
    if false is OJ.is.nullOrEmpty defaults.ajaxOpts.data
      # GET requests expect queryString parameters
      if defaults.ajaxOpts.verb is 'GET'
        defaults.ajaxOpts.data = OJ.params defaults.ajaxOpts.data
      # all other requests take an object
      else
        defaults.ajaxOpts.data = OJ.serialize defaults.ajaxOpts.data
    
    getJQueryDeferred = (watchGlobal) ->
      ret = $.ajax defaults.ajaxOpts
      
      ret.done (data, textStatus, jqXHR) ->
        config.onSuccess defaults, data

      ret.fail (jqXHR, textStatus, errorText) ->
        config.onError jqXHR, textStatus, errorText, defaults
  
      ret.always (xmlHttpRequest, textStatus) ->
        defaults.onComplete xmlHttpRequest, textStatus

      OJ.async.ajaxPromise ret

    promise = getJQueryDeferred(defaults.watchGlobal)
    promise
  
  ajax = {}
  
  # ## post
  # [OJ](oj.html).ajax.post: insert a new object or init a form post
  
  # - `opts` can be an object representing the configuration of the request.
  # - `opts` can also be a string, representing the URL to hit. 
  ajax.post = (opts) ->
    config.execRequest 'POST', opts
  
  # ## get
  # [OJ](oj.html).ajax.get: get an existing object
  
  # - `opts` can be an object representing the configuration of the request.
  # - `opts` can also be a string, representing the URL to hit.
  #
  ajax.get = (opts) ->
    config.execRequest 'GET', opts

  # ## delete
  # [OJ](oj.html).ajax.delete: delete an existing object
  
  # - `opts` can be an object representing the configuration of the request.
  # - `opts` can also be a string, representing the URL to hit.
  ajax.delete = (opts) ->
    config.execRequest 'DELETE', opts

  # ## put
  # [OJ](oj.html).ajax.put: update an existing object
  
  # - `opts` can be an object representing the configuration of the request.
  # - `opts` can also be a string, representing the URL to hit.
  ajax.put = (opts) ->
    config.execRequest 'PUT', opts

  OJ.async.register 'ajax', ajax

  return
  

