var App = App || {};
App.Presenters = App.Presenters || {};

App.Presenters.PostPresenter = function(
	_,
	jQuery,
	util,
	promise,
	api,
	auth,
	router,
	keyboard,
	presenterManager,
	postsAroundCalculator,
	postCommentListPresenter,
	topNavigationPresenter,
	messagePresenter) {

	var $el = jQuery('#content');
	var $messages = $el;

	var templates = {};
	var params;

	var postNameOrId;
	var post;

	var privileges = {};
	var editPrivileges = {};

	var tagInput;
	var postContentFileDropper;
	var postThumbnailFileDropper;
	var postContent;
	var postThumbnail;

	function init(params, loaded) {
		topNavigationPresenter.select('posts');
		postsAroundCalculator.resetCache();

		privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
		privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
		privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
		editPrivileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
		editPrivileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
		editPrivileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
		editPrivileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
		editPrivileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
		editPrivileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
		editPrivileges.canChangeFlags = auth.hasPrivilege(auth.privileges.changePostFlags);

		promise.wait(
				util.promiseTemplate('post'),
				util.promiseTemplate('post-edit'),
				util.promiseTemplate('post-content'),
				util.promiseTemplate('history'))
			.then(function(
					postTemplate,
					postEditTemplate,
					postContentTemplate,
					historyTemplate) {
				templates.post = postTemplate;
				templates.postEdit = postEditTemplate;
				templates.postContent = postContentTemplate;
				templates.history = historyTemplate;

				reinit(params, loaded);
			}).fail(function(response) {
				showGenericError(response);
				loaded();
			});
	}

	function reinit(_params, loaded) {
		params = _params;
		params.query = params.query || {};
		params.query.page = parseInt(params.query.page) || 1;

		postNameOrId = params.postNameOrId;

		promise.wait(refreshPost())
			.then(function() {
				topNavigationPresenter.changeTitle('@' + post.id);
				render();
				loaded();
			}).fail(function() {
				console.log(arguments);
				loaded();
			});
	}

	function attachLinksToPostsAround() {
		promise.wait(postsAroundCalculator.getLinksToPostsAround(params.query, post.id))
			.then(function(nextPostUrl, prevPostUrl) {
				var $prevPost = $el.find('#post-current-search .right a');
				var $nextPost = $el.find('#post-current-search .left a');

				if (nextPostUrl) {
					$nextPost.addClass('enabled');
					$nextPost.attr('href', nextPostUrl);
					keyboard.keyup('a', function() {
						router.navigate(nextPostUrl);
					});
				} else {
					$nextPost.removeClass('enabled');
					$nextPost.removeAttr('href');
					keyboard.unbind('a');
				}

				if (prevPostUrl) {
					$prevPost.addClass('enabled');
					$prevPost.attr('href', prevPostUrl);
					keyboard.keyup('d', function() {
						router.navigate(prevPostUrl);
					});
				} else {
					$prevPost.removeClass('enabled');
					$prevPost.removeAttr('href');
					keyboard.unbind('d');
				}
			});
	}

	function refreshPost() {
		return promise.make(function(resolve, reject) {
			promise.wait(api.get('/posts/' + postNameOrId))
				.then(function(postResponse) {
					post = postResponse.json;
					resolve();
				}).fail(function(response) {
					showGenericError(response);
					reject();
				});
		});
	}

	function render() {
		$el.html(renderPostTemplate());
		$messages = $el.find('.messages');

		if (editPrivileges.canChangeTags) {
			tagInput = new App.Controls.TagInput($el.find('form [name=tags]'));
			tagInput.inputConfirmed = editPost;
		}

		postContentFileDropper = new App.Controls.FileDropper($el.find('form [name=content]'));
		postContentFileDropper.onChange = postContentChanged;
		postContentFileDropper.setNames = true;
		postThumbnailFileDropper = new App.Controls.FileDropper($el.find('form [name=thumbnail]'));
		postThumbnailFileDropper.onChange = postThumbnailChanged;
		postThumbnailFileDropper.setNames = true;

		if (_.any(editPrivileges)) {
			keyboard.keyup('e', function() {
				editButtonClicked(null);
			});
		}

		$el.find('.post-edit-wrapper form').submit(editFormSubmitted);
		attachSidebarEvents();

		presenterManager.initPresenters([
			[postCommentListPresenter, _.extend({post: post}, {$target: $el.find('#post-comments-target')})]],
			function() { });

		attachLinksToPostsAround();
	}

	function softRender() {
		renderSidebar();
		$el.find('video').prop('loop', post.flags.loop);
	}

	function renderSidebar() {
		$el.find('#sidebar').html(jQuery(renderPostTemplate()).find('#sidebar').html());
		attachSidebarEvents();
	}

	function renderPostTemplate() {
		return templates.post({
			query: params.query,
			post: post,
			ownScore: post.ownScore,
			postFavorites: post.favorites,
			postHistory: post.history,

			formatRelativeTime: util.formatRelativeTime,
			formatFileSize: util.formatFileSize,

			postContentTemplate: templates.postContent,
			postEditTemplate: templates.postEdit,
			historyTemplate: templates.history,

			hasFav: _.any(post.favorites, function(favUser) { return favUser.id === auth.getCurrentUser().id; }),
			isLoggedIn: auth.isLoggedIn(),
			privileges: privileges,
			editPrivileges: editPrivileges,
		});
	}

	function attachSidebarEvents() {
		$el.find('#sidebar .delete').click(deleteButtonClicked);
		$el.find('#sidebar .feature').click(featureButtonClicked);
		$el.find('#sidebar .edit').click(editButtonClicked);
		$el.find('#sidebar .history').click(historyButtonClicked);
		$el.find('#sidebar .add-favorite').click(addFavoriteButtonClicked);
		$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
		$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
		$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
	}

	function deleteButtonClicked(e) {
		e.preventDefault();
		messagePresenter.hideMessages($messages);
		if (window.confirm('Do you really want to delete this post?')) {
			deletePost();
		}
	}

	function deletePost() {
		promise.wait(api.delete('/posts/' + post.id))
			.then(function(response) {
				router.navigate('#/posts');
			}).fail(showGenericError);
	}

	function featureButtonClicked(e) {
		e.preventDefault();
		messagePresenter.hideMessages($messages);
		if (window.confirm('Do you want to feature this post on fron page?')) {
			featurePost();
		}
	}

	function featurePost() {
		promise.wait(api.post('/posts/' + post.id + '/feature'))
			.then(function(response) {
				router.navigate('#/home');
			}).fail(showGenericError);
	}

	function editButtonClicked(e) {
		if (e) {
			e.preventDefault();
		}
		messagePresenter.hideMessages($messages);
		if ($el.find('.post-edit-wrapper').is(':visible')) {
			hideEditForm();
		} else {
			showEditForm();
		}
	}

	function editFormSubmitted(e) {
		e.preventDefault();
		editPost();
	}

	function showEditForm() {
		$el.find('.post-edit-wrapper').slideDown('fast');
		util.enableExitConfirmation();
		tagInput.focus();
	}

	function hideEditForm() {
		$el.find('.post-edit-wrapper').slideUp('fast');
		util.disableExitConfirmation();
	}

	function editPost() {
		var $form = $el.find('form');
		var formData = {};
		formData.seenEditTime = post.lastEditTime;
		formData.flags = {};

		if (editPrivileges.canChangeContent && postContent) {
			formData.content = postContent;
		}

		if (editPrivileges.canChangeThumbnail && postThumbnail) {
			formData.thumbnail = postThumbnail;
		}

		if (editPrivileges.canChangeSource) {
			formData.source = $form.find('[name=source]').val();
		}

		if (editPrivileges.canChangeSafety) {
			formData.safety = $form.find('[name=safety]:checked').val();
		}

		if (editPrivileges.canChangeTags) {
			formData.tags = tagInput.getTags().join(' ');
		}

		if (editPrivileges.canChangeRelations) {
			formData.relations = $form.find('[name=relations]').val();
		}

		if (editPrivileges.canChangeFlags) {
			if (post.contentType === 'video') {
				formData.flags.loop = $form.find('[name=loop]').is(':checked') ? 1 : 0;
			}
		}

		if (post.tags.length === 0) {
			showEditError('No tags set.');
			return;
		}

		promise.wait(api.put('/posts/' + post.id, formData))
			.then(function(response) {
				post = response.json;
				hideEditForm();
				softRender();
			}).fail(function(response) {
				showEditError(response);
			});
	}

	function postContentChanged(files) {
		postContentFileDropper.readAsDataURL(files[0], function(content) {
			postContent = content;
		});
	}

	function postThumbnailChanged(files) {
		postThumbnailFileDropper.readAsDataURL(files[0], function(content) {
			postThumbnail = content;
		});
	}

	function historyButtonClicked(e) {
		e.preventDefault();
		if ($el.find('.post-history-wrapper').is(':visible')) {
			hideHistory();
		} else {
			showHistory();
		}
	}

	function hideHistory() {
		$el.find('.post-history-wrapper').slideUp('slow');
	}

	function showHistory() {
		$el.find('.post-history-wrapper').slideDown('slow');
	}

	function addFavoriteButtonClicked(e) {
		e.preventDefault();
		addFavorite();
	}

	function deleteFavoriteButtonClicked(e) {
		e.preventDefault();
		deleteFavorite();
	}

	function addFavorite() {
		promise.wait(api.post('/posts/' + post.id + '/favorites'))
			.then(function(response) {
				promise.wait(refreshPost()).then(softRender);
			}).fail(showGenericError);
	}

	function deleteFavorite() {
		promise.wait(api.delete('/posts/' + post.id + '/favorites'))
			.then(function(response) {
				promise.wait(refreshPost()).then(softRender);
			}).fail(showGenericError);
	}

	function scoreUpButtonClicked(e) {
		e.preventDefault();
		var $target = jQuery(this);
		score($target.hasClass('active') ? 0 : 1);
	}

	function scoreDownButtonClicked(e) {
		e.preventDefault();
		var $target = jQuery(this);
		score($target.hasClass('active') ? 0 : -1);
	}

	function score(scoreValue) {
		promise.wait(api.post('/posts/' + post.id + '/score', {score: scoreValue}))
			.then(function() {
				promise.wait(refreshPost()).then(softRender);
			}).fail(showGenericError);
	}

	function showEditError(response) {
		window.alert(response.json && response.json.error || response);
	}

	function showGenericError(response) {
		if ($messages === $el) {
			$el.empty();
		}
		messagePresenter.showError($messages, response.json && response.json.error || response);
	}

	return {
		init: init,
		reinit: reinit,
		render: render
	};

};

App.DI.register('postPresenter', [
	'_',
	'jQuery',
	'util',
	'promise',
	'api',
	'auth',
	'router',
	'keyboard',
	'presenterManager',
	'postsAroundCalculator',
	'postCommentListPresenter',
	'topNavigationPresenter',
	'messagePresenter'],
	App.Presenters.PostPresenter);
