(function ($, undefined) {

/**
 * Better Unobtrusive  javascript request for Jquery
 * https://github.com/gagoar/SrBuj
 *
 * Requires jQuery 1.7.0 or later.
 *
 * Released under the MIT license
 *
 * JSHINT
 * jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, jquery:true, indent:4, maxerr:50
 * global jQuery
 */

'use strict';

$.fn.present = function () {
    return this.length === 1 && this;
};
var SrBuj;
$.SrBuj = SrBuj = {
    version: '0.10.0',
    selector: '[data-remote][data-target]',
    notifyHeaders: {
      message  : 'X-SRBUJ-MSG',
      type     : 'X-SRBUJ-TYPE',
      side     : 'X-SRBUJ-SIDE',
      position : 'X-SRBUJ-POS',
      time     : 'X-SRBUJ-TIME',
      remove   : 'X-SRBUJ-REMOVE',
      raw      : 'X-SRBUJ-RAW'
    },
    defaults: {
        '$el': undefined,
        target: undefined,
        onError: undefined,
        wrapper: undefined,
        method: 'GET',
        modal: false,
        change: true,
        custom: false,
        replace: false,
        callback: false,
        remove: false,
        url: undefined,
        push: false,
        jqueryselector: false
    },
    changeDom: function (method, $target, data) {
        switch (method) {
        case 'POST':
            $target.append(data);
            break;
        case 'PUT':
        case 'PATCH':
            $target.replaceWith(data);
            break;
        case 'DELETE':
            $target.remove();
            break;
        default:
            $target.html(data);
        }
    },
    kindOfCallback: function (callback) {
        if (typeof callback === 'function') {
            return callback;
        } else {
            if (window[callback]) {
                return window[callback];
            } else {
                return new Function(callback);
            }
        }
    },
    getUrl: function($el){
      var url = $el.attr('href') || $el.attr('action');
      if((/^[\/#](\w)/).test(url)){
        return url
      }
    },
    needToChangeUrl: function(url){
      return !((window.document.location.origin + url) == window.document.location.href)
    },
    browserSupportsPushState: function(){
      return window.history && window.history.pushState && window.history.replaceState
    },
    getVerb: function ($el) {
        var respond_as = $el.data('respond-as'),
            dataVerb = $el.data('method'),
            replace = $el.data('replace'),
            proto = $el.attr('method');
        if (respond_as) {
            return respond_as.toUpperCase();
        } else
        if (dataVerb) {
          return dataVerb.toUpperCase();
        } else {
            if (proto) {
              return replace ? 'PUT' : proto.toUpperCase();
            }
        }
    },
    getOptions: function (el, user_options) {
        user_options = user_options || {};
        var options = {},
            $el = $(user_options.el || el).present(),
            el_options = {
                '$el': $el,
                'target': $el.data('target'),
                'method': $.SrBuj.getVerb($el),
                'onError': $el.data('error'),
                'callback': $el.data('callback'),
                'change': !($el.data('nochange') || false),
                'jqueryselector': $el.is('[data-jqueryselector]'),
                'modal': $el.is('[data-modal]'),
                'wrapper': $el.data('error'),
                'custom': $el.is('[data-custom]'),
                'replace': $el.data('replace'),
                'url': $.SrBuj.getUrl($el),
                'push': $el.is('[data-push]'),
                'remove': $el.is('[data-srbuj]')
            };
        user_options = user_options || {};
        for ( var attr in this.defaults ) {
            if ( this.defaults.hasOwnProperty(attr) ) {
                options[attr] = user_options[attr] || el_options[attr] || this.defaults[attr];
            }
        }
        return options;
    },
    success: function (e, data, status, xhr, user_options) {
      if ( xhr ){
        var notify = {};
        for ( var attr in $.SrBuj.notifyHeaders )
          if ( $.SrBuj.notifyHeaders.hasOwnProperty(attr) ) {
            notify[attr] = xhr.getResponseHeader($.SrBuj.notifyHeaders[attr]);
          }
          if (notify.message){ $.SrBuj.Util.notify(notify) }
          if (notify.remove){ $.SrBuj.Util.removeNotify() }
          if ( (/javascript/).test( xhr.getResponseHeader('Content-Type') )){
            return true;
          }
      }
      var options = $.SrBuj.getOptions(e.target, user_options),
      $target = options.jqueryselector ? $(options.target).present() : $(document.getElementById(options.target)),
      $wrapper = options.jqueryselector ? $(options.wrapper) : $(document.getElementById(options.wrapper));
      if ($target.present()) {
        e.stopPropagation();
        if (!options.custom) {
          if (options.change) {
            $.SrBuj.changeDom(options.method, $target, data);
          }
          if (options.modal) {
            if (options.wrapper) {
              $wrapper.modal('toggle');
            } else {
              $target.modal('toggle');
            }
          }
        }
        if(options.url && options.push && $.SrBuj.needToChangeUrl(options.url) && $.SrBuj.browserSupportsPushState() ){
          window.history.pushState({ SrBuj: true }, '', options.url)
        }
        if (options.callback) {
          var callback = $.SrBuj.kindOfCallback(options.callback);
          if (callback) {
            callback.apply(this, [e, data, status]);
          }
        }
        if (options.remove){
          this.remove();
        }
      }},
    fail: function (e, data, status, error_code, user_options) {
      e.stopPropagation();
      var $el = $(e.target).present(),
          error = $el.data('error'),
          jqueryselector = $el.data('jqueryselector'),
          $error = jqueryselector ? $(error) : $(document.getElementById(error));
      if (error) {
        $.SrBuj.changeDom('ERROR', $error, data.responseText);
        var notify = {};
        for (var attr in $.SrBuj.notifyHeaders)
          if ($.SrBuj.notifyHeaders.hasOwnProperty(attr)) {
            notify[attr] = data.getResponseHeader($.SrBuj.notifyHeaders[attr]);
          }
          if (notify.message){ $.SrBuj.Util.notify(notify) }
      }else {
        throw 'cant find data-error on element ' + e.target + ' maybe content_type missing on response?';
      }
    },
    bind: function (selector) {
        selector = selector || this.selector;
        $(document).on('ajax:success', selector, this.success);
        $(document).on('ajax:error', selector, this.fail);
    },
    Util: {
      notify: function (options){
      /* This function will show a growling element, with the message and attached class that was given.
       * will endure only a few seconds and its going to be removed from DOM afterwards.
       * use: $.SrBuj.Util.notify({message: 'This is Madness', type: 'info'}) this will produce
       * <s id=_growlingMsg class=info>This is Madness</s>
       */
       var options = options || {};
         if ($.SrBuj.gMsg_interval){ window.clearInterval($.SrBuj.gMsg_interval) }
         var gMsg = document.getElementById('_growlingMsg')|| document.createElement('s');
         gMsg.id = '_growlingMsg';
         if ( options.type ){
           gMsg.className = (/^(info|warning|error)$/).test( options.type ) ?
            ['alert', '-' , options.type ].join('') : options.type;
         }else{
           gMsg.className = 'alert-info';
         }
         gMsg.innerHTML = options.raw ? options.message
                                      : $.SrBuj.Util.decodeUTF8(options.message);
         $('body').append(gMsg);
         gMsg.className += [' alert', options.side || 'right', options.position ||  'bottom', 'srbuj-notify' ].join(' ').toLowerCase();
         if (options.time != -1) {
           options.time = Number(options.time) > 0 ? options.time : 2000;
           $.SrBuj.gMsg_interval = window.setInterval( $.SrBuj.Util.removeNotify, options.time );
         }
      },
      removeNotify: function(){
        $('#_growlingMsg').removeClass('srbuj-notify');
      },
      randomCode: function(size) {
        var size = !isNaN(size) && size < 12 ? size : 12
        return Math.random().toString(36).substring(4).substring(0, size)
      },
      decodeUTF8: function(message) {
        return decodeURIComponent(escape(message))
      },
      link: function (user_options){
        /* This function will create a link with options, trigger it and remove the link afterwards
         * user_options must be a hash (Obj) with key: value without the data word
         * if the hash contain more keys, these will be integrated too as data-key form. Example:
         * { target: 'modal', error: 'modal', modal: true, href: '/admin/request'}
         * this will become:
         * <a href: '/admin/request' data-remote data-srbuj data-target= 'modal' data-modal data-error= 'modal' ></a>
         * note: we add an extra attribute, in order to debug ([data-srbuj]) and recover the link that has been made from the dom that
         * if the attribute [data-srbuj] its present in any element that is handled by SrBuj response it will be removed form dom after complete the process
         * the white spaces will be removed from keys.
        */
        var user_options = user_options || {};
        $.extend(user_options, {remote: true, srbuj: true});
        if(user_options.target && user_options.href){
          var _srbujLink = document.createElement('a'),
              randomKey = $.SrBuj.Util.randomCode(6);

          _srbujLink.id = ['_srbujLink', randomKey].join('_');
          if (user_options.force_refresh) {
            var params     = { key: randomKey }
              , urlParams  = $.param(params)
              , splitedUrl = user_options.href.split(/\?.+/)
              , joinChar   = (splitedUrl.length > 1) ? '&'
                             : splitedUrl[0].match(/\?$/) ? ''
                               : '?';

            user_options.href +=  joinChar + urlParams;
          }
          _srbujLink.href = user_options.href;
              delete user_options.href;
          for (var attr in user_options) {
            if (user_options.hasOwnProperty(attr)) {
              var key = ['data', attr.replace(/\s/g, '')].join('-'),
                  value = user_options[attr];
              if( value === true ){ value = '' }
              _srbujLink.setAttribute(key, value);
            }
          }
          $('body').append(_srbujLink);
          $(_srbujLink).trigger('click');
        }else{
          throw 'not enough options given. Maybe target or href not present?'
        }
      }
    }
};

$(function () {
    $.SrBuj.bind();
});

})(jQuery);