/* jshint onevar: false, smarttabs: true, devel: true */
/* global VideoPressAdminSettings, setUserSetting, JSON */

/**
 * VideoPress Admin
 *
 * @todo i18n
 */
(function($) {
	var media = wp.media;
	var VideoPress = VideoPress || {};

	VideoPress.caps = VideoPressAdminSettings.caps;
	VideoPress.l10n = VideoPressAdminSettings.l10n;

	/**
	 * Create a new controller that simply adds a videopress key
	 * to the library query
	 */
	media.controller.VideoPress = media.controller.Library.extend({
		defaults: _.defaults({
			id:         'videopress',
			router:     'videopress',
			toolbar:    'videopress-toolbar',
			title:      'VideoPress',
			priority:   200,
			searchable: true,
			sortable:   false
		}, media.controller.Library.prototype.defaults ),

		initialize: function() {
			if ( ! this.get('library') ) {
				this.set( 'library', media.query({ videopress: true }) );
			}

			media.controller.Library.prototype.initialize.apply( this, arguments );
		},

		/**
		 * The original function saves content for the browse router only,
		 * so we hi-jack it a little bit.
		 */
		saveContentMode: function() {
			if ( 'videopress' !== this.get('router') ) {
				return;
			}

			var mode = this.frame.content.mode(),
				view = this.frame.router.get();

			if ( view && view.get( mode ) ) {

				// Map the Upload a Video back to the regular Upload Files.
				if ( 'upload_videopress' === mode ) {
					mode = 'upload';
				}

				setUserSetting( 'libraryContent', mode );
			}
		}
	});

	/**
	 * VideoPress Uploader
	 */
	media.view.VideoPressUploader = media.View.extend({
		tagName:   'div',
		className: 'uploader-videopress',
		template:  media.template('videopress-uploader'),

		events: {
			'submit .videopress-upload-form': 'submitForm'
		},

		initialize: function() {
			var that = this;

			if ( ! window.addEventListener ) {
				window.attachEvent( 'onmessage', function() { return that.messageHandler.apply( that, arguments ); } );
			} else {
				window.addEventListener( 'message', function() { return that.messageHandler.apply( that, arguments ); }, false );
			}

			return media.View.prototype.initialize.apply( this, arguments );
		},

		submitForm: function() {
			var data = false;

			this.clearErrors();

			if ( this.$( 'input[name="videopress_file"]').val().length < 1 ) {
				this.error( VideoPress.l10n.selectVideoFile );
				return false;
			}

			// Prevent multiple submissions.
			this.$( '.videopress-upload-form .button' ).prop( 'disabled', true );

			// A non-async request for an upload token.
			media.ajax( 'videopress-get-upload-token', { async: false } ).done( function( response ) {
				data = response;
				data.success = true;
			}).fail( function( response ) {
				data = response;
				data.success = false;
			});

			if ( ! data.success ) {
				// Re-enable form elements.
				this.$( '.videopress-upload-form .button' ).prop( 'disabled', false );

				// Display an error message and cancel form submission.
				this.error( data.message );
				return false;
			}

			this.error( VideoPress.l10n.videoUploading, 'updated' );

			// Set the form token.
			this.$( 'input[name="videopress_blog_id"]' ).val( data.videopress_blog_id );
			this.$( 'input[name="videopress_token"]' ).val( data.videopress_token );
			this.$( '.videopress-upload-form' ).attr( 'action', data.videopress_action_url );
			return true;
		},

		error: function( message, type ) {
			type = type || 'error';
			var div = $( '<div />' ).html( $( '<p />' ).text( message ) ).addClass( type );
			this.$( '.videopress-errors' ).html( div );
			return this;
		},

		success: function( message ) {
			return this.error( message, 'updated' );
		},

		clearErrors: function() {
			this.$( '.videopress-errors' ).html('');
			return this;
		},

		messageHandler: function( event ) {
			if ( ! event.origin.match( /\.wordpress\.com$/ ) ) {
				return;
			}

			if ( event.data.indexOf && event.data.indexOf( 'vpUploadResult::' ) === 0 ) {
				var result = JSON.parse( event.data.substr( 16 ) );

				if ( ! result || ! result.code ) {
					this.error( VideoPress.l10n.unknownError );
					this.$( '.videopress-upload-form .button' ).prop( 'disabled', false );
					return;
				}

				if ( 'success' === result.code && result.data ) {
					var that = this, controller = this.controller,
					    state = controller.states.get( 'videopress' );

					// Our new video has been added, so we need to reset the library.
					// Since the Media API caches all queries, we add a random attribute
					// to avoid the cache, then call more() to actually fetch the data.

					state.set( 'library', media.query({ videopress:true, vp_random:Math.random() }) );
					state.get( 'library' ).more().done(function(){
						var model = state.get( 'library' ).get( result.data.attachment_id );

						// Clear errors and select the uploaded item.
						that.clearErrors();
						state.get( 'selection' ).reset([ model ]);
						controller.content.mode( 'browse' );
					});
				} else {
					this.error( result.code );

					// Re-enable form elements.
					this.$( '.videopress-upload-form .button' ).prop( 'disabled', false );
				}
			}
		}
	});

	/**
	 * Add a custom sync function that would add a few extra
	 * options for models which are VideoPress videos.
	 */
	var attachmentSync = media.model.Attachment.prototype.sync;
	media.model.Attachment.prototype.sync = function( method, model, options ) {
		if ( model.get( 'vp_isVideoPress' ) ) {
			console.log( 'syncing ' + model.get( 'vp_guid' ) );
			options.data = _.extend( options.data || {}, {
				is_videopress: true,
				vp_nonces: model.get( 'vp_nonces' )
			} );
		}

		// Call the original sync routine.
		return attachmentSync.apply( this, arguments );
	};

	/**
	 * Extend the default Attachment Details view. Check for vp_isVideoPress before
	 * adding anything to these methods.
	 */
	var AttachmentDetails = media.view.Attachment.Details;
	media.view.Attachment.Details = AttachmentDetails.extend({

		initialize: function() {
			if ( this.model.get( 'vp_isVideoPress' ) ) {
				_.extend( this.events, {
					'click a.videopress-preview': 'vpPreview',
					'change .vp-radio': 'vpRadioChange',
					'change .vp-checkbox': 'vpCheckboxChange'
				});
			}
			return AttachmentDetails.prototype.initialize.apply( this, arguments );
		},

		render: function() {
			var r = AttachmentDetails.prototype.render.apply( this, arguments );
			if ( this.model.get( 'vp_isVideoPress' ) ) {
				var template = media.template( 'videopress-attachment' );
				var options = this.model.toJSON();

				options.can = {};
				options.can.save = !! options.nonces.update;

				this.$el.append( template( options ) );
			}
			return r;
		},

		// Handle radio buttons
		vpRadioChange: function(e) {
			$( e.target ).parents( '.vp-setting' ).find( '.vp-radio-text' ).val( e.target.value ).change();
		},

		// And checkboxes
		vpCheckboxChange: function(e) {
			$( e.target ).parents( '.vp-setting' ).find( '.vp-checkbox-text' ).val( Number( e.target.checked ) ).change();
		},

		vpPreview: function() {
			VideoPressModal.render( this );
			return this;
		}
	});

	/**
	 * Don't display the uploader dropzone for the VideoPress router.
	 */
	var UploaderWindow = media.view.UploaderWindow;
	media.view.UploaderWindow = UploaderWindow.extend({
		show: function() {
			if ( 'videopress' !== this.controller.state().get('id') ) {
				UploaderWindow.prototype.show.apply( this, arguments );
			}

			return this;
		}
	});

	/**
	 * Don't display the uploader in the attachments browser.
	 */
	var AttachmentsBrowser = media.view.AttachmentsBrowser;
	media.view.AttachmentsBrowser = AttachmentsBrowser.extend({
		/**
		 * Snag the Core 3.9.2 versions as a quick fix to avoid
		 * the breakage introduced by r29364-core
		 */
		updateContent: function() {
			var view = this;

			if( ! this.attachments ) {
				this.createAttachments();
			}

			if ( ! this.collection.length ) {
				this.toolbar.get( 'spinner' ).show();
				this.collection.more().done(function() {
					if ( ! view.collection.length ) {
						view.createUploader();
					}
					view.toolbar.get( 'spinner' ).hide();
				});
			} else {
				view.toolbar.get( 'spinner' ).hide();
			}
		},
		/**
		 * Empty out to avoid breakage.
		 */
		toggleUploader: function() {},
		createUploader: function() {
			if ( 'videopress' !== this.controller.state().get('id') ) {
				return AttachmentsBrowser.prototype.createUploader.apply( this, arguments );
			}
		}
	});

	/**
	 * Add VideoPress-specific methods for all frames.
	 */
	_.extend( media.view.MediaFrame.prototype, { VideoPress: { // this.VideoPress.method()

		// When the VideoPress router is activated.
		activate: function() {
			var view = _.first( this.views.get( '.media-frame-router' ) ),
			    viewSettings = {};

			if ( VideoPress.caps.read_videos ) {
				viewSettings.browse = { text: VideoPress.l10n.VideoPressLibraryRouter, priority: 40 };
			}

			if ( VideoPress.caps.upload_videos ) {
				viewSettings.upload_videopress = { text: VideoPress.l10n.uploadVideoRouter, priority: 20 };
			}

			view.set( viewSettings );

			// Intercept and clear all incoming uploads
			wp.Uploader.queue.on( 'add', this.VideoPress.disableUpload, this );

			// Map the Upload Files view to the Upload a Video one (upload_videopress vs. upload)
			if ( 'upload' === this.content.mode() && VideoPress.caps.upload_videos ) {
				this.content.mode( 'upload_videopress' );
			} else {
				this.content.mode( 'browse' );
			}
		},

		// When navigated away from the VideoPress router.
		deactivate: function( /*view*/ ) {
			wp.Uploader.queue.off( 'add', this.VideoPress.disableUpload );
		},

		// Disable dragdrop uploads in the VideoPress router.
		disableUpload: function( attachment ) {
			var uploader = this.uploader.uploader.uploader;
			uploader.stop();
			uploader.splice();
			attachment.destroy();
		},

		// Runs on videopress:insert event fired by our custom toolbar
		insert: function( selection ) {
			var guid = selection.models[0].get( 'vp_guid' ).replace( /[^a-zA-Z0-9]+/, '' );
			media.editor.insert( '[wpvideo ' + guid + ']' );
			return this;
		},

		// Triggered by the upload_videopress router item.
		uploadVideo: function() {
			this.content.set( new media.view.VideoPressUploader({
				controller: this
			}) );
			return this;
		},

		// Create a custom toolbar
		createToolbar: function( /*toolbar*/ ) {
			// Alow an option to hide the toolbar.
			if ( this.options.VideoPress && this.options.VideoPress.hideToolbar ) {
				return this;
			}

			var controller = this;
			this.toolbar.set( new media.view.Toolbar({
				controller: this,
				items: {
					insert: {
						style:    'primary',
						text:     VideoPress.l10n.insertVideoButton,
						priority: 80,
						requires: {
							library: true,
							selection: true
						},

						click: function() {
							var state = controller.state(),
								selection = state.get('selection');

							controller.close();
							state.trigger( 'videopress:insert', selection ).reset();
						}
					}
				}
			}) );
		}
	}});

	var MediaFrame = {};

	/**
	 * Extend the selection media frame
	 */
	MediaFrame.Select = media.view.MediaFrame.Select;
	media.view.MediaFrame.Select = MediaFrame.Select.extend({
		bindHandlers: function() {
			MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );

			this.on( 'router:create:videopress', this.createRouter, this );
			this.on( 'router:activate:videopress', this.VideoPress.activate, this );
			this.on( 'router:deactivate:videopress', this.VideoPress.deactivate, this );

			this.on( 'content:render:upload_videopress', this.VideoPress.uploadVideo, this );
			this.on( 'toolbar:create:videopress-toolbar', this.VideoPress.createToolbar, this );
			this.on( 'videopress:insert', this.VideoPress.insert, this );
		}
	});

	/**
	 * Extend the post editor media frame with our own
	 */
	MediaFrame.Post = media.view.MediaFrame.Post;
	media.view.MediaFrame.Post = MediaFrame.Post.extend({
		createStates: function() {
			MediaFrame.Post.prototype.createStates.apply( this, arguments );
			this.states.add([ new media.controller.VideoPress() ]);
		}
	});

	/**
	 * A VideoPress Modal view that we can use to preview videos.
	 * Expects a controller object on render.
	 */
	var VideoPressModalView = Backbone.View.extend({
		'className': 'videopress-modal-container',
		'template': wp.media.template( 'videopress-media-modal' ),

		// Render the VideoPress modal with a video object by guid.
		render: function( controller ) {
			this.delegateEvents( {
				'click .videopress-modal-close': 'closeModal',
				'click .videopress-modal-backdrop': 'closeModal'
			} );

			this.model = controller.model;
			this.guid = this.model.get( 'vp_guid' );

			if ( ! this.$frame ) {
				this.$frame = $( '.media-frame-content' );
			}

			this.$el.html( this.template( { 'video' : this.model.get( 'vp_embed' ) } ) );
			this.$modal = this.$( '.videopress-modal' );
			this.$modal.hide();

			this.$frame.append( this.$el );
			this.$modal.slideDown( 'fast' );

			return this;
		},

		closeModal: function() {
			var view = this;
			this.$modal.slideUp( 'fast', function() { view.remove(); } );
			return this;
		}
	});

	var VideoPressModal = new VideoPressModalView();

	// Configuration screen behavior
	$(document).ready( function() {
		var $form = $( '#videopress-settings' );

		// Not on a configuration screen
		if ( ! $form.length ) {
			return;
		}

		var $access = $form.find( 'input[name="videopress-access"]' ),
		    $upload = $form.find( 'input[name="videopress-upload"]' );

		$access.on( 'change', function() {
			var access = $access.filter( ':checked' ).val();
			$upload.attr( 'disabled', ! access );

			if ( ! access ) {
				$upload.attr( 'checked', false );
			}
		});

		$access.trigger( 'change' );
	});

	// Media -> VideoPress menu
	$(document).on( 'click', '#videopress-browse', function() {

		wp.media({
			state: 'videopress',
			states: [ new media.controller.VideoPress() ],
			VideoPress: { hideToolbar: true }
		}).open();

		return false;
	});
})(jQuery);
