ensurePackage("guardian.serverSidePluck");

var sspSitesProxies = true;

var config = {
	messages : {
		commentBlocked : 'This comment has been removed by a moderator. Replies may also be deleted.'
	},
	commentsSignUpUrl : commentsSignUpUrl,
	numberOfCommentsPerPage : 50,
	signOutUrl : "/Users/signout/tr/1,,,00.html",
	pluckMaxNumberPerPage : 10,
	/*addClippingsUrl : serverData.env.addClippingsUrl,*/
	commentKeyPrefix : 'CommentKey:',
	userProfileServiceUrl : sitePrefixUrl + "/users/pluck/getUserProfile.js",
	reportAbuseServiceUrl : sitePrefixUrl + "/users/pluck/report-abuse"
};

guardian.serverSidePluck.ErrorMessageView = function () {

	function objectToString(exception) {
		if (typeof exception === "object") {
			var result = ['{'];
			for (var name in exception) {
				if (exception.hasOwnProperty(name)) {
					result.push(name + ' -> ');
					result.push(objectToString(exception[name]));
				}
			}
			result.push('}');
			return result.join('\n');
		}
		return exception.toString(); 
	}
	
	this.writeMessage = function (exception) {
		var div = document.createElement('textarea');
		div.style.display = 'none';
		div.style.width = '100%';
		div.style.height = '400px';
		
		div.innerHTML = objectToString(exception);
		
		document.getElementsByTagName('body')[0].appendChild(div);		
	};
};

/* ---- PluckSender.js ---- */
/* create this with
new guardian.serverSidePluck.PluckSender(pluckObjectFactory, serverUrl, errorMessageView)
*/

guardian.serverSidePluck.PluckSender = function (pluckObjectFactory, pluckServerUrl, errorMessageView) {
	var instance = this;
	
	function handleErrors(callback, errors) {
		if (callback.errorHandler) {
			callback.errorHandler(errors);
		} else {
			errorMessageView.writeMessage(errors);			
		}
	}
	
	function createErrorMessage(args, callback, responseBatch) {
		return {
			args : args,
			callback : callback,
			responseBatch : responseBatch,
			messages : [],
			hasErrors : function () {
				return this.messages.length > 0;
			}
		};
	}

	this.submit = function (callback) {
		var args = Array.prototype.slice.call(arguments, 1);
		var requestBatch = pluckObjectFactory.newRequestBatch(args);
		var myCallback = function (responseBatch) {
			var errors = createErrorMessage(args, callback, responseBatch);
			for (var i = 0; i < responseBatch.Messages.length; i++) {
				var message = responseBatch.Messages[i].Message;
				if (message !== 'ok') {
					errors.messages.push(message);
				}
			}
			if (errors.hasErrors()) {
				handleErrors(callback, errors);
			} else {
				callback(responseBatch);
			}
		};
		

		requestBatch.BeginRequest(pluckServerUrl, myCallback);
	};
	
	this.submitIndividually = function (callback, messageArray, progressCallback) {
		var responseBatches = [];
		var numberOfCallbacks = 0;
		var numberOfErrors = 0;
		var expectedNumberOfCallbacks =  messageArray.length;
		var responseCallback = function (responseBatch) {
			responseBatches.push(responseBatch);
			numberOfCallbacks++;
			if (progressCallback) {
				progressCallback(responseBatch);
			}
			returnResponseBatchesIfNoMoreCallbacks(numberOfCallbacks, responseBatches, expectedNumberOfCallbacks, callback);
		};
		responseCallback.errorHandler = function () {
			numberOfCallbacks++;
			numberOfErrors++;
			if (numberOfErrors === expectedNumberOfCallbacks) {
				if (callback.errorHandler) {
					callback.errorHandler();
				}
			}
			else {
				returnResponseBatchesIfNoMoreCallbacks(numberOfCallbacks, responseBatches, expectedNumberOfCallbacks, callback);
			}
		};
		for (var i = 0; i < messageArray.length; i++) {
			instance.submit(responseCallback, messageArray[i]);
		}
	};

	function returnResponseBatchesIfNoMoreCallbacks(numberOfCallbacks, responseBatches, expectedNumberOfCallbacks, callback) {
		if (numberOfCallbacks === expectedNumberOfCallbacks) {
			callback(responseBatches);
		}
	}
};

