(function($, _) {
  if (!CRM.Designer) CRM.Designer = {};

  // TODO Optimize this class
  CRM.Designer.PaletteFieldModel = CRM.Backbone.Model.extend({
    defaults: {
      /**
       * @var {string} required; a form-specific binding to an entity instance (eg 'student', 'mother')
       */
      entityName: null,

      /**
       * @var {string}
       */
      fieldName: null
    },
    initialize: function() {
    },
    getFieldSchema: function() {
      return this.getRel('ufGroupModel').getFieldSchema(this.get('entityName'), this.get('fieldName'));
    },
    getLabel: function() {
      // Note: if fieldSchema were a bit tighter, then we need to get a label from PaletteFieldModel at all
      return this.getFieldSchema().title || this.get('fieldName');
    },
    getSectionName: function() {
      // Note: if fieldSchema were a bit tighter, then we need to get a section from PaletteFieldModel at all
      return this.getFieldSchema().section || 'default';
    },
    getSection: function() {
      return this.getRel('ufGroupModel').getModelClass(this.get('entityName')).prototype.sections[this.getSectionName()];
    },
    /**
     * Add a new UFField model to a UFFieldCollection (if doing so is legal).
     * If it fails, display an alert.
     *
     * @param {int} ufGroupId
     * @param {CRM.UF.UFFieldCollection} ufFieldCollection
     * @param {Object} addOptions
     * @return {CRM.UF.UFFieldModel} or null (if the field is not addable)
     */
    addToUFCollection: function(ufFieldCollection, addOptions) {
      var name, paletteFieldModel = this;
      var ufFieldModel = paletteFieldModel.createUFFieldModel(ufFieldCollection.getRel('ufGroupModel'));
      ufFieldModel.set('uf_group_id', ufFieldCollection.uf_group_id);
      if (!ufFieldCollection.isAddable(ufFieldModel)) {
        CRM.alert(
          ts('The field "%1" is already included.', {
            1: paletteFieldModel.getLabel()
          }),
          ts('Duplicate'),
          'alert'
        );
        return null;
      }
      ufFieldCollection.add(ufFieldModel, addOptions);
      // Load metadata and set defaults
      // TODO: currently only works for custom fields
      name = this.get('fieldName').split('_');
      if (name[0] === 'custom') {
        CRM.api('custom_field', 'getsingle', {id: name[1]}, {success: function(field) {
          ufFieldModel.set(_.pick(field, 'help_pre', 'help_post', 'is_required'));
        }});
      }
      return ufFieldModel;
    },
    createUFFieldModel: function(ufGroupModel) {
      var model = new CRM.UF.UFFieldModel({
        is_active: 1,
        label: this.getLabel(),
        entity_name: this.get('entityName'),
        field_type: this.getFieldSchema().civiFieldType,
        // For some reason the 'formatting' field gets a random number appended in core so we mimic that here.
        // TODO: Why?
        field_name: this.get('fieldName') == 'formatting' ? 'formatting_' + (Math.floor(Math.random() * 8999) + 1000) : this.get('fieldName')
      });
      return model;
    }
  });

  /**
   *
   * options:
   *  - ufGroupModel: UFGroupModel
   */
  CRM.Designer.PaletteFieldCollection = CRM.Backbone.Collection.extend({
    model: CRM.Designer.PaletteFieldModel,
    initialize: function(models, options) {
      this.initializeCopyToChildrenRelation('ufGroupModel', options.ufGroupModel, models);
    },

    /**
     * Look up a palette-field
     *
     * @param entityName
     * @param fieldName
     * @return {CRM.Designer.PaletteFieldModel}
     */
    getFieldByName: function(entityName, fieldName) {
      if (fieldName.indexOf('formatting') === 0) {
        fieldName = 'formatting';
      }
      return this.find(function(paletteFieldModel) {
        return ((!entityName || paletteFieldModel.get('entityName') == entityName) && paletteFieldModel.get('fieldName') == fieldName);
      });
    },

    /**
     * Get a list of all fields, grouped into sections by "entityName+sectionName".
     *
     * @return {Object} keys are sections ("entityName+sectionName"); values are CRM.Designer.PaletteFieldModel
     */
    getFieldsByEntitySection: function() {
      // TODO cache
      var fieldsByEntitySection = this.groupBy(function(paletteFieldModel) {
        return paletteFieldModel.get('entityName') + '-' + paletteFieldModel.getSectionName();
      });
      return fieldsByEntitySection;
    }
  });
})(CRM.$, CRM._);
