/* =========================================================
 * composer-automapper.js v0.2.1
 * =========================================================
 * Copyright 2013 Wpbakery
 *
 * Visual composer automapper for shortcodes
 * ========================================================= */
var vc_am = {
  current_form: false
};
(function ($) {
  "use strict";
  _.extend( wp.shortcode.prototype, {
    taggedString: function() {
      var text    = '[<span class="vc-preview-tag">' + this.tag + '</span>';

      _.each( this.attrs.numeric, function( value ) {
        if ( /\s/.test( value ) ) {
          text += ' <span class="vc-preview-param">"' + value + '"</span>';
        } else {
          text += ' <span class="vc-preview-param">' + value + '</span>';
        }
      });

      _.each( this.attrs.named, function( value, name ) {
        text += ' <span class="vc-preview-param">' + name + '="' + value + '"</span>';
      });

      // If the tag is marked as `single` or `self-closing`, close the
      // tag and ignore any additional content.
      if ( 'single' === this.type ) {
        return text + ']';
      } else if ( 'self-closing' === this.type ) {
        return text + ' /]';
      }

      // Complete the opening tag.
      text += ']';

      if ( this.content ) {
        text += '<span class="vc-preview-content">' + this.content + '</span>';
      }

      // Add the closing tag.
      return text + '[/<span class="vc-preview-tag">' + this.tag + '</span>]';
    }});
  wp.shortcode.atmPreview = function(options) {
    return new wp.shortcode( options ).taggedString();
  };
  var message_timer, show_message = function(text, type) {
    if(message_timer) {
      window.clearTimeout(message_timer);
      $('.vc-settings-automapper').remove();
      message_timer = false;
    }
    var $message = $('<div class="vc-atm-message updated' + (type ? ' vc-message-' + type : '') + '" style="display: none;"></div>');
    $message.text(text);
    $message.prependTo($('#vc-settings-automapper')).fadeIn(500, function(){
        var $message = $(this);
        window.setTimeout(function(){
          $message.remove();
        }, 2000);
      });
    },
    template_options = {
        evaluate:    /<#([\s\S]+?)#>/g,
        interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
        escape:      /\{\{([^\}]+?)\}\}(?!\})/g
    },
    regexp_shortcode = _.memoize(function() {
      return new RegExp( '\\[(\\[?)(\\S+)(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)' );
    }),
    to_title = function(string) {
      string = string.replace(/_|-/, ' ');
      return string.charAt(0).toUpperCase() + string.slice(1);
    };
  var request_url = window.ajaxurl + '?vc_action=automapper',
      sync_callback = function(method, model, options) {
        var data;
        if(method === 'create') {
          model.set('id', window.vc_guid());
          data = {
            vc_action: 'create',
            data: model.toJSON()
          };
        } else if(method === 'update') {
          data = {
            vc_action: 'update',
            id: model.get('id'),
            data: model.toJSON()
          };
        } else if(method === 'delete') {
          data = {
            vc_action: 'delete',
            id: model.get('id')
          };
        } else {
          data = {
            vc_action: 'read'
          };
        }
        $.ajax({
          method: 'POST',
          url: request_url,
          dataType: 'json',
          data:_.extend(data, {action: 'vc_automapper'}),
          context: this
        }).done(function(data){
            var result = model;
            if(data && method === 'read') result =  data;
            // Response
            if (result) {
              (method === 'read') && options.success(result);
            } else {
              options.error("Not found");
            }
          }).error(function(data){
          });
      };
  var ShortcodeModel = Backbone.Model.extend({
    defaults:function () {
      return {
        tag: '',
        name: '',
        category: '',
        description: '',
        params: []
      };
    },
    sync: sync_callback
  });
  var ShortcodesCollection = Backbone.Collection.extend({
    model: ShortcodeModel,
    sync: sync_callback
  });
  vc_am.shortcodes = new ShortcodesCollection;

  var ShortcodeView = Backbone.View.extend({
    tagName: 'li',
    // className: 'vc-automapper-item',
    className: 'widget',
    events: {
      'click .vc-automapper-edit-btn': 'edit',
      'click h4, widget-action': 'edit',
      'click .vc-automapper-delete-btn': 'clear'
    },
    template_html: $('#vc-automapper-item-tpl').html() || '<span>{{ tag }}</span>',
    initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.removeView)
    },
    render: function() {
      this.$el.html(_.template(this.template_html, this.model.toJSON(), template_options)).attr('data-item-id', this.model.get('id'));
      return this;
    },
    edit: function(e) {
      e && e.preventDefault();
      new EditFormView({model: this.model}).render();
    },
    clear: function(e) {
      e && e.preventDefault();
      if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete)) {
        this.model.destroy();
      }
    },
    removeView: function() {
      this.$el.remove();
    }
  });
  var FormView = Backbone.View.extend({
    render: function() {
      vc_am.current_form && vc_am.current_form.close();
      vc_am.current_form = this;
      return this;
    },
    getType: function() {
      return 'form';
    },
    validate: function(attrs) {
      var result = false;
      if(!attrs.name) {
        return window.i18nLocaleVcAutomapper.error_shortcode_name_is_required;
      }
      if (!attrs.tag || !attrs.tag.match(/^\S+$/)) {
        return window.i18nLocaleVcAutomapper.error_enter_valid_shortcode_tag;
      }
      var fields_required = ['param_name', 'heading', 'type'];
      _.each(attrs.params, function(param){
        _.each(fields_required, function(field){
          if(param[field] === '') {
            result = window.i18nLocaleVcAutomapper.error_enter_required_fields // '';
          } else if(field == 'param_name' && !param[field].match(/^[a-z0-9_]+$/g)) {
            result = window.i18nLocaleVcAutomapper.error_enter_required_fields;
          }
        }, this);
      }, this);
      return result || null;
    },
    isValid: function (data) {
      this.validationError = this.validate(data);
      return this.validationError ? false : true;
    },
    close: function(e) {
      e && e.preventDefault();
      vc_am.current_form = false;
      this.remove();
    }
  });
  var ComplexShortcodeView = Backbone.View.extend({
    _$widget_title: false,
    _$form_view: false,
    edit_view: false,
    tagName: 'li',
    className: 'widget',
    events: {
      'click .vc-automapper-edit-btn': 'edit',
      'click h4, .widget-action': 'edit'
    },
    template_html: $('#vc-automapper-item-complex-tpl').html() || '<span>{{ tag }}</span>',
    header_template_html: '<h4>{{ name }}<span class="in-widget-title"></span></h4>',
    initialize: function() {
      _.bindAll(this, 'removeEditForm');
      // this.listenTo(this.model, 'change', this.renderTitle);
      this.listenTo(this.model, 'destroy', this.removeView);
      this.model.view = this;
    },
    render: function() {
      this.$el.html(_.template(this.template_html, this.model.toJSON(), template_options)).attr('data-item-id', this.model.get('id'));
      return this;
    },
    renderTitle: function() {
      this.$widgetTitle().html(_.template(this.header_template_html, this.model.toJSON(), template_options));
    },
    edit: function(e) {
      e && e.preventDefault();
      if(this.$editForm().is(':animated')) return false;
      this.$el.addClass('vc-opened');
      if(this.edit_view) {
        this.close();
      } else {
        this.edit_view = new EditFormInnerView({model: this.model}).render();
      }
    },
    $widgetTitle: function() {
      if(!this._$widget_title) this._$widget_title = this.$el.find('.widget-title');
      return this._$widget_title;
    },
    $editForm: function() {
      if(!this._$edit_form) this._$edit_form = this.$el.find('.widget-inside');
      return this._$edit_form;
    },
    removeEditForm: function() {
      this.edit_view && this.edit_view.remove();
      this.edit_view = false;
    },
    beforeSave: function() {
      this.$el.find('#vc-atm-name').val($('#vc-atm-header-name').val());
    },
    close: function() {
      vc_am.current_form = false;
      this.$el.removeClass('vc-opened');
      this.renderTitle();
      this.$editForm().slideUp(100, this.removeEditForm);
    },
    clear: function(e) {
      e && e.preventDefault();
      this.model.destroy();
    },
    removeView: function() {
      this.remove();
    }
  });

  var AddFormView = FormView.extend({
    className: 'vc-add-form-atm',
    template_html: $('#vc-automapper-add-form-tpl').html(),
    events: {
      'click #vc-atm-parse-string': 'parseShortcode',
      'click .vc-atm-cancel': 'close'
    },
    getType: function() {
      return 'create';
    },
    render: function() {
      AddFormView.__super__.render.call(this);
      this.$el.html(_.template(this.template_html, {}, template_options));
      this.$el.insertAfter('.vc-automapper-toolbar');
      return this;
    },
    parseShortcode: function(e) {
      e && e.preventDefault && e.preventDefault();
      var string = $('#vc-atm-shortcode-string').val(), matches, data, params = [], attr;
      if(_.isEmpty(string)) return alert(window.i18nLocaleVcAutomapper.error_enter_valid_shortcode);
      matches = string.match(regexp_shortcode());
      if(!matches) return alert(window.i18nLocaleVcAutomapper.error_enter_valid_shortcode);
      attr = wp.shortcode.attrs(matches[3]);
      _.each(attr.named, function(value, key){
        params.push({param_name: key, type: "textfield", heading: to_title(key), description: 'Example: ' + value , value: value});
      }, this);
      if(matches[5]) params.push({param_name: 'content', type: "textarea", heading: 'Content', description: '', value: matches[5]});
      data = {
        tag: matches[2],
        name: to_title(matches[2]),
        category: window.i18nLocaleVcAutomapper.my_shortcodes_category,
        params: params
      };
      if(this.isValid(data)) {
        vc_am.shortcodes.create(data);
        show_message(window.i18nLocaleVcAutomapper.new_shortcode_mapped, 'success');
        // new EditFormView({model: vc_am.shortcodes.last()}).render();
        vc_am.shortcodes.last().view.edit();
      }  else {
        alert(this.validationError);
      }
    }
  });
  var EditFormView = FormView.extend({
    className: 'vc-edit-form',
    active_preview: false,
    events: {
      'click #vc-atm-save': 'save',
      'click .vc-atm-cancel': 'close',
      'click .vc-atm-delete': 'clear',
      'click #vc-atm-add-param': 'addParam',
      'click .vc-delete-param': 'deleteParam',
      'change #vc-atm-is-container': 'setContentParam',
      'keyup .vc-param-name, .vc-param-value, #vc-atm-tag': 'setPreview',
      'focus #vc-atm-tag': 'setTagFieldActive',
      'focus .vc-params input, .vc-params textarea': 'setParamFieldActive',
      'focus .vc-param.vc-content input, .vc-param.vc-content textarea': 'setContentParamFieldActive',
      'blur #vc-atm-tag, vc-param input': 'unsetFieldActive'
    },
    new: false,
    template_html: $('#vc-automapper-form-tpl').html(),
    param_template_html: $('#vc-atm-form-param-tpl').html(),
    getType: function() {
      return 'edit';
    },
    render: function() {
      EditFormView.__super__.render.call(this);
      this.$el.html(_.template(this.template_html, this.model.toJSON(), template_options));
      this.$el.insertAfter($('[data-item-id=' + this.model.id +']').hide());
      this.addAllParams();
      return this;
    },
    setTagFieldActive: function(e) {
      this.active_preview && $(this.active_preview).removeClass('vc-active');
      this.active_preview = '#vc-shortcode-preview .vc-preview-tag';
      $(this.active_preview).addClass('vc-active');
    },
    setParamFieldActive: function(e) {
      var $control = $(e.currentTarget),
          index = $control.parents('.vc-param:first').index();
      this.active_preview && $(this.active_preview).removeClass('vc-active');
      this.active_preview = '#vc-shortcode-preview .vc-preview-param:eq(' + index + ')';
      $(this.active_preview).addClass('vc-active');
    },
    setContentParamFieldActive: function(e) {
      this.active_preview && $(this.active_preview).removeClass('vc-active');
      this.active_preview = '#vc-shortcode-preview .vc-preview-content';
      $(this.active_preview).addClass('vc-active');
    },
    unsetFieldActive: function(e) {
      $(this.active_preview).removeClass('vc-active');
      this.active_preview = false;
    },
    /***
     * Escape double quotes in params value.
     * @param value
     * @return {*}
     */
    escapeParam:function (value) {
      return value.replace(/"/g, '``');
    },
    getPreview: function(data) {
      var params = data.params,
          content = false,
          params_to_string = {};
      _.each(params, function (value, key) {
        if (value.param_name !== 'content') {
          params_to_string[value.param_name] = this.escapeParam(value.value);
        } else {
          content = value.value;
        }

      }, this);

      return wp.shortcode.atmPreview({
            tag: data.tag,
            attrs: params_to_string,
            content: content,
            type: content === false ? 'single' : ''
          });
    },
    setPreview: function() {
      var data = {
        params: this.getParams(),
        tag: $('#vc-atm-tag').val()
      };
      $('#vc-shortcode-preview').html(this.getPreview(data));
      this.active_preview && $(this.active_preview).addClass('vc-active');
    },
    save: function(e) {
      e && e.preventDefault && e.preventDefault();
      this.$el.find('.vc-error').removeClass('vc-error');
      var data = {
        tag: $('#vc-atm-tag').val(),
        name: $('#vc-atm-name').val(),
        category: $('#vc-atm-category').val(),
        description: $('#vc-atm-description').val(),
        params: this.getParams()
        };
      if(this.isValid(data)) {
          this.model.save(data);
          show_message(window.i18nLocaleVcAutomapper.shortcode_updated, 'success');
        this.close();
      } else {
        alert(this.validationError);
      }
    },
    validate: function(attrs) {
      var result = false, added_param_names = {};
      if(!attrs.name) {
        $('#vc-atm-name').addClass('vc-error');
        return window.i18nLocaleVcAutomapper.error_shortcode_name_is_required;
      }
      if (!attrs.tag || !attrs.tag.match(/^\S+$/)) {
        $('#vc-atm-tag').addClass('vc-error');
        return window.i18nLocaleVcAutomapper.error_enter_valid_shortcode_tag;
      }
      var fields_required = ['param_name', 'heading', 'type'];
      _.each(attrs.params, function(param, index){
        if(param.param_name === 'content' && !$('#vc-atm-params-list [name=param_name]:eq(' + index +')').data('system')) {
          result = window.i18nLocaleVcAutomapper.error_content_param_not_manually;
          $('#vc-atm-params-list [name=param_name]:eq(' + index +')').addClass('vc-error');
          return;
        }
        if(_.isBoolean(added_param_names[param.param_name]) && added_param_names[param.param_name] == true) {
          $('#vc-atm-params-list [name=param_name]:eq(' + index +')').addClass('vc-error');
          if(!result) result = window.i18nLocaleVcAutomapper.error_param_already_exists.replace(/\%s/, param.param_name);
        }
        added_param_names[param.param_name] = true;
        _.each(fields_required, function(field){
          if(param[field] === '') {
            $('#vc-atm-params-list [name=' + field +']:eq(' + index +')').addClass('vc-error');
            if(!result) result = window.i18nLocaleVcAutomapper.error_enter_required_fields;
          } else if(field == 'param_name' && !param[field].match(/^[a-z0-9_]+$/g)) {
            $('#vc-atm-params-list [name=' + field +']:eq(' + index +')').addClass('vc-error');
            if(!result) result = window.i18nLocaleVcAutomapper.error_wrong_param_name;
          }
        }, this);
      }, this);
      return result || null;
    },
    setContentParam: function(e) {
      var $control = $(e.currentTarget);
      if($control.is(':checked')) {
          this.addParamField({type: 'textarea', heading: 'Content', description: '', param_name: 'content', value: ''});
          this.setParamSorting();
      } else {
          this.removeParamField('content');
      }
      this.setPreview();
    },
    addAllParams: function() {
      _.each(this.model.get('params'), function(param){
        this.addParamField(param);
        if(param.param_name === 'content') $('#vc-atm-is-container').prop('checked', true);
      }, this);
      this.setParamSorting();
    },
    getParams: function() {
      var params = [];
      _.each($('.vc-param'), function(param){
        var $param = $(param);
        params.push({
          param_name: $param.find('[name=param_name]').val(),
          type: $param.find('[name=type]').val(),
          description: $param.find('[name=description]').val(),
          heading: $param.find('[name=heading]').val(),
          value: $param.find('[name=value]').val()
        });
      }, this);
      return params;
    },
    addParam: function(e) {
      e && e.preventDefault();
      this.addParamField({type: '', heading: '', description: '', param_name: '', value: ''});
      this.setPreview();
    },
    removeParamField: function(name) {
      $('.vc-param-name[value="' + name + '"]').parents('.vc-param').remove();
    },
    addParamField: function(attr) {
      var $block = $('<div class="vc-param' + ( attr.param_name === 'content' ? ' vc-content' : '' ) + '"/>').appendTo('#vc-atm-params-list');
      $block.html(_.template(this.param_template_html, attr, template_options));
    },
    setParamSorting: function() {
      $('#vc-atm-params-list').sortable({
        items: '> .vc-param',
        tolerance: "pointer",
        handle: '.vc-move-param',
        update: this.setPreview,
        placeholder: "vc-sortable-placeholder"});
    },
    deleteParam: function(e) {
      var $control;
      e && e.preventDefault();
      if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete_param)) {
        $control =$(e.currentTarget);
        $control.parents('.vc-param').remove();
        this.setPreview();
      }
    },
    close: function(e) {
      e && e.preventDefault();
      this.model && $('[data-item-id=' + this.model.get('id') +']').show();
      vc_am.current_form = false;
      this.remove();
    },
    clear: function(e) {
      e && e.preventDefault();
      if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete)) {
        this.model.destroy();
        this.close();
      }
    }
  });
  var EditFormInnerView = EditFormView.extend({
    template_html: $('#vc-automapper-form-tpl').html(),
    getType: function() {
      return 'edit';
    },
    initialize: function() {
      _.bindAll(this, 'setPreview');
    },
    render: function() {
      var params, content,
          parent = this.model.view;
      params = this.model.get('params');
      EditFormView.__super__.render.call(this);
      this.$el.html(_.template(this.template_html, _.extend({shortcode_preview: this.getPreview(this.model.toJSON())}, this.model.toJSON()), template_options));
      this.$el.appendTo(parent.$editForm());
      parent.$widgetTitle().html('<span class="vc-atm-header"><input type="text" name="name" value="" id="vc-atm-header-name" class="vc-header-name"></span><span class="in-widget-title"></span>');
      $('#vc-atm-header-name').val(this.model.get('name'));
      this.addAllParams();
      parent.$editForm().slideDown();
      return this;
    },
    save: function(e) {
      e && e.preventDefault();
      this.model.view.beforeSave();
      EditFormInnerView.__super__.save.call(this);
    },
    close: function(e) {
      e && e.preventDefault();
      vc_am.current_form = false;
      this.model.view.close();
    },
    clear: function(e) {
      e && e.preventDefault();
      if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete)) {
        this.model.view.clear();
        this.remove();
      }
    }
  });
  var AppView = Backbone.View.extend({
    events: {
      'click #vc-automapper-add-btn': 'create'
    },
    className: 'vc-atm-form',
    initialize: function() {
      this.listenTo(vc_am.shortcodes, 'add', this.addOne);
      this.listenTo(vc_am.shortcodes, 'reset', this.addAll);
      this.listenTo(vc_am.shortcodes, 'all', this.render);
      this.$list = $('.vc-automapper-list');
      vc_am.shortcodes.fetch();
    },
    addAll: function(models) {
      models.each(function(model){
        this.addOne(model);
      }, this);
    },
    addOne: function(model) {
      var view = new ComplexShortcodeView({model: model});
      this.$list.append(view.render().el);
    },
    create: function(e) {
      e && e.preventDefault();
      if(!vc_am.current_form || vc_am.current_form.getType() !== 'create') {
        new AddFormView().render();
      }
    },
    render: function() {
    }
  });
  new AppView({el: $('#vc-settings-automapper')});
})(window.jQuery);