/* ---- PluckObjectFactory.js ---- */

/* created with
new guardian.serverSidePluck.PluckObjectFactory(config)
*/

guardian.serverSidePluck.PluckObjectFactory = function (config) {
	
	var instance = this;
	
	this.newCommentPage = function (articleId, numberOfCommentsPerSlice, sliceNumber, sort) {
		return new CommentPage(new ArticleKey(articleId), numberOfCommentsPerSlice, sliceNumber, (sort || "TimeStampAscending"));
	};

	this.newUserCommentPage = function (userId, numberOfCommentsPerSlice, sliceNumber, sort) {
		return new UserCommentPage(new UserKey(userId), numberOfCommentsPerSlice, sliceNumber, (sort || "TimeStampDescending"));
	};

	this.newRequestBatch = function (data) {
		var requestBatch = new RequestBatch();
		for (var i = 0; i < data.length; i++) {
			requestBatch.AddToRequest(data[i]);
		}
		return requestBatch;
	};

	this.newCommentAction = function (articleId, pageUrl, pageTitle, commentBody) {
		var articleKey = new ArticleKey(articleId);
		return new CommentAction(articleKey, pageUrl, pageTitle, commentBody);
	};
	
	this.newDiscoverArticlesAction = function (sections, categories, contributors, activity, age, maxResults) {
		return new DiscoverArticlesAction(sections, categories, contributors, activity, age, maxResults);
	};

	this.newArticleKey = function (articleId) {
		return new ArticleKey(articleId);
	};
	
	this.newUserKey = function (userId) {
		return new UserKey(userId);
	};
	
	this.newActivity = function (name) {
		return new Activity(name);
	};

	this.newCommentKey = function (commentId) {
		return instance.newCommentKeyWithoutPrefix(config.commentKeyPrefix + commentId);
	};

	this.newCommentKeyWithoutPrefix = function (commentId) {
		return new CommentKey(commentId);
	};
	
	this.newCustomItemKey = function (key) {
		return new CustomItemKey(key);
	};

	this.newSection = function (name) {
		return new Section(name);
	};
	
	this.newSectionList = function (sectionIdList) {
		var sectionList = [];
		for (var i = 0; i < sectionIdList.length; i++) {
			sectionList.push(instance.newSection(sectionIdList[i].toString()));
		}
		return sectionList;
	};
	
	this.newCategoryList = function (tagIdList) {
		var categoryList = [];
		for (var i = 0; i < tagIdList.length; i++) {
			categoryList.push(instance.newCategory(tagIdList[i].toString()));
		}
		return categoryList;
	};	
	
	this.newCategory = function (name) {
		return new Category(name);
	};
	
	this.articleByDefault = {};
	this.userByDefault = {};
	
	this.newPluckKey = function (keyString, articleOrUserByDefault) {
		if (keyString && keyString.match(/^CommentKey/)) {
			return new CommentKey(keyString);
		}
		
		if (articleOrUserByDefault === instance.articleByDefault) {
			return new ArticleKey(keyString);
		}
		if (articleOrUserByDefault === instance.userByDefault) {
			return new UserKey(keyString);
		}
	};
	
	this.newReportAbuseAction = function (abuseReport) {
		var description = abuseReport.description;
		if (abuseReport.email) {
			description += " [" + abuseReport.email + "]";
		}
		return new ReportAbuseAction(instance.newPluckKey(abuseReport.commentKey, instance.userByDefault), abuseReport.reason, description);
	};
	
	this.newRecommendActionForComment = function (commentId) {
		return instance.newRecommendAction(instance.newCommentKeyWithoutPrefix(commentId));
	};
	
	this.newRecommendAction = function (recommendedItemKey) {
		return new RecommendAction(recommendedItemKey);
	};
	
	this.newUpdateArticleAction = function (articleInfo) {
		var articleKey = instance.newArticleKey(articleInfo.articleId);
		var section = instance.newSection(articleInfo.section);
		var categories = [];
		for (var i = 0; articleInfo.categories && i < articleInfo.categories.length; i++) {
			categories[i] = instance.newCategory(articleInfo.categories[i]);
		}
		return new UpdateArticleAction(articleKey, articleInfo.pageUrl, articleInfo.pageTitle, section, categories);
	};
	
	this.newSearchAction = function (searchString, numberOfCommentsPerPage, onPage) {
		var searchType = 'Comment';
		return new SearchAction(searchType, searchString, numberOfCommentsPerPage, onPage);
	};
	
	this.newUpdateCustomItemAction = function (customItemKey, content) {
		var name = "placeholder";
		return new UpdateCustomItemAction(customItemKey, name, null, null, content);
	};
	
	this.newUserTier = function (userTier) {
		return new UserTier(userTier);
	};
	
	this.newContentPolicyActionType = function (contentPolicyActionType) {
		return new ContentPolicyActionType(contentPolicyActionType);
	};
	
	this.newContentPolicy = function (contentPolicy) {
		return new ContentPolicy(contentPolicy);
	};
	
	this.newSetContentPolicyAction = function (articleId, userTierString, actionTypeString, contentPolicyString) {
		var articleKey = instance.newArticleKey(articleId);
		var userTier = instance.newUserTier(userTierString);
		var actionType = instance.newContentPolicyActionType(actionTypeString);
		var contentPolicy = instance.newContentPolicy(contentPolicyString);
		return new SetContentPolicyAction(articleKey, userTier, actionType, contentPolicy);
	};
};

