/**
 * Section Repeater object
 *
 * @type {{}}
 */
EpsilonFramework.sectionRepeater.base = {
  /**
   * Deletes a section from the control
   *
   * @param index
   */
  delete: function( sectionInstance, index, control ) {
    var self = this,
        currentSettings = self.getValue( control ),
        section,
        i,
        prop;

    if ( currentSettings[ index ] ) {
      // Find the row
      section = control.sections[ index ];
      if ( section ) {

        // Remove the sections settings
        delete currentSettings[ index ];

        // Remove the sections from the rows collection
        delete control.sections[ index ];

        currentSettings = EpsilonFramework.sectionRepeater.base.cleanArray( currentSettings );
        control.sections = EpsilonFramework.sectionRepeater.base.cleanArray( control.sections );

        // Update the new setting values
        self.setValue( control, currentSettings, true );
      }
    }

    jQuery.each( control.sections, function( index, element ) {
      EpsilonFramework.sectionRepeater.base.setSectionIndex( element, index, control );
    } );

    // Remap the row numbers
    i = 1;
    for ( prop in control.sections ) {
      if ( control.sections.hasOwnProperty( prop ) && control.sections[ prop ] ) {
        self.updateLabel( control.sections[ prop ], control );
        i ++;
      }
    }

    control.currentIndex --;
  },
  /**
   * Add a new section handler
   */
  add: function( control, type, data ) {
    var self = this,
        template = _.memoize( EpsilonFramework.repeater.base.repeaterTemplate() ),
        settingValue = self.getValue( control ),
        newSectionSetting = {},
        templateData,
        newSection,
        i;

    /**
     * In case we don`t have a template, we terminate here
     */
    if ( ! template ) {
      return;
    }

    /**
     * Extend template data with what we passed in PHP
     */
    if ( 'undefined' === typeof ( control.params.sections[ type ] ) ) {
      return;
    }

    templateData = jQuery.extend( true, {}, control.params.sections[ type ].fields );

    /**
     * In case we added the row with "known" data, we need to overwrite the array
     */
    if ( data ) {
      for ( i in data ) {
        if ( data.hasOwnProperty( i ) && templateData.hasOwnProperty( i ) ) {
          templateData[ i ][ 'default' ] = data[ i ];
        }
      }
    }
    /**
     * Add an index
     *
     * @type {number}
     */
    templateData.index = control.currentIndex;
    /**
     * Render the HTML template with underscores
     */
    template = template( templateData );

    /**
     * Initiate a new ROW
     *
     * @type {*}
     */
    newSection = new EpsilonFramework.sectionRepeater.section.constructor(
        control.currentIndex,
        jQuery( template ).appendTo( control.repeaterContainer ),
        control.params.sections[ type ].id,
        control.params.sections[ type ].title,
        control
    );

    /**
     * 1. Remove row event
     */
    newSection.container.on( 'section:remove', function( e, sectionIndex ) {
      self.delete( this, sectionIndex, control );
    } );
    /**
     * 2. Update row event
     */
    newSection.container.on( 'section:update', function( e, sectionIndex, type, fieldName, element, control ) {
      self.updateField.call( e, sectionIndex, type, fieldName, element, control );
      self.updateLabel( newSection );
    } );

    /**
     * Register the new row in the control
     *
     * @type {*}
     */
    control.sections[ control.currentIndex ] = newSection;

    /**
     * Add a new "index" to the setting ( easier to render in the frontend )
     */
    for ( i in templateData ) {
      if ( templateData.hasOwnProperty( i ) ) {
        newSectionSetting[ i ] = templateData[ i ][ 'default' ];
      }
    }

    newSectionSetting.type = type;

    /**
     * Add a value to the setting
     * @type {{}}
     */
    settingValue[ control.currentIndex ] = newSectionSetting;

    if ( ! data ) {
      /**
       * Set it
       */
      self.setValue( control, settingValue );
    }

    /**
     * Update index
     */
    control.currentIndex ++;

    /**
     * Return constructor
     */
    return newSection;
  },
  /**
   * Handle the adding section button
   *
   * @private
   */
  handleAddButton: function( context ) {
    var isAddBtn,
        self = this,
        body = jQuery( 'body' );

    /**
     * Get a reference for the parent section, if we close it. we must close the Section sidebar as well
     */
    wp.customize[ 'section' ]( context.params.section, function( instance ) {
      instance.container.find( '.accordion-section-title, .customize-section-back' ).on( 'click keydown', function( event ) {
        if ( wp.customize.utils.isKeydownButNotEnterEvent( event ) ) {
          return;
        }

        /**
         * In case we left the "sections" screen, let's close all the repeatable sections
         */
        _.each( context.sections, function( sect ) {
          if ( ! sect.container.hasClass( 'minimized' ) ) {
            self.toggleMinimize( sect );
          }
        } );

        body.find( '.doubled-section-opened' ).removeClass( 'doubled-section-opened' );
      } );
    } );

    context.container.find( '.epsilon-add-new-section' ).on( 'click keydown', function( e ) {
      if ( jQuery( 'body' ).hasClass( 'adding-doubled-section' ) ) {
        return;
      }

      isAddBtn = jQuery( e.target ).is( '.epsilon-add-new-section' );

      body.toggleClass( 'adding-section' );
      if ( body.hasClass( 'adding-section' ) && ! isAddBtn ) {
        context.close();
      }
    } );
  },

  /**
   * Set the value of the customizer option
   *
   * @param instance
   * @param newValue
   */
  setValue: function( instance, newValue ) {
    instance.setting.set( [] );
    instance.setting.set( newValue );
  },

  /**
   * Get the value of the customizer option
   *
   * @param instance
   */
  getValue: function( instance ) {
    return instance.setting.get();
  },

  /**
   * Update the label of the section
   *
   * @param section
   * @param control
   */
  updateLabel: function( section, control ) {
    section.header.find( '.repeater-row-label' ).html( '<span class="repeater-index">#' + ( section.sectionIndex + 1 ) + ' - </span>' + section.label );
  },
  /**
   * Update a single field inside a row.
   * Triggered when a field has changed
   *
   * @param e Event Object
   */
  updateField: function( sectionIndex, sectionType, fieldId, element, control ) {
    var section,
        currentSettings;

    if ( ! control.sections[ sectionIndex ] ) {
      return;
    }

    if ( ! control.params.sections[ sectionType ].fields[ fieldId ] ) {
      return;
    }

    section = control.sections[ sectionIndex ];
    currentSettings = EpsilonFramework.sectionRepeater.base.getValue( control );

    element = jQuery( element );

    if ( _.isUndefined( currentSettings[ section.sectionIndex ][ fieldId ] ) ) {
      return;
    }

    switch ( control.params.sections[ sectionType ].fields[ fieldId ].type ) {
      case 'checkbox':
      case 'epsilon-toggle':
        currentSettings[ section.sectionIndex ][ fieldId ] = element.prop( 'checked' );
        break;
      default:
        currentSettings[ section.sectionIndex ][ fieldId ] = element.val();
        break;
    }

    EpsilonFramework.sectionRepeater.base.setValue( control, currentSettings, true );
  },
  /**
   * Remove a row from the instance
   *
   * @param instance
   */
  removeSection: function( instance ) {
    instance.container.slideUp( 300, function() {
      jQuery( this ).detach();
    } );
    instance.container.trigger( 'section:remove', [ instance.sectionIndex ] );
  },
  /**
   * Set section's index
   *
   * @param rowIndex
   */
  setSectionIndex: function( sectionInstance, sectionIndex, control ) {
    sectionInstance.sectionIndex = sectionIndex;
    sectionInstance.container.attr( 'data-row', sectionIndex );
    sectionInstance.container.data( 'row', sectionIndex );
    EpsilonFramework.sectionRepeater.base.updateLabel( sectionInstance, control );
  },

  /**
   * Drag and drop functionality
   * @param control
   */
  sort: function( control, data ) {
    var sections = control.repeaterContainer.find( '.repeater-row' ),
        settings = EpsilonFramework.sectionRepeater.base.getValue( control ),
        newOrder = [],
        newSections = [],
        newSettings = [];

    sections.each( function( i, element ) {
      newOrder.push( jQuery( element ).data( 'row' ) );
    } );

    jQuery.each( newOrder, function( newPosition, oldPosition ) {
      newSections[ newPosition ] = control.sections[ oldPosition ];

      EpsilonFramework.sectionRepeater.base.setSectionIndex( newSections[ newPosition ], newPosition, control );
      newSettings[ newPosition ] = settings[ oldPosition ];

    } );

    EpsilonFramework.sectionRepeater.base.reinitTexteditor( control, data.item );

    control.sections = newSections;

    EpsilonFramework.sectionRepeater.base.setValue( control, newSettings );
  },

  /**
   * Handle image uploading in a repeater field
   *
   * @param instance
   * @param container
   */
  handleImageUpload: function( instance, container ) {
    var self = this,
        setting = {},
        size,
        temp,
        input,
        image = wp.media( {
          multiple: false,
        } ).open();

    /**
     * On selection, save the data in a JSON
     */
    image.on( 'select', function() {
      input = container.find( 'input' );
      temp = image.state().get( 'selection' ).first();
      size = input.attr( 'data-size' );

      if ( 'undefined' === typeof (temp.toJSON().sizes[ size ]) ) {
        size = 'full';
      }

      setting.id = temp.id;
      setting.url = temp.toJSON().sizes[ size ].url;

      self._setImage( container, setting.url );
      input.attr( 'value', ( 'url' === input.attr( 'data-save-mode' ) ? setting.url : setting.id ) ).trigger( 'change' );

      container.find( '.actions .image-upload-remove-button' ).show();
    } );
  },

  /**
   * Handle Image Removal in a repeater field
   *
   * @param instance
   * @param container
   */
  handleImageRemoval: function( instance, container ) {
    var self = this,
        setting = {},
        thumb = container.find( '.epsilon-image' );

    if ( thumb.length ) {
      thumb.find( 'img' ).fadeOut( 200, function() {
        thumb.removeClass( 'epsilon-image' ).addClass( 'placeholder' ).html( EpsilonTranslations.selectFile );
      } );
    }

    container.find( '.actions .image-upload-remove-button' ).hide();
    container.find( 'input' ).attr( 'value', '' ).trigger( 'change' );
  },

  /**
   * Set image in the customizer option control
   *
   * @param control
   * @param image
   *
   * @access private
   */
  _setImage: function( container, image ) {
    /**
     * If we already have an image, we need to return that div, else we grab the placeholder
     *
     * @type {*}
     */
    var thumb = container.find( '.epsilon-image' ).length ? container.find( '.epsilon-image' ) : container.find( '.placeholder' );

    /**
     * We "reload" the image container
     */
    if ( thumb.length ) {
      thumb.removeClass( 'epsilon-image placeholder' ).addClass( 'epsilon-image' );
      thumb.html( '' );
      thumb.append( '<img style="display:none" src="' + image + '" />' );
      thumb.find( 'img' ).fadeIn( 200 );
    }
  },

  /**
   * Handle the icon picker field
   *
   * @param instance
   * @param container
   */
  handleIconPickerToggle: function( instance, container ) {
    container.find( '.epsilon-icon-picker-container' ).toggleClass( 'opened' );
  },

  /**
   * Handle the selection of the icon picker
   *
   * @param instance
   * @param container
   */
  handleIconPickerSelection: function( instance, clicked, container ) {
    var icon, label;

    container.find( '.epsilon-icons > i.selected' ).removeClass( 'selected' );
    icon = jQuery( clicked ).addClass( 'selected' ).attr( 'data-icon' );
    label = jQuery( clicked ).addClass( 'selected' ).attr( 'data-search' );

    container.find( '.epsilon-icon-name > i' ).removeClass().addClass( icon );
    container.find( '.epsilon-icon-name > .icon-label' ).html( label );

    /**
     * Set value
     */
    container.find( '.epsilon-icon-picker' ).attr( 'value', icon ).trigger( 'change' );
  },

  /**
   * Handle the Filtering of the icons
   *
   * @param instance
   * @param input
   * @param container
   */
  handleIconPickerFiltering: function( instance, input, container ) {
    var filter, temp,
        collection = jQuery( container ).find( '.epsilon-icons > i' );

    filter = jQuery( input ).val().toLowerCase();

    jQuery.each( collection, function() {
      temp = jQuery( this ).attr( 'data-search' ).toLowerCase();
      jQuery( this )[ temp.indexOf( filter ) !== - 1 ? 'show' : 'hide' ]();
    } );
  },

  /**
   * Remove the editor so we can add it again
   *
   * @param instance
   * @param container
   */
  reinitTexteditor: function( instance, container ) {
    var self = this,
        textarea = container.find( 'textarea' ),
        editorId;

    jQuery.each( textarea, function() {
      wp.editor.remove( jQuery( this ).attr( 'id' ) );
      wp.editor.initialize( jQuery( this ).attr( 'id' ), {
        tinymce: {
          wpautop: true,
          setup: function( editor ) {
            editor.on( 'change', function( e ) {
              editor.save();
              jQuery( editor.getElement() ).trigger( 'change' );
            } );
          }
        },
        quicktags: true
      } );
    } );
  },
  /**
   * Initiate the text editor in the repeater field
   *
   * @param instance
   * @param container
   */
  initTexteditor: function( instance, container ) {
    var textarea = container.find( 'textarea' ),
        editorId;

    jQuery.each( textarea, function() {
      editorId = jQuery( this ).attr( 'id' );
      wp.editor.initialize( editorId, {
        tinymce: {
          wpautop: true,
          setup: function( editor ) {
            editor.on( 'change', function( e ) {
              editor.save();
              jQuery( editor.getElement() ).trigger( 'change' );
            } );
          }
        },
        quicktags: true
      } );
    } );

  },

  /**
   * Toggle vizibility
   *
   * @param instance
   */
  toggleMinimize: function( instance ) {
    instance.container.find( '.repeater-row-content' ).slideToggle( 300, function() {
      instance.container.toggleClass( 'minimized' );
      instance.header.find( '.dashicons' ).toggleClass( 'dashicons-arrow-up' ).toggleClass( 'dashicons-arrow-down' );
      jQuery('body').removeClass( 'adding-section' );
      jQuery('body').removeClass( 'adding-doubled-section' );
      jQuery.each( instance.container.siblings(), function( index, element ) {
        if ( ! jQuery( element ).hasClass( 'minimized' ) ) {
          jQuery( element ).addClass( 'minimized' );
          jQuery( element ).find( '.repeater-row-content' ).slideToggle( 300, function() {
            jQuery( element ).find( 'repeater-row-header' ).addClass( 'minimized' ).find( '.dashicons' ).toggleClass( 'dashicons-arrow-up' ).toggleClass( 'dashicons-arrow-down' );
          } );
        }
      } );
    } );
  },

  /**
   * Cleans an array (undefined values), returns value
   *
   * @param actual
   * @returns {Array}
   */
  cleanArray: function( actual ) {
    var newArray = [],
        self = this;
    for ( var i = 0; i < actual.length; i ++ ) {
      if ( actual[ i ] ) {
        newArray.push( actual[ i ] );
      }
    }

    return newArray;
  },
};