/*##################################################|*/
/* #CMS# */
(function($) {
// CMS.$ will be passed for $
$(document).ready(function () {
	/*!
	 * TreeManager
	 * Handles treeview
	 * TODO this will be refactored in 3.1
	 */
	CMS.TreeManager = new CMS.Class({
		options: {
			'lang': {}
		},
		initialize: function (options) {
			this.options = $.extend(true, {}, this.options, options);
			// load internal functions
			if(!this.options.settings.filtered) {
				this.setupFunctions();
				this.setupTreePublishing();
				this.setupUIHacks();
				this.setupGlobals();
				this.setupTree();
				// init tree component
				initTree();
			} else {
				// when filtered is active, prevent tree actions
				this.setupUIHacks();
			}
		},
		setupFunctions: function () {
			var that = this;
			$.syncCols = function(){
				$('#sitemap .col-softroot').syncWidth(0);
				$('#sitemap .col-apphook').syncWidth(0);
				$('#sitemap .col-language').syncWidth(0);
				$('#sitemap .col-navigation').syncWidth(0);
				$('#sitemap .col-actions').syncWidth(0);
				$('#sitemap .col-info').syncWidth(0);
				that.refreshColumns.call($('ul.tree-default li'));
			};
			/* Colums width sync */
			$.fn.syncWidth = function(max) {
				var visible = false;
				$(this).each(function() {
					if($(this).is(':visible')) {
						visible = true;
						var val= $(this).width();
						if(val > max){
							max = val;
						}
					}
				});
				if (visible && max > 0) {
					$(this).each(function() {
						$(this).css('width', max);
					});
				}
			};
			// jquery.functional
			$.curry = function(fn) {
				if (arguments.length < 2) return fn;
				args = $.makeArray(arguments).slice(1, arguments.length);
				return function() {
					return fn.apply(this, args.concat($.makeArray(arguments)));
				}
			};
			$.__callbackPool = {};
			$.callbackRegister = function(name, fn /*, arg0, arg1, ..*/){
				if (arguments.length > 2) {
					// create curried function
					fn = $.curry.apply(this, $.makeArray(arguments).slice(1, arguments.length));
				}
				$.__callbackPool[name] = fn;
				return name;
			};
			$.callbackCall = function(name/*, extra arg0, extra arg1, ..*/){
				if (!name || !name in $.__callbackPool) {
					throw "No callback registered with name: " + name;
				}
				$.__callbackPool[name].apply(this, $.makeArray(arguments).slice(1, arguments.length));
				$.callbackRemove(name);
				return name;
			};
			$.callbackRemove = function(name) {
				delete $.__callbackPool[name];
			};
			// very simple yellow fade plugin..
			$.fn.yft = function(){
				this.effect("highlight", {}, 1000);
			};
			// jquery replace plugin :)
			$.fn.replace = function(o) {
				return this.after(o).remove().end();
			};
		},
		setupTreePublishing: function () {
			// ADD DIRECT PUBLISHING
			var that = this;
			var tree = $('.tree');
			var langTrigger = '.col-language .trigger-tooltip span';
			var langTooltips = '.language-tooltip';
			var langTimer = function () {};
			var langDelay = 100;
			var langFadeDuration = 200;
			// show the tooltip
			tree.delegate(langTrigger, 'mouseenter', function () {
				var el = $(this).closest('.col-language').find('.language-tooltip');
				var anchors = el.find('a');
				var span = $(this);
				// clear timer
				clearTimeout(langTimer);
				// cancel if tooltip already visible
				if(el.is(':visible')) return false;
				// set correct position
				el.css('right', 20 + $(this).position().left);
				// figure out what should be shown
				anchors.hide();
				if(span.hasClass('unpublished') || span.hasClass('unpublishedparent')) anchors.eq(1).show();
				if(span.hasClass('published')) anchors.eq(0).show();
				if(span.hasClass('dirty')) anchors.show().parent().addClass('language-tooltip-multiple');
				// hide all elements
				$(langTooltips).fadeOut(langDelay);
				// use a timeout to display the tooltip
				langTimer = setTimeout(function () {
					el.stop(true, true).fadeIn(langFadeDuration);
				}, langDelay);
			});
			// hide the tooltip when leaving the area
			tree.delegate(langTrigger, 'mouseleave', function () {
				// clear timer
				clearTimeout(langTimer);
				// hide all elements
				langTimer = setTimeout(function () {
					$(langTooltips).fadeOut(langFadeDuration);
				}, langDelay * 2);
			});
			// reset hiding when entering the tooltip itself
			tree.delegate(langTooltips, 'mouseover', function () {
				// clear timer
				clearTimeout(langTimer);
			});
			tree.delegate(langTooltips, 'mouseleave', function () {
				// hide all elements
				langTimer = setTimeout(function () {
					$(langTooltips).fadeOut(langFadeDuration);
				}, langDelay * 2);
			});
			// attach double check event if publish or unpublish should be triggered
			tree.delegate('.language-tooltip a', 'click', function (e) {
				e.preventDefault();
				// cancel if not confirmed
				if(!confirm(that.options.lang.publish.replace('ยง', $(this).text().toLowerCase()))) return false;
				// publish page and update
				window.location.href = $(this).attr('href');
			});
		},
		setupUIHacks: function () {
			// enables tab click on title entry to open in new window
			$('.tree').delegate('.col1 .title', 'click', function (e) {
				if(!e.metaKey) {
					window.top.location.href = $(this).attr('href');
				} else {
					window.open($(this).attr('href'), '_blank');
				}
			});
			// adds functionality to the filter
			$('#changelist-filter-button').bind('click', function () {
				$("#changelist-filter").toggle();
			});
			// set correct active entry
			if(window.parent && window.parent.CMS && window.parent.CMS.config) {
				var page_id = window.parent.CMS.config.request.page_id;
				$('div[data-page_id="'+page_id+'"]').addClass('cont-active');
			}
		},
		setupGlobals: function () {
			var that = this;
			var msg = '';
			var parent = null;
			window.moveSuccess = function(node){
				$.syncCols();
				msg = $(''+that.options.lang.success+'');
				parent = window.parent;
				node.after(msg);
				node.parent().find('.col2').hide();
				msg.fadeOut(1000, function () {
					node.parent().find('.col2').show()
				});
				// check for reload changes
				if(window.self !== window.top) {
					window.parent.CMS.API.Helpers.reloadBrowser(false, false, true);
					window.parent.CMS.API.Toolbar.openMessage(that.options.lang.changes, false, 0);
				}
			};
			window.moveError = function(node,message){
				if(message && message !== 'error') {
					msg = $(''+message+'');
				}
				else {
					msg = $(''+that.options.lang.error+'');
				}
				node.parent().find('.col2').hide();
				node.after(msg);
			};
		},
		setupTree: function () {
			var that = this;
			var tree;
			// global initTree function
			initTree = function(){
				tree = new tree_component();
				var options = {
					rules: {
						clickable: "all",
						renameable: "none",
						deletable: "all",
						creatable: "all",
						draggable: "all",
						dragrules: "all",
						droppable: "all",
						metadata : "mdata",
						use_inline: true
						//droppable : ["tree_drop"]
					},
					path: false,
					ui: {
						dots: true,
						rtl: false,
						animation: 0,
						hover_mode: true,
						//theme_path: script_url_path() + "/../jstree/themes/",
						a_class: "title"
					},
					cookies : {
						prefix: "djangocms_nodes"
					},
					callback: {
						beforemove  : function(what, where, position) {
							item_id = what.id.split("page_")[1];
							target_id = where.id.split("page_")[1];
							old_node = what;
							if($(what).parent().children("li").length > 1){
								if($(what).next("li").length){
									old_target = $(what).next("li")[0];
									old_position = "right";
								}
								if($(what).prev("li").length){
									old_target = $(what).prev("li")[0];
									old_position = "left";
								}
							}else{
								if($(what).attr("rel") != "topnode"){
									old_target = $(what).parent().parent()[0];
									old_position = "inside";
								}
							}
							addUndo(what, where, position);
							return true;
						},
						onmove: function(what, where, position){
							item_id = what.id.split("page_")[1];
							target_id = where.id.split("page_")[1];
							if (position == "before") {
								position = "left";
							}else if (position == "after") {
								position = "right";
							}else if(position == "inside"){
								position = "last-child";
							}
							moveTreeItem(what, item_id, target_id, position, false);
						},
						onload: function () {
							setTimeout(function () {
								reCalc();
							}, 250);
						}
					}
				};
				if (!$($("div.tree").get(0)).hasClass('root_allow_children')){
					// disalow possibility for adding subnodes to main tree, user doesn't
					// have permissions for this
					options.rules.dragrules = ["node inside topnode", "topnode inside topnode", "node * node"];
				}
				tree.init($("div.tree"), options);
			};
			selected_page = false;
			action = false;
			var _oldAjax = $.ajax;
			$.ajax = function(s){
				// just override ajax function, so the loader message gets displayed
				// always
				$('#loader-message').show();
				callback = s.success || false;
				s.success = function(data, status){
					if (callback) {
						callback(data, status);
					}
					$('#loader-message').hide();
				};
				// just for debuging!!
				/*s.complete = function(xhr, status) {
					if (status == "error" && that.options.settings.debug) {
						$('body').before(xhr.responseText);
					}
				}*/
				// end just for debuging
				// TODO: add error state!
				return _oldAjax(s);
			};
			function refresh(){
				window.location = window.location.href;
			}
			function refreshIfChildren(pageId){
				return $('#page_' + pageId).find('li[id^=page_]').length ? refresh : function(){ return true; };
			}
			/**
			 * Loads remote dialog to dialogs div.
			 *
			 * @param {String} url
			 * @param {Object} data Data to be send over post
			 * @param {Function} noDialogCallback Gets called when response is empty.
			 * @param {Function} callback Standard callback function.
			 */
			function loadDialog(url, data, noDialogCallback, callback){
				if (data === undefined) data = {};
				$.post(url, data, function(response) {
					if (response == '' && noDialogCallback) noDialogCallback();
					$('#dialogs').empty().append(response);
					if (callback) callback(response);
				});
			}
			// let's start event delegation
			$('#changelist li').click(function(e) {
				// I want a link to check the class
				if(e.target.tagName == 'IMG' || e.target.tagName == 'SPAN') {
					target = e.target.parentNode;
				} else {
					target = e.target;
				}
				var jtarget = $(target);
				if(jtarget.hasClass("move")) {
					// prepare tree for move / cut paste
					var id = e.target.id.split("move-link-")[1];
					if(id==null){
						id = e.target.parentNode.id.split("move-link-")[1];
					}
					var page_id = id;
					selected_page = page_id;
					action = "move";
					$('span.move-target-container, span.line, a.move-target').show();
					$('#page_'+page_id).addClass("selected");
					$('#page_'+page_id+' span.move-target-container').hide();
					e.stopPropagation();
					return false;
				}
				if(jtarget.hasClass("copy")) {
					// prepare tree for copy
					id = e.target.id.split("copy-link-")[1];
					if(id==null){
						id = e.target.parentNode.id.split("copy-link-")[1];
					}
					selected_page = id;
					action = mark_copy_node(id);
					e.stopPropagation();
					return false;
				}
				if(jtarget.hasClass("viewpage")) {
					var view_page_url = $('#' + target.id + '-select').val();
					if(view_page_url){
						window.open(view_page_url);
					}
				}
				if(jtarget.hasClass("addlink")) {
					if (!/#$/g.test(jtarget.attr('href'))) {
						// if there is url instead of # inside href, follow this url
						// used if user haves add_page
						return true;
					}
					$("tr").removeClass("target");
					$("#changelist table").removeClass("table-selected");
					page_id = target.id.split("add-link-")[1];
					selected_page = page_id;
					action = "add";
					$('tr').removeClass("selected");
					$('#page-row-'+page_id).addClass("selected");
					$('.move-target-container').hide();
					$('a.move-target, span.line, #move-target-'+page_id).show();
					e.stopPropagation();
					return false;
				}
				// don't assume admin site is root-level
				// grab base url to construct full absolute URLs
				admin_base_url = document.URL.split("/cms/page/")[0] + "/";
				// in navigation
				if(jtarget.hasClass('navigation-checkbox')) {
					e.stopPropagation();
					var pageId = jtarget.attr('name').split('navigation-')[1];
					var language = jtarget.closest('.cont').find('a[lang]').attr('lang') || '';
					// if I don't put data in the post, django doesn't get it
					reloadItem(jtarget, admin_base_url + 'cms/page/' + pageId + '/change-navigation/?language=' + language, { 1:1 });
				}
				 // lazy load descendants on tree open
				if(jtarget.hasClass("closed")) {
					// only load them once
					if(jtarget.find('ul > li').length == 0 && !jtarget.hasClass("loading")) {
						// keeps this event from firing multiple times before
						// the dom as changed. it still needs to propagate for
						// the other click event on this element to fire
						jtarget.addClass("loading");
						var pageId = $(jtarget).attr("id").split("page_")[1];
						var language = $(jtarget).children('div.cont').children('div.col1').children('.title').attr('lang')
						$.get(admin_base_url + "cms/page/" + pageId + "/" + language + "/descendants/", {}, function(r, status) {
							jtarget.children('ul').append(r);
							// show move targets if needed
							if($('span.move-target-container:visible').length > 0) {
								jtarget.children('ul').find('a.move-target, span.move-target-container, span.line').show();
							}
							reCalc();
						});
					} else{
						reCalc();
					}
				}
				if(jtarget.hasClass("move-target")) {
					if(jtarget.hasClass("left")){
						position = "left";
					}
					if(jtarget.hasClass("right")){
						position = "right";
					}
					if(jtarget.hasClass("last-child")){
						position = "last-child";
					}
					target_id = target.parentNode.id.split("move-target-")[1];
					if(action=="move") {
						moveTreeItem(null, selected_page, target_id, position, tree);
						$('.move-target-container').hide();
					}else if(action=="copy") {
						site = $('#site-select')[0].value;
						copyTreeItem(selected_page, target_id, position, site);
						$('.move-target-container').hide();
					}else if(action=="add") {
						site = $('#site-select')[0].value;
						window.location.href = window.location.href.split("?")[0].split("#")[0] + 'add/?target='+target_id+"&position="+position+"&site="+site;
					}
					e.stopPropagation();
					return false;
				}
				return true;
			});
			$("div#sitemap").show();
			function reCalc(){
				$.syncCols();
			}
			$(window).bind('resize', reCalc);
			/* Site Selector */
			$('#site-select').change(function(){
				var form = $(this).closest('form');
				// add correct value for copy
				if(action === 'copy') $('#site-copy').val(selected_page);
				// submit form
				form.submit();
			});
			//
			// If an A element has a data-attribute 'alt-class'. At this time,
			// this is only the edit button in the page-tree, but could be
			// more in future. It is important that the CSS be written in such
			// a manner that the alt-class is defined after the normal class,
			// so that it can be overridden when the alt-key is depressed.
			//
			// NOTE: This 'preview' part of the 'alt-click to [alternative
			// function]' feature may not work in some environments (Windows
			// in a some virtual machine environments, notably), but is only a
			// nice-'extra', not a requirement for the feature.
			//
			$(document).on('keydown keyup', function(evt){
				if (evt.which === 18) {
					$('a[data-alt-class]').each(function(){
						var self = $(this);
						self.toggleClass(self.data('alt-class'), evt.type === 'keydown');
					})
				}
			});
			//
			// If the A-element has a data-attribute 'alt-href', then this
			// click-handler uses that instead of the normal href attribute as
			// the click-destination. Again, currently this is only on the
			// edit button, but could be more in future.
			//
			$('a[data-alt-href]').on('click', function(evt){
				var href;
				evt.preventDefault();
				if (evt.shiftKey) {
					href = $(this).data('alt-href');
				}
				else {
					href = $(this).attr('href');
				}
				window.location = href;					
			});
			var copy_splits = window.location.href.split("copy=");
			if(copy_splits.length > 1){
				var id = copy_splits[1].split("&")[0];
				var action = mark_copy_node(id);
				selected_page = id;
			}
			function copyTreeItem(item_id, target_id, position, site){
				if (that.options.settings.permission) {
					return loadDialog('./' + item_id + '/dialog/copy/', {
						position:position,
						target:target_id,
						site:site,
						callback: $.callbackRegister("_copyTreeItem", _copyTreeItem, item_id, target_id, position, site)
					});
				}
				return _copyTreeItem(item_id, target_id, position, site);
			}
			function _copyTreeItem(item_id, target_id, position, site, options) {
				var data = {
					position:position,
					target:target_id,
					site:site
				};
				data = $.extend(data, options);
				$.post("./" + item_id + "/copy-page/", data, function(decoded) {
					response = decoded.content;
					status = decoded.status;
					if(status==200) {
						// reload tree
						window.location = window.location.href;
					}else{
						alert(response);
						moveError($('#page_'+item_id + " div.col1:eq(0)"),response);
					}
				});
			}
			function mark_copy_node(id){
				$('a.move-target, span.move-target-container, span.line').show();
				$('#page_'+id).addClass("selected");
				$('#page_'+id).parent().parent().children('div.cont').find('a.move-target.first-child, span.second').hide();
				$('#page_'+id).parent().parent().children('ul').children('li').children('div.cont').find('a.move-target.left, a.move-target.right, span.first, span.second').hide();
				return "copy";
			}
			/**
			 * Reloads tree item (one line). If some filtering is found, adds
			 * filtered variable into posted data.
			 *
			 * @param {HTMLElement} el Any child element of tree item
			 * @param {String} url Requested url
			 * @param {Object} data Optional posted data
			 * @param {Function} callback Optional calback function
			 */
			function reloadItem(el, url, data, callback, errorCallback) {
				if (data === undefined) data = {};
				if (/\/\?/ig.test(window.location.href)) {
					// probably some filter here, tell backend, we need a filtered
					// version of item
					data['fitlered'] = 1;
				}
				function onSuccess(response, textStatus) {
					var status = true;
					var target = null;
					if(callback) status = callback(response, textStatus);
					if(status) {
						if (/page_\d+/.test($(el).attr('id'))) {
							// one level higher
							target = $(el).find('div.cont:first');
						} else {
							target = $(el).parents('div.cont:first');
						}
						var parent = target.parent();
						// remove the element if something went wrong
						if(response == 'NotFound') return parent.remove();
						var origin = $('.messagelist');
						target.replace(response);
						var messages = $(parent).find('.messagelist');
						if(messages.length) {
							origin.remove();
							messages.insertAfter('.breadcrumbs');
						}
						parent.find('div.cont:first').yft();
						// ensure after removal everything is aligned again
						$(window).trigger('resize');
					}
				}
				$.ajax({
					'type': 'POST',
					'data': data,
					'url': url,
					'success': onSuccess,
					'error': function (XMLHttpRequest, textStatus, errorThrown) {
						// errorCallback is passed through the reloadItem function
						if(errorCallback) errorCallback(XMLHttpRequest, textStatus, errorThrown);
					},
					'xhr': (window.ActiveXObject) ? function(){try {return new window.ActiveXObject("Microsoft.XMLHTTP");} catch(e) {}} : function() {return new window.XMLHttpRequest();}
				});
			}
			function moveTreeItem(jtarget, item_id, target_id, position, tree){
				reloadItem(
					jtarget, "./" + item_id + "/move-page/",
					{ position: position, target: target_id },
					// on success
					function(decoded,textStatus){
						response = decoded.content;
						status = decoded.status;
						if(status==200) {
							if (tree) {
								var tree_pos = {'left': 'before', 'right': 'after'}[position] || 'inside';
								tree.moved("#page_" + item_id, $("#page_" + target_id + " a.title")[0], tree_pos, false, false);
							} else {
								moveSuccess($('#page_'+item_id + " div.col1:eq(0)"));
							}
							return false;
						}
						else {
							moveError($('#page_'+item_id + " div.col1:eq(0)"),response);
							return false;
						}
					}
				);
			}
			var undos = [];
			function addUndo(node, target, position){
				undos.push({node:node, target:target, position:position});
			}
		},
		refreshColumns: function () {
			$('div.col2').children('div').each(function(index, item){
				$(item).css('display', 'block');
			});
			var min_width = 100000;
			var max_col2_width = 0;
			var max_col2 = null;
			$(this).each(function() {
				var cont = $(this).children('div.cont');
				if (!cont.is(':visible')) {
					return;
				}
				var col1 = cont.children('div.col1');
				var col2 = cont.children('div.col2');
				var col1_width = col1.outerWidth(true);
				var col2_width = col2.outerWidth(true);
				var total_width = cont.outerWidth(true);
				var dif = total_width - col1_width;
				if(dif < min_width){
				   min_width = dif;
				}
				if(col2_width > max_col2_width){
					max_col2_width = col2_width;
					max_col2 = col2
				}
			});
			var offset = 50;
			var w = 0;
			var hidden_count = 0;
			var max_reached = false;
			if(max_col2){
				max_col2.children('div').each(function(){
					if(!max_reached){
						w += $(this).outerWidth(true);
					}
					if(max_reached || w > (min_width - offset)){
						hidden_count = hidden_count + 1;
						max_reached = true
					}
				});
				if(hidden_count){
					$(this).each(function() {
						$(this).children('div.cont').children('div.col2').children('div').slice(-hidden_count).each(function(){
							$(this).css('display', 'none');
						})
					});
					$('div#sitemap ul.header div.col2').children().slice(-hidden_count).each(function(){
						$(this).css('display','none');
					})
				}
			}
		}
	});
});
})(CMS.$);