/* ---- PluckHashCookieHandler.js ---- */

guardian.serverSidePluck.PluckHashCookieHandler = function () {

	var cookieName = 'at'; 
		
	this.cookieExists = function () {
		return readCookie(cookieName) !== null;	
	};
	
	this.getLoggedInUserName = function () {
		var atCookieBody = readCookie('at');
		
		if (!atCookieBody) {
			return null;
		}
		
		var loggedInUserName = atCookieBody.match(/&a=([^&]+)&/)[1];
		return loggedInUserName;
	};
	
	this.getLoggedInUserId = function () {
		var atCookieBody = readCookie(cookieName);
		
		if (!atCookieBody) {
			return null;
		}
		
		var loggedInUserId = atCookieBody.match(/u=([^&]+)&/)[1];
		return loggedInUserId;
	};	
};

/* How it's created:
	var cookieDomain = "."+document.domain;
	var urlStack = new UrlStack(cookieDomain);
	var pluckCookieHandler = new guardian.serverSidePluck.PluckHashCookieHandler()
	var authenticationService = new guardian.r2.pluck.PluckAuthenticationService(config, pluckCookieHandler, urlStack, false);
*/


/* ---- PluckAuthenticationService.js ---- */
guardian.serverSidePluck.PluckAuthenticationService = function (config, pluckCookieHandler, urlStack, targetOpener) {
	var showBoxParamName = 'showCommentBox';
	var instance = this;
	
	this.isUserLoggedIntoPluck = function () {
		return pluckCookieHandler.cookieExists();
	};

	this.getLoggedInUserName = function () {
		if (!this.isUserLoggedIntoPluck()) {
			throw "Can't get username because no pluck cookie exists.";
		}
		return pluckCookieHandler.getLoggedInUserName();
	};

	this.getLoggedInUserId = function () {
		if (!this.isUserLoggedIntoPluck()) {
			throw "Can't get username because no pluck cookie exists.";
		}
		return pluckCookieHandler.getLoggedInUserId();
	};

	this.login = function (shouldShowCommentBoxOnReturn) {
		if (instance.isUserLoggedIntoPluck()) {
			return;
		}

		urlStack.clearUrlStack();

		// TODO move document.location stuff into view or inject
		var destinationUrl = stripParamFromUrl(showBoxParamName, document.location.href);
		if (shouldShowCommentBoxOnReturn) {
			destinationUrl = appendParam(destinationUrl, showBoxParamName, 'true');
		}
		
		urlStack.pushUrlOntoStack(destinationUrl);
		// TODO return url to controller rather than modifying document.location
		
		if (targetOpener) {
			window.opener.document.location = config.commentsSignUpUrl;
		} else {
			document.location = config.commentsSignUpUrl;
		}
	};
	
	this.isLoggedInUserThePageOwner = function (userIdOfPage) {
		return pluckCookieHandler.getLoggedInUserId() === userIdOfPage;
	};

	this.signOut = function () {
		var destinationUrl = stripParamFromUrl(showBoxParamName, document.location.href);
		urlStack.pushUrlOntoStack(destinationUrl);
		// TODO return url to controller rather than modifying document.location
		document.location = config.signOutUrl;
	};

	var appendParam = function (url, name, value) {
		if (url.indexOf('?') === -1) {
			return url + '?' + name + '=' + value;
		}

		return url + '&' + name + '=' + value;
	};
};

