/**
 * Model settings fields view
 *
 * @since 3.17.0
 * @version 4.7.0
 */
define( [], function() {

	return Backbone.View.extend( _.defaults( {

		/**
		 * DOM events
		 *
		 * @type  {Object}
		 */
		events: {
			'click .llms-settings-group-toggle': 'toggle_group',
		},

		/**
		 * Processed fields data
		 * Allows access by ID without traversing the schema
		 *
		 * @type  {Object}
		 */
		fields: {},

		/**
		 * Wrapper Tag name
		 *
		 * @type  {String}
		 */
		tagName: 'div',

		/**
		 * Get the underscore template
		 *
		 * @type  {[type]}
		 */
		template: wp.template( 'llms-settings-fields-template' ),

		/**
		 * Initialization callback func (renders the element on screen)
		 *
		 * @return   void
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		// initialize: function() {},

		/**
		 * Retrieve an array of all editor fields in all groups
		 *
		 * @return   array
		 * @since    3.17.1
		 * @version  3.17.1
		 */
		get_editor_fields: function() {
			return _.filter( this.fields, function( field ) {
				return this.is_editor_field( field.type );
			}, this );
		},

		/**
		 * Get settings group data from a model
		 *
		 * @return   {[type]}
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		get_groups: function() {

			return this.model.get_settings_fields();

		},

		/**
		 * Determine if a settings group is hidden in localStorage
		 *
		 * @param    string   group_id  id of the group
		 * @return   {Boolean}
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		is_group_hidden: function( group_id ) {

			var id = 'llms-' + this.model.get( 'type' ) + '-settings-group--' + group_id;

			if ( 'undefined' !== window.localStorage ) {
				return ( 'hidden' === window.localStorage.getItem( id ) );
			}

			return false;

		},

		/**
		 * Get the switch attribute for a field with switches
		 *
		 * @param    obj   field  field data obj
		 * @return   string
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		get_switch_attribute: function( field ) {

			return field.switch_attribute ? field.switch_attribute : field.attribute;

		},

		/**
		 * Determine if a field has a switch
		 *
		 * @param    string   type  field type string
		 * @return   {Boolean}
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		has_switch: function( type ) {
			return ( -1 !== type.indexOf( 'switch' ) );
		},

		/**
		 * Determine if a field is a default (text) field
		 *
		 * @param    string   type  field type string
		 * @return   {Boolean}
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		is_default_field: function( type ) {

			var types = [ 'audio_embed', 'datepicker', 'number', 'text', 'video_embed' ];
			return ( -1 !== types.indexOf( type.replace( 'switch-', '' ) ) );

		},

		/**
		 * Determine if a field is a WYSIWYG editor field
		 *
		 * @param    string   type  field type string
		 * @return   {Boolean}
		 * @since    3.17.1
		 * @version  3.17.1
		 */
		is_editor_field: function( type ) {

			var types = [ 'editor', 'switch-editor' ];
			return ( -1 !== types.indexOf( type.replace( 'switch-', '' ) ) );

		},

		/**
		 * Determine if a switch is enabled for a field
		 *
		 * @param    obj   field  field data object
		 * @return   {Boolean}
		 * @since    3.17.0
		 * @version  3.17.6
		 */
		is_switch_condition_met: function( field ) {

			return ( field.switch_on === this.model.get( field.switch_attribute ) );

		},

		/**
		 * Compiles the template and renders the view
		 *
		 * @return   self (for chaining)
		 * @since    3.17.0
		 * @version  3.17.1
		 */
		render: function() {

			this.$el.html( this.template( this ) );

			// if editors exist, render them
			_.each( this.get_editor_fields(), function( field ) {
				this.render_editor( field );
			}, this );

			return this;

		},

		/**
		 * Renders an editor field
		 *
		 * @since 3.17.1
		 * @since 3.37.11 Replace references to `wp.editor` with `_.getEditor()` helper.
		 *
		 * @param  {Object} field Field data object.
		 * @return {Void}
		 */
		render_editor: function( field ) {

			var self     = this,
				wpEditor = _.getEditor();

			// Exit early if there's no editor to work with.
			if ( undefined === wpEditor ) {
				console.error( 'Unable to access `wp.oldEditor` or `wp.editor`.' );
				return;
			}

			wpEditor.remove( field.id );
			field.settings.tinymce.setup = function( editor ) {

				var $ed     = $( '#' + editor.id ),
					$parent = $ed.closest( '.llms-editable-editor' ),
					$label  = $parent.find( '.llms-label' ),
					prop    = $ed.attr( 'data-attribute' )

				if ( $label.length ) {
					$label.prependTo( $parent.find( '.wp-editor-tools' ) );
				}

				// save changes to the model via Visual ed
				editor.on( 'change', function( event ) {
					self.model.set( prop, wpEditor.getContent( editor.id ) );
				} );

				// save changes via Text ed
				$ed.on( 'input', function( event ) {
					self.model.set( prop, $ed.val() );
				} );

				// trigger an input on the Text ed when quicktags buttons are clicked
				$parent.on( 'click', '.quicktags-toolbar .ed_button', function() {
					setTimeout( function() {
						$ed.trigger( 'input' );
					}, 10 );
				} );
			};

			wpEditor.initialize( field.id, field.settings );

		},

		/**
		 * Get the HTML for a select field
		 *
		 * @param    obj      options    flat or multi-dimensional options object
		 * @param    string   attribute  name of the select field's attribute
		 * @return   string
		 * @since    3.17.0
		 * @version  3.17.2
		 */
		render_select_options: function( options, attribute ) {

			var html     = '',
				selected = this.model.get( attribute );

			function option_html( label, val ) {

				return '<option value="' + val + '"' + _.selected( val, selected ) + '>' + label.substring( 0, 100 ) + ( label.length > 100 ? '...' : '' ) + '</option>';

			}

			_.each( options, function( option, index ) {

				// this will be an key:val object
				if ( 'string' === typeof option ) {
					html += option_html( option, index );
					// either option group or array of key,val objects
				} else if ( 'object' === typeof option ) {
					// option group
					if ( option.label && option.options ) {
						html += '<optgroup label="' + option.label + '">';
						html += this.render_select_options( option.options, attribute );
					} else {
						html += option_html( option.val, option.key );
					}
				}

			}, this );

			return html;

		},

		/**
		 * Setup and fill fields with default data based on field type
		 *
		 * @since 3.17.0
		 * @since 3.24.0 Unknown.
		 * @since 3.37.11 Replace reference to `wp.editor` with `_.getEditor()` helper.
		 * @since 4.7.0 Ensure `switch-number` fields are set with the `number` type attribute.
		 *
		 * @param  {Object}  orig_field  Original field as defined in the settings.
		 * @param  {Integer} field_index Index of the field in the current row.
		 * @return {Object}
		 */
		setup_field: function( orig_field, field_index ) {

			var defaults = {
				classes: [],
				id: _.uniqueId( orig_field.attribute + '_' ),
				input_type: 'text',
				label: '',
				options: {},
				placeholder: '',
				tip: '',
				tip_position: 'top-right',
				settings: {},
			};

			// check the field condition if set
			if ( orig_field.condition && false === _.bind( orig_field.condition, this.model )() ) {
				return false;
			}

			switch ( orig_field.type ) {

				case 'audio_embed':
					defaults.classes.push( 'llms-editable-audio' );
					defaults.placeholder = 'https://';
					defaults.tip         = LLMS.l10n.translate( 'Use SoundCloud or Spotify audio URLS.' );
					defaults.input_type  = 'url';
				break;

				case 'datepicker':
					defaults.classes.push( 'llms-editable-date' );
				break;

				case 'editor':
				case 'switch-editor':
					var orig_settings = orig_field.settings || {};
					defaults.settings = $.extend( true, _.getEditor().getDefaultSettings(), {
						mediaButtons: true,
						tinymce: {
							toolbar1: 'bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_adv',
							toolbar2: 'formatselect,underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',
						}
					}, orig_settings );
				break;

				case 'number':
				case 'switch-number':
					defaults.input_type = 'number';
				break;

				case 'permalink':
					defaults.label = LLMS.l10n.translate( 'Permalink' );
				break;

				case 'video_embed':
					defaults.classes.push( 'llms-editable-video' );
					defaults.placeholder = 'https://';
					defaults.tip         = LLMS.l10n.translate( 'Use YouTube, Vimeo, or Wistia video URLS.' );
					defaults.input_type  = 'url';
				break;

			}

			if ( this.has_switch( orig_field.type ) ) {
				defaults.switch_on  = 'yes';
				defaults.switch_off = 'no';
			}

			var field = _.defaults( _.deepClone( orig_field ), defaults );

			// if options is a function run it
			if ( _.isFunction( field.options ) ) {
				field.options = _.bind( field.options, this.model )();
			}

			// if it's a radio field options values can be submitted as images
			// this will transform those images into <img> html
			if ( -1 !== [ 'radio', 'switch-radio' ].indexOf( orig_field.type ) ) {

				var has_images = false;
				_.each( orig_field.options, function( val, key ) {
					if ( -1 !== val.indexOf( '.png' ) || -1 !== val.indexOf( '.jpg' ) ) {
						field.options[key] = '<span><img src="' + val + '"></span>';
						has_images         = true;
					}
				} );
				if ( has_images ) {
					field.classes.push( 'has-images' );
				}

			}

			// transform classes array to a css class string
			if ( field.classes.length ) {
				field.classes = ' ' + field.classes.join( ' ' );
			}

			this.fields[ field.id ] = field;

			return field;

		},

		/**
		 * Determine if toggling a switch select should rerender the view
		 *
		 * @param    string   field_type  field type string
		 * @return   boolean
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		should_rerender_on_toggle: function( field_type ) {

			return ( -1 !== field_type.indexOf( 'switch-' ) ) ? 'yes' : 'no';

		},

		/**
		 * Click event for toggling visibility of settings groups
		 * If localStorage is available, persist state
		 *
		 * @param    obj   event  js event object
		 * @return   void
		 * @since    3.17.0
		 * @version  3.17.0
		 */
		toggle_group: function( event ) {

			event.preventDefault();

			var $el    = $( event.currentTarget ),
				$group = $el.closest( '.llms-model-settings' );

			$group.toggleClass( 'hidden' );

			if ( 'undefined' !== window.localStorage ) {

				var id = $group.attr( 'id' );
				if ( $group.hasClass( 'hidden' ) ) {
					window.localStorage.setItem( id, 'hidden' );
				} else {
					window.localStorage.removeItem( id );
				}

			}

		},

	} ) );

} );
