AUI.add(
	'uea-asset-categories-selector',
	function(A) {
		var Lang = A.Lang;

		var LString = Lang.String;

		var AObject = A.Object;

		var BOUNDING_BOX = 'boundingBox';

		var CSS_LOADING_ANIMATION = 'loading-animation';

		var CSS_TAGS_LIST = 'lfr-categories-selector-list';

		var EMPTY_FN = Lang.emptyFn;

		var ID = 'id';

		var NAME = 'categoriesselector';

		var STR_MAX_ENTRIES = 'maxEntries';

		var STR_MORE_RESULTS_LABEL = 'moreResultsLabel';

		var STR_START = 'start';

		var TPL_CHECKED = ' checked="checked" ';

		var TPL_INPUT = '<label title="{titleCurrentValue}">' +
				'<span class="lfr-categories-selector-category-name" title="{titleCurrentValue}">' +
					'<input data-categoryId="{categoryId}" data-vocabularyid="{vocabularyId}" name="{inputName}" type="{type}" value="{titleCurrentValue}" {checked} />' +
					'{titleCurrentValue}' +
				'</span>' +
				'<span class="lfr-categories-selector-search-results-path" title="{path}">{path}</span>' +
			'</label>';

		var TPL_MESSAGE = '<div class="lfr-categories-message">{0}</div>';

		var TPL_SEARCH_RESULTS = '<div class="lfr-categories-selector-search-results"></div>';

		/**
		 * ----------
		 * Placecube Notes:
		 * This was copied from the below path to allow us to modify the behaviour to limit to certain categories. 
		 * /modules/apps/foundation/frontend-js/frontend-js-aui-web/src/main/resources/META-INF/resources/liferay/asset_categories_selector.js
		 * 
		 * Liferay Version: 7.0 (Fixpack 86)
		 * Functions Replaced: _getEntries, _searchCategories, _vocabulariesIterator
		 * Taglib: com.worth.uea.common.assetcategory.taglib
		 * Ajax Interactions Portlet: com.worth.uea.common.assetcategory.interactions
		 * ----------
		 * OPTIONS
		 * Required
		 * className {String}: The class name of the current asset.
		 * curEntryIds (string): The ids of the current categories.
		 * curEntries (string): The names of the current categories.
		 * hiddenInput {string}: The hidden input used to pass in the current categories.
		 * instanceVar {string}: The instance variable for this class.
		 * labelNode {String|A.Node}: The node of the label element for this selector.
		 * title {String}: The title of the button element for this selector.
		 * vocabularyIds (string): The ids of the vocabularies.
		 * vocabularyGroupIds (string): The groupIds of the vocabularies.
		 *
		 * Optional
		 * maxEntries {Number}: The maximum number of entries that will be loaded. The default value is -1, which will load all categories.
		 * moreResultsLabel {String}: The localized label for link "Load more results".
		 * portalModelResource {boolean}: Whether the asset model is on the portal level.
		 * vocabularyGroupDescriptiveNames (string): The groupDescriptiveNames of the vocabularies.
		 */

		var UeaAssetCategoriesSelector = A.Component.create(
			{
				ATTRS: {
					curEntries: {
						setter: function(value) {
							var instance = this;

							if (Lang.isString(value)) {
								value = value.split('_CATEGORY_');
							}

							return value;
						},
						value: []
					},

					curEntryIds: {
						setter: function(value) {
							var instance = this;

							if (Lang.isString(value)) {
								value = value.split(',');
							}

							return value;
						},
						value: []
					},

					label: {
						validator: '_isValidString',
						value: 'Select'
					},

					labelNode: {
						setter: function(value) {
							return A.one(value) || A.Attribute.INVALID_VALUE;
						},
						value: null
					},

					maxEntries: {
						validator: Lang.isNumber,
						value: -1
					},

					moreResultsLabel: {
						validator: '_isValidString',
						value: 'Load\x20More\x20Results'
					},

					singleSelect: {
						validator: Lang.isBoolean,
						value: false
					},

					title: {
						validator: '_isValidString',
						value: 'Select\x20Categories'
					},

					vocabularyGroupDescriptiveNames: {
						setter: function(value) {
							var instance = this;

							if (Lang.isString(value) && value) {
								value = value.split(',');
							}

							return value;
						},
						value: []
					},

					vocabularyGroupIds: {
						setter: function(value) {
							var instance = this;

							if (Lang.isString(value) && value) {
								value = value.split(',');
							}

							return value;
						},
						value: []
					},

					vocabularyIds: {
						setter: function(value) {
							var instance = this;

							if (Lang.isString(value) && value) {
								value = value.split(',');
							}

							return value;
						},
						value: []
					}
				},

				EXTENDS: Liferay.AssetTagsSelector,

				NAME: NAME,

				prototype: {
					TREEVIEWS: {},
					UI_EVENTS: {},

					renderUI: function() {
						var instance = this;

						UeaAssetCategoriesSelector.superclass.constructor.superclass.renderUI.apply(instance, arguments);

						instance._renderIcons();

						instance.inputContainer.addClass('hide-accessible');

						instance._applyARIARoles();
					},

					bindUI: function() {
						var instance = this;

						UeaAssetCategoriesSelector.superclass.bindUI.apply(instance, arguments);
					},

					syncUI: function() {
						var instance = this;

						UeaAssetCategoriesSelector.superclass.constructor.superclass.syncUI.apply(instance, arguments);

						var matchKey = instance.get('matchKey');

						instance.entries.getKey = function(obj) {
							return obj.categoryId;
						};

						var curEntries = instance.get('curEntries');
						var curEntryIds = instance.get('curEntryIds');

						curEntryIds.forEach(
							function(item, index) {
								var entry = {
									categoryId: item
								};

								entry[matchKey] = curEntries[index];

								entry.value = LString.unescapeHTML(entry.value);

								instance.entries.add(entry);
							}
						);
					},

					_afterTBLFocusedChange: EMPTY_FN,

					_applyARIARoles: function() {
						var instance = this;

						var boundingBox = instance.get(BOUNDING_BOX);
						var labelNode = instance.get('labelNode');

						if (labelNode) {
							boundingBox.attr('aria-labelledby', labelNode.attr(ID));

							labelNode.attr('for', boundingBox.attr(ID));
						}
					},

					_bindTagsSelector: EMPTY_FN,

					_clearEntries: function() {
						var instance = this;

						var entries = instance.entries;

						entries.each(A.fn('removeAt', entries, 0));
					},

					_formatJSONResult: function(json) {
						var instance = this;

						var output = [];

						var type = 'check';

						if (instance.get('singleSelect')) {
							type = 'radio';
						}

						json.forEach(
							function(item, index) {
								var checked = false;
								var treeId = 'category' + item.categoryId;

								if (instance.entries.findIndexBy('categoryId', item.categoryId) > -1) {
									checked = true;
								}

								var newTreeNode = {
									after: {
										checkedChange: A.bind('_onCheckedChange', instance)
									},
									checked: checked,
									id: treeId,
									label: LString.escapeHTML(item.titleCurrentValue),
									leaf: !item.hasChildren,
									paginator: instance._getPaginatorConfig(item),
									type: type
								};

								output.push(newTreeNode);
							}
						);

						return output;
					},

					_formatRequestData: function(groupId, parentVocabularyId, treeNode) {
						var instance = this;

						var data = {};

						data.p_auth = Liferay.authToken;
						data.scopeGroupId = groupId;

						var assetId = instance._getTreeNodeAssetId(treeNode);
						var assetType = instance._getTreeNodeAssetType(treeNode);

						if (Lang.isValue(assetId)) {
							if (assetType == 'category') {
								data.categoryId = assetId;

								if (parentVocabularyId) {
									data.vocabularyId = parentVocabularyId;
								}
							}
							else {
								data.vocabularyId = assetId;
							}
						}

						return data;
					},

					_getEntries: function(className, callback) {
						var instance = this;

						var portalModelResource = instance.get('portalModelResource');

						var groupIds = [];

						var vocabularyIds = instance.get('vocabularyIds');

						var resourceURL = Liferay.PortletURL.createResourceURL(); 
						resourceURL.setResourceId("/assetvocabulary/get-vocabularies");
						resourceURL.setParameter("p_p_id", "com_worth_uea_common_categories_taglib_CategorySelectorInteractionsPortlet")
						
						$.ajax({
							url: resourceURL.toString(),
							dataType: "JSON",
					        success: function (response) {
								callback(response.vocabularies);
							}
						});
						
					},

					_getPaginatorConfig: function(item) {
						var instance = this;

						var paginatorConfig = {
							offsetParam: STR_START
						};

						var maxEntries = instance.get(STR_MAX_ENTRIES);

						if (maxEntries > 0) {
							paginatorConfig.limit = maxEntries;
							paginatorConfig.moreResultsLabel = instance.get(STR_MORE_RESULTS_LABEL);
							paginatorConfig.total = item.childrenCount;
						}
						else {
							paginatorConfig.end = -1;
							paginatorConfig.start = -1;
						}

						return paginatorConfig;
					},

					_getTreeNodeAssetId: function(treeNode) {
						var treeId = treeNode.get(ID);

						var match = treeId.match(/(\d+)$/);

						return match ? match[1] : null;
					},

					_getTreeNodeAssetType: function(treeNode) {
						var treeId = treeNode.get(ID);

						var match = treeId.match(/^(vocabulary|category)/);

						return match ? match[1] : null;
					},

					_initSearch: EMPTY_FN,

					_initSearchFocus: function() {
						var instance = this;

						var popup = instance._popup;

						var vocabularyGroupIds = instance.get('vocabularyGroupIds');
						var vocabularyIds = instance.get('vocabularyIds');

						var searchResults = instance._searchResultsNode;

						if (!searchResults) {
							searchResults = A.Node.create(TPL_SEARCH_RESULTS);

							instance._searchResultsNode = searchResults;

							var processSearchResults = A.bind(
								'_processSearchResults',
								instance,
								searchResults
							);

							var searchCategoriesTask = A.debounce(instance._searchCategories, 350, instance);

							popup.searchField.on(
								'keyup',
								function(event) {
									if (!event.isNavKey()) {
										searchCategoriesTask(event, searchResults, vocabularyIds, vocabularyGroupIds, processSearchResults);
									}
								}
							);

							if (instance.get('singleSelect')) {
								var onSelectChange = A.bind('_onSelectChange', instance);

								popup.entriesNode.delegate('change', onSelectChange, 'input[type=radio]');
							}
						}

						popup.entriesNode.append(searchResults);

						instance._searchBuffer = [];
					},

					_isValidString: function(value) {
						var instance = this;

						return Lang.isString(value) && value.length;
					},

					_onBoundingBoxClick: EMPTY_FN,

					_onCheckboxCheck: function(event) {
						var instance = this;

						var currentTarget = event.currentTarget;

						var assetId;
						var entryMatchKey;

						if (A.instanceOf(currentTarget, A.Node)) {
							assetId = currentTarget.attr('data-categoryId');

							entryMatchKey = currentTarget.val();
						}
						else {
							assetId = instance._getTreeNodeAssetId(currentTarget);

							entryMatchKey = currentTarget.get('label');
						}

						var matchKey = instance.get('matchKey');

						var entry = {
							categoryId: assetId
						};

						entry[matchKey] = entryMatchKey;

						entry.value = LString.unescapeHTML(entry.value);

						instance.entries.add(entry);
					},

					_onCheckboxClick: function(event) {
						var instance = this;

						var method = '_onCheckboxUncheck';

						if (event.currentTarget.attr('checked')) {
							method = '_onCheckboxCheck';
						}

						instance[method](event);
					},

					_onCheckboxUncheck: function(event) {
						var instance = this;

						var currentTarget = event.currentTarget;

						var assetId;

						if (A.instanceOf(currentTarget, A.Node)) {
							assetId = currentTarget.attr('data-categoryId');
						}
						else {
							assetId = instance._getTreeNodeAssetId(currentTarget);
						}

						instance.entries.removeKey(assetId);
					},

					_onCheckedChange: function(event) {
						var instance = this;

						if (event.newVal) {
							if (instance.get('singleSelect')) {
								instance._clearEntries();
							}

							instance._onCheckboxCheck(event);
						}
						else {
							instance._onCheckboxUncheck(event);
						}
					},

					_onSelectChange: function(event) {
						var instance = this;

						instance._clearEntries();

						instance._onCheckboxCheck(event);
					},

					_processSearchResults: function(searchResults, results) {
						var instance = this;

						var buffer = instance._searchBuffer;

						buffer.length = 0;

						var categories = results.categories;

						if (categories && categories.length > 0) {
							var inputType = 'checkbox';

							if (instance.get('singleSelect')) {
								inputType = 'radio';
							}

							var inputName = A.guid();

							categories.forEach(
								function(item, index) {
									item.checked = instance.entries.findIndexBy('categoryId', item.categoryId) > -1 ? TPL_CHECKED : '';

									item.inputName = inputName;
									item.type = inputType;

									buffer.push(Lang.sub(TPL_INPUT, item));
								}
							);
						}
						else {
							var message = Lang.sub(TPL_MESSAGE, ['No\x20categories\x20were\x20found\x2e']);

							buffer.push(message);
						}

						searchResults.removeClass(CSS_LOADING_ANIMATION);

						searchResults.html(buffer.join(''));
					},

					_renderIcons: function() {
						var instance = this;

						var contentBox = instance.get('contentBox');

						instance.icons = new A.Toolbar(
							{
								children: [
									{
										label: instance.get('label'),
										on: {
											click: A.bind('_showSelectPopup', instance)
										},
										title: instance.get('title')
									}
								]
							}
						).render(contentBox);

						var iconsBoundingBox = instance.icons.get(BOUNDING_BOX);

						instance.entryHolder.placeAfter(iconsBoundingBox);
					},

					_searchCategories: function(event, searchResults, vocabularyIds, vocabularyGroupIds, callback) {
						var instance = this;

						var searchValue = event.currentTarget.val().trim();

						instance._searchValue = searchValue;

						if (searchValue) {
							searchResults.empty();

							searchResults.addClass(CSS_LOADING_ANIMATION);
							
							var resourceURL = Liferay.PortletURL.createResourceURL(); 
							resourceURL.setResourceId("/assetcategory/search-categories");
							resourceURL.setParameter("p_p_id", "com_worth_uea_common_categories_taglib_CategorySelectorInteractionsPortlet")
							resourceURL.setParameter("searchValue", searchValue);

							$.ajax({
								url: resourceURL.toString(),
								dataType: "JSON",
						        success: function (response) {
									callback(response);
								}
							});

						}

						searchResults.toggle(!!searchValue);

						var treeViews = instance.TREEVIEWS;

						AObject.each(
							treeViews,
							function(item, index) {
								item.toggle(!searchValue);
							}
						);
					},

					_showPopup: function(event) {
						var instance = this;

						Liferay.Util.getTop().AUI().use('aui-tree');

						UeaAssetCategoriesSelector.superclass._showPopup.apply(instance, arguments);
					},

					_showSelectPopup: function(event) {
						var instance = this;

						instance._showPopup(event);

						var popup = instance._popup;

						popup.titleNode.html('Categories');

						popup.entriesNode.addClass(CSS_TAGS_LIST);
						
						var className = instance.get('className');						

						instance._getEntries(
							className,
							function(entries) {
								var searchResults = instance._searchResultsNode;
								var searchValue = instance._searchValue;

								if (searchResults) {
									searchResults.removeClass(CSS_LOADING_ANIMATION);

									searchResults.toggle(!!searchValue);
								}

								popup.entriesNode.all('.tree-view, .loading-animation').remove(true);

								if (entries) {
									entries.forEach(instance._vocabulariesIterator, instance);	
								}  else {
									popup.entriesNode.empty();
									popup.entriesNode.append("You are not a member of any group that can publish news or events.");
								}

								A.each(
									instance.TREEVIEWS,
									function(item, index) {
										item.toggle(!searchValue);

										item.expandAll();
									}
								);
							}
						);

						if (instance._bindSearchHandle) {
							instance._bindSearchHandle.detach();
						}

						instance._bindSearchHandle = popup.searchField.once('focus', instance._initSearchFocus, instance);
					},

					_vocabulariesIterator: function(item, index) {
						var instance = this;

						var groupDescriptiveNames = instance.get('vocabularyGroupDescriptiveNames');
						var popup = instance._popup;
						var vocabularyId = item.vocabularyId;
						var vocabularyTitle = item.titleCurrentValue;

						if (item.groupId == themeDisplay.getCompanyGroupId()) {
							vocabularyTitle += ' (' + 'Global' + ')';
						} else if (groupDescriptiveNames.length > 0) {
							var vocabularyGroupIds = instance.get('vocabularyGroupIds');

							var groupDescriptiveName = groupDescriptiveNames[vocabularyGroupIds.indexOf(item.groupId)];

							if (groupDescriptiveName) {
								vocabularyTitle += ' (' + groupDescriptiveName + ')';
							}
						}

						var treeId = 'vocabulary' + vocabularyId;

						var vocabularyRootNode = {
							alwaysShowHitArea: true,
							id: treeId,
							label: vocabularyTitle,
							leaf: false,
							paginator: instance._getPaginatorConfig(item),
							type: 'io'
						};

						if (!_.isEmpty(instance.TREEVIEWS)) {
							for (var vocabId in instance.TREEVIEWS) {
								var tree = instance.TREEVIEWS[vocabId];
								var children = tree.get('children');

								if (!children || !children.length || children[0].hasChildNodes()) {
									tree.destroy();

									delete instance.TREEVIEWS[vocabId];
								}
							}
						}

						
						var resourceURL = Liferay.PortletURL.createResourceURL(); 
						resourceURL.setResourceId("/assetcategories/get-categories");
						resourceURL.setParameter("p_p_id", "com_worth_uea_common_categories_taglib_CategorySelectorInteractionsPortlet")
						resourceURL.setParameter("vocabularyId", vocabularyId);
						
						instance.TREEVIEWS[vocabularyId] = new A.TreeView(
							{
								children: [vocabularyRootNode],
								io: {
									cfg: {
										on: {
											success: function(event) {
												var treeViews = instance.TREEVIEWS;

												var tree = treeViews[vocabularyId];

												var children = tree.get('children');

												if (!children || !children.length || !children[0].hasChildNodes()) {
													tree.destroy();

													delete treeViews[vocabularyId];
												}
											}
										}
									},
									formatter: A.bind('_formatJSONResult', instance),
									url: resourceURL.toString()
									
								}
							}
						).render(popup.entriesNode);
					}
				}
			}
		);

		Liferay.UeaAssetCategoriesSelector = UeaAssetCategoriesSelector;
	},
	'',
	{
		requires: ['aui-tree', 'liferay-asset-tags-selector']
	}
);
;(function() {
	var adjustScrollTop = function() {
		var controlMenu;
		var controlMenuId;
		var controlMenuScroll;
		var errorFieldLabel;
		var labelScroll;

		errorFieldLabel = document.querySelector('.form-group.has-error .control-label');

		if (errorFieldLabel) {
			labelScroll = (errorFieldLabel.clientHeight || 0);

			window.scrollBy(0, -labelScroll);
		}

		if (Liferay.ControlMenu) {
			controlMenuId = Liferay.ControlMenu._namespace + 'ControlMenu';
			controlMenu = document.getElementById(controlMenuId);

			if (controlMenu) {
				controlMenuScroll = (controlMenu.offsetHeight || 0);

				window.scrollBy(0, -controlMenuScroll);
			}
		}
	};

	var handleFormRegistered = function(event) {
		if (event.form && event.form.formValidator) {
			AUI().Do.after(
				adjustScrollTop,
				event.form.formValidator,
				'focusInvalidField'
			);
		}
	};

	Liferay.on('form:registered', handleFormRegistered);
}());