/* ---- PluckReportAbuseService.js ---- */

guardian.serverSidePluck.PluckReportAbuseService = function (config) {

	this.reportAbuse = function (abuseReport, callback) {
		var responseCallback = function (responseBatch) {
			callback();
		};
		
		delegateErrorHandler(responseCallback, callback);

		// Change following to jQ.post when R2 allows POSTing to raw resources
		var abuseGETUrl = config.reportAbuseServiceUrl 
			+ '?email=' + escape(abuseReport.email)
			+ '&commentKey=' + escape(abuseReport.commentKey)
			+ '&reason=' + escape(abuseReport.reason)
			+ '&description=' + escape(abuseReport.description);
		jQ.getJSON(abuseGETUrl, responseCallback);
		//jQ.post(config.reportAbuseServiceUrl, abuseReport, responseCallback, "jsonp");
	};
	
};

/* ---- CharCounter.js ---- */

guardian.serverSidePluck.CharCounter = function (maxChars) {
	
	var labelSetter;
	var charGetter;
	var charSetter;

	var ensureCharsWithinLimit = function () {
		var chars = charGetter();
		if (chars.length > maxChars) {
			charSetter(chars.substring(0, maxChars));
		}
	};

	this.configure = function (_labelSetter, _charGetter, _charSetter) {
		labelSetter = _labelSetter;
		charGetter = _charGetter;
		charSetter = _charSetter;

		this.count();
	};

	this.count = function () {
		ensureCharsWithinLimit();
		var charsLeft = maxChars - charGetter().length;
		labelSetter(charsLeft);
	};

	this.reset = function () {
		labelSetter(maxChars);
		charSetter("");
	};
};

/* ---- PluckAbuseBoxController ---- */

/* How it's created
this.createPluckUserAbuseBoxController = function () {
    var reportAbuseView = new guardian.serverSidePluck.PluckAbuseBoxView();
    var abuseBoxCharCounter = new guardian.serverSidePluck.CharCounter(300);
    return new guardian.serverSidePluck.PluckAbuseBoxController(authenticationService, reportAbuseService, reportAbuseView, abuseBoxCharCounter);	
};
*/


guardian.serverSidePluck.PluckAbuseBoxController = function (authenticationService, reportAbuseService, reportAbuseView, charCounter) {

	var instance = this;
	var commentKey;
	var errorHasOccured = false;
	
	function onLoad() {
		charCounter.configure(reportAbuseView.setCharsLeft, reportAbuseView.getRawAbuseDescription, reportAbuseView.setAbuseDescription);
		registerViewListeners();
		reportAbuseView.init();
	}

	function resetAbuseBox() {
		charCounter.reset();
		resetView();
	}

	function registerViewListeners() {
		reportAbuseView.registerClickListenerOnOpenAbuseBoxButton(instance.openAbuseBox);
		reportAbuseView.registerClickListenerOnCloseConfirmButton(instance.closeConfirm);
		reportAbuseView.registerClickListenerOnSubmitAbuseReportButton(instance.submitAbuseReport);
		reportAbuseView.registerClickListenerOnCloseAbuseBoxButton(instance.closeAbuseBox);
		reportAbuseView.registerClickListenerOnCancelCloseButton(instance.cancelClose);
		reportAbuseView.registerChangeListenerOnAbuseReasonList(instance.changeAbuseReason);
		reportAbuseView.registerChangeListenerOnAbuseReasonList(instance.validate);
		reportAbuseView.registerKeyPressListenerOnAbuseEmail(instance.validate);
		reportAbuseView.registerKeyPressListenerOnAbuseDescriptionTextArea(instance.validate);
		reportAbuseView.registerKeyPressListenerOnAbuseDescriptionTextArea(charCounter.count);
	}
	
	function isDirty() {
		return reportAbuseView.getAbuseReason() !== "" || reportAbuseView.getRawAbuseDescription() !== "" || reportAbuseView.getAbuseEmail() !== "";
	}

	function isValid() {
		return isAbuseReasonSelected() && isEmailValid() && isAbuseDescriptionValid();
	}

	function isAbuseReasonSelected() {
		return reportAbuseView.getAbuseReason() !== "";		
	}

	function isAbuseDescriptionValid() {
		if (reportAbuseView.getAbuseReason() !== "Other") {
			return true;
		}
		else {
			return trim(reportAbuseView.getRawAbuseDescription()).length > 0;
		}
	}
	
	function processResponse() {
		showThankYouArea();
		reportAbuseView.disableOpenAbuseBoxButton(commentKey);
	}
	
	function handleError() {
		errorHasOccured = true;
		reportAbuseView.hideProgressArea();
		reportAbuseView.showPluckErrorArea();
	}

	// TODO pull out into a util file (e.g. 10util)
	function isEmailValid() {
		var valid = false;

		var email = trim(reportAbuseView.getAbuseEmail());
		var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;

		return email.length === 0 || filter.test(email);
	}

	
	function resetView() {
		reportAbuseView.hideEmailInfo();
		reportAbuseView.hideLoginInfo();
		reportAbuseView.hideProgressArea();
		reportAbuseView.hideCloseConfirmationArea();
		reportAbuseView.hideThankYouArea();
		reportAbuseView.hidePluckErrorArea();
		
		reportAbuseView.disableSubmitButton();
		reportAbuseView.resetAbuseReason();
		reportAbuseView.clearAbuseDescription();
		reportAbuseView.clearAbuseEmail();
		reportAbuseView.setAbuseDescriptionOptional();

		reportAbuseView.showEditArea();
		reportAbuseView.showCloseButton();		
	}
	
	function showProgressArea() {
		reportAbuseView.hideEditArea();
		reportAbuseView.showProgressArea();
	}
	
	function showEditArea() {
		reportAbuseView.hideCloseConfirmationArea();
		reportAbuseView.showCloseButton();
		reportAbuseView.showEditArea();
	}
	
	function showCloseConfirmationArea() { 
		reportAbuseView.hideCloseButton();
		reportAbuseView.hideEditArea();
		reportAbuseView.showCloseConfirmationArea();
	}
	
	function showThankYouArea() {
		reportAbuseView.hideProgressArea();
		reportAbuseView.hideCloseButton();
		reportAbuseView.showThankYouArea();
	}	

	this.openAbuseBox = function (_commentKey) {
		commentKey = _commentKey;
		
		resetAbuseBox();
		
		if (authenticationService.isUserLoggedIntoPluck()) {
			reportAbuseView.setUserName(authenticationService.getLoggedInUserName());
			reportAbuseView.showLoginInfo();
		} else {
			reportAbuseView.showEmailInfo();
		}

		reportAbuseView.showAbuseBox();
	};

	this.closeAbuseBox = function () {
		if (!isDirty() || errorHasOccured) {
			instance.closeConfirm();
			return;
		} 
		
		showCloseConfirmationArea();
	};

	this.closeConfirm = function () {
		reportAbuseView.hideAbuseBox();	
	};

	this.cancelClose = function () {
		showEditArea();
	};	

	this.submitAbuseReport = function () {
		showProgressArea();
		
		var abuseReport = {
			commentKey : commentKey, 
			reason : reportAbuseView.getAbuseReason(),
			description : reportAbuseView.getAbuseDescription(),
			email : reportAbuseView.getAbuseEmail()
		};
		
		var callback = processResponse;
		callback.errorHandler = handleError;
		
		reportAbuseService.reportAbuse(abuseReport, callback);
	};

	this.changeAbuseReason = function () {
		if (reportAbuseView.getAbuseReason() === "Other") {
			reportAbuseView.setAbuseDescriptionMandatory();
		}
		else {
			reportAbuseView.setAbuseDescriptionOptional();	
		}
	};

	this.validate = function () {
		if (isValid()) {
			reportAbuseView.enableSubmitButton();
		}
		else {
			reportAbuseView.disableSubmitButton();
		}
	};

	reportAbuseView.addLoadEvent(onLoad);
};

/* ---- PluckAbuseBoxView.js ---- */

guardian.serverSidePluck.PluckAbuseBoxView = function () {

	var dialogBox = new guardian.r2.DialogBox();
	
	function positionAbuseBox() {
		var abuseBox = document.getElementById('abuse-box');
		var abuseBoxWrapper = document.getElementById('abuse-box-wrapper');
		dialogBox.positionDialogBox(abuseBox, abuseBoxWrapper);
	}
	
	this.addLoadEvent = function (callback) {
		addEvent(document, "load", callback);				
	};

	this.registerClickListenerOnOpenAbuseBoxButton = function (callback) {
		var myCallback = function (event) {			
			var target = guardian.r2.event.getElement(event);					
			if (target.className === "report-abuse") {
				var commentKey = target.parentNode.parentNode.id;
				callback(commentKey);
			}
		};

		addEvent("pluck-comment-block", "click", myCallback);
	};
	
	this.registerClickListenerOnCloseAbuseBoxButton = function (callback) {
		addEvent("abuse-box-close", "click", callback);
	};

	this.registerClickListenerOnCloseConfirmButton = function (callback) {
		addEvent("abuse-close-confirm", "click", callback);
		addEvent("abuse-close-thank-you", "click", callback);
	};

	this.registerClickListenerOnSubmitAbuseReportButton = function (callback) {
		addEvent("abuse-submit", "click", callback);
	};

	this.registerClickListenerOnCancelCloseButton = function (callback) {
		addEvent("abuse-close-cancel", "click", callback);
	};

	this.registerChangeListenerOnAbuseReasonList = function (callback) {
		addEvent("abuse-reason", "change", callback);
	};

	this.registerKeyPressListenerOnAbuseEmail = function (callback) {
		addEvent("abuse-email", "keyup", callback);
	};

	this.registerKeyPressListenerOnAbuseDescriptionTextArea = function (callback) {
		addEvent("abuse-description", "keyup", callback);
	};

	this.showAbuseBox = function () {
		var abuseBox = document.getElementById('abuse-box');
		var abuseBoxWrapper = document.getElementById('abuse-box-wrapper');
		dialogBox.showDialogBox(abuseBox, abuseBoxWrapper);
	};
	
	this.hideAbuseBox = function () {
		abuseBoxWrapper = document.getElementById("abuse-box-wrapper");
		abuseBoxWrapper.style.display = "none";
		dialogBox.hideDialogBox(abuseBoxWrapper);
	};

	this.setUserName = function (userName) {
		document.getElementById("abuse-user-name").innerHTML = userName;
	};

	this.showEmailInfo = function () {
		document.getElementById("abuse-email-info").style.display = "block";
	};

	this.hideEmailInfo = function () {
		document.getElementById("abuse-email-info").style.display = "none";
	};

	this.showLoginInfo = function () {
		document.getElementById("abuse-login-info").style.display = "block";
	};

	this.hideLoginInfo = function () {
		document.getElementById("abuse-login-info").style.display = "none";
	};

	this.getAbuseReason = function () {
		return document.getElementById("abuse-reason").value;
	};

	this.resetAbuseReason = function () {
		//setTimeout is a fix so that resetting works correctly in opera 
		setTimeout(
		function () {
			document.getElementById("abuse-reason").value = "";
		}, 0);
	};

	this.getAbuseDescription = function () {
		return document.getElementById("abuse-description").value;
	};
	
	this.getRawAbuseDescription = function () {
		return document.getElementById("abuse-description").value;
	};	

	this.setAbuseDescription = function (abuseDescription) {
		document.getElementById("abuse-description").value = abuseDescription;
	};

	this.clearAbuseDescription = function () {
		document.getElementById("abuse-description").value = "";
	};

	this.setAbuseDescriptionOptional = function () {
		document.getElementById("abuse-description-optional").style.display = "inline";	
	};

	this.setAbuseDescriptionMandatory = function () {
		document.getElementById("abuse-description-optional").style.display = "none";	
	};

	this.getAbuseEmail = function () {
		return document.getElementById("abuse-email").value;
	};

	this.clearAbuseEmail = function () {
		document.getElementById("abuse-email").value = "";
	};

	this.showEditArea = function () {
		document.getElementById("abuse-box-edit-area").style.display = "block";
	};

	this.hideEditArea = function () {
		document.getElementById("abuse-box-edit-area").style.display = "none";
	};

	this.showProgressArea = function () {
		document.getElementById("abuse-progress-area").style.display = "block";
	};

	this.hideProgressArea = function () {
		document.getElementById("abuse-progress-area").style.display = "none";
	};

	this.showThankYouArea = function () {
		document.getElementById("abuse-thank-you-area").style.display = "block";
	};

	this.hideThankYouArea = function () {
		document.getElementById("abuse-thank-you-area").style.display = "none";
	};

	this.showCloseConfirmationArea = function () {
		document.getElementById("abuse-close-confirmation-area").style.display = "block";
	};

	this.hideCloseConfirmationArea = function () {
		document.getElementById("abuse-close-confirmation-area").style.display = "none";
	};

	this.showCloseButton = function () {
		document.getElementById("abuse-box-close").style.display = "block";
	};

	this.hideCloseButton = function () {
		document.getElementById("abuse-box-close").style.display = "none";
	};
	
	this.disableOpenAbuseBoxButton = function (commentKey) {
		var commentUl = document.getElementById(commentKey);
		guardian.r2.dom.element.getElementsByCssSelector('.abuse-report', commentUl)[0].innerHTML = 'Report abuse';
	};
	
	this.disableSubmitButton = function () {
		document.getElementById("abuse-submit").disabled = true;
	};

	this.enableSubmitButton = function () {
		document.getElementById("abuse-submit").disabled = false;
	};

	this.setCharsLeft = function (charsLeft) {
		document.getElementById("abuse-chars-left").innerHTML = charsLeft;
	};
	
	this.showPluckErrorArea = function () {
		document.getElementById("abuse-pluck-error-area").style.display = "block";
	};
	
	this.hidePluckErrorArea = function () {
		document.getElementById("abuse-pluck-error-area").style.display = "none";
	};
	
	this.init = function () {
	};
};

/* ---- PluckRecommendationController.js ---- */
guardian.serverSidePluck.PluckRecommendationController = function (recommendationService, recommendationView) {
	
	var instance = this;
	
	this.onClickRecommendation = function (commentKey) {
		recommendationView.onClick(commentKey, instance.recommend);
	}
	
	this.processResponse = function (comment, callback) {
		callback(comment.NumberOfRecommendations);		
	};
	
	this.recommend = function (commentKey, callback) {
		var recommendCallback = function (comment) {
			instance.processResponse(comment, callback);
		};
		recommendationService.recommend(commentKey, recommendCallback);
	};
};

/* ---- PluckRecommendationService.js ---- */
guardian.serverSidePluck.PluckRecommendationService = function (pluckObjectFactory, pluckSender) {
	
	this.recommend = function (commentId, callback) {
		var responseCallback = function (responseBatch) {
			var forEachElementCallback = function (response) {
				if (response.Comment) {
					callback(response.Comment);
				}
			};
			forEachElementOf(responseBatch.Responses, forEachElementCallback);
		};		
				
		var commentRecommendation = pluckObjectFactory.newRecommendActionForComment(commentId);
		var commentKey = pluckObjectFactory.newCommentKeyWithoutPrefix(commentId);
		
		pluckSender.submit(responseCallback, commentRecommendation, commentKey);
	};
};

/* ---- PluckRecommendationView.js ---- */
guardian.serverSidePluck.PluckRecommendationView = function () {

	this.onClick = function (commentKey, callback) {
		var target = document.getElementById("pluck-single-comment-" + commentKey);								
		if (target.className === "recommend") {		
			var updateNumberOfRecommendations = function (numberRecommendations) {
				document.getElementById("pluck-single-comment-no-" + commentKey).innerHTML = '(' + numberRecommendations + ')';
				disableAnchorTag(document.getElementById("pluck-single-comment-" + commentKey));
			};
			callback(commentKey, updateNumberOfRecommendations);
		}				
	};
	
	function disableAnchorTag(anchorTagElement) {
		var anchorTagText = anchorTagElement.innerHTML;
		var anchorTagParent = anchorTagElement.parentNode;
		
		anchorTagParent.replaceChild(document.createTextNode(anchorTagText), anchorTagElement);
	};
};


var pluckObjectFactory = new guardian.serverSidePluck.PluckObjectFactory(config);
var errorMessageView = new guardian.serverSidePluck.ErrorMessageView();
var pluckSender = new guardian.serverSidePluck.PluckSender(pluckObjectFactory, serverUrl, errorMessageView);

var cookieDomain = "."+document.domain;
var urlStack = new UrlStack(cookieDomain);
var pluckCookieHandler = new guardian.serverSidePluck.PluckHashCookieHandler();
var authenticationService = new guardian.serverSidePluck.PluckAuthenticationService(config, pluckCookieHandler, urlStack, false);

var reportAbuseService = new guardian.serverSidePluck.PluckReportAbuseService(config);

var reportAbuseView = new guardian.serverSidePluck.PluckAbuseBoxView();
var abuseBoxCharCounter = new guardian.serverSidePluck.CharCounter(300);
var pluckAbuseBoxController = new guardian.serverSidePluck.PluckAbuseBoxController(authenticationService, reportAbuseService, reportAbuseView, abuseBoxCharCounter);	

var recommendService = new guardian.serverSidePluck.PluckRecommendationService(pluckObjectFactory, pluckSender);
var recommendView = new guardian.serverSidePluck.PluckRecommendationView();
var recommendController = new guardian.serverSidePluck.PluckRecommendationController(recommendService, recommendView);

function onClickRecommendation(commentKey) {
	recommendController.onClickRecommendation(commentKey);
}
