/**
*
*/
var CJTToolBox = {
	forms : {templatesLookupForm : []}
}; // Application name spaces structure.

/*
*
*
*/
var CJTBlocksPage;

/*
*
*
*/
(function($){

	/*
	*
	*
	*/
	CJTBlocksPage = {

		/*
		*
		*
		*
		*/
		blocksContainer : null,
				
		/*
		*
		*
		*
		*/
		blocksForm : null,
		
		/*
		*
		*
		*
		*/
		blocks : null,

		/**
		*
		*
		*
		*
		*
		*/
		changes : [],
		
		/*
		*
		*
		*
		*/		
		deletedBlocks : [],
		
		/*
		*
		*
		*
		*/
		loadingElement : null,
		
		/*
		*
		*
		*
		*/		
		loadingImage : null,

		/**
		*
		*
		*
		*/
		pageId : 'cjtoolbox',
		
		/**
		*
		*
		*
		*/
		server : null,
		
		/**
		*
		*
		*
		*/
		toolboxes : {
		
			/**
			*
			*
			*
			*/
			toolboxes : null,
			
			/*
			*
			*
			*
			*/
			css : function(role, value) {
				this.toolboxes.each(
					function() {
						$(this).css(role, value);
					}
				);
			},
			
			/**
			* put your comment there...
			* 
			*/
			getIButton : function(buttonName, method, params) {
				var dispatcher = {
					/**
					* put your comment there...
					* 
					*/
					dispatch : function(params) {
						var result = {};
						CJTBlocksPage.toolboxes.toolboxes.each(
							function(index) {
								// Get button object.
								var button = this.CJTToolBox.buttons[buttonName];
								// Dispatch button method.
								result[index] = button[method].apply(button, params);
							}
						);
						return result;
					}
				};
				// When created and params is passed vall dispatch.
				if (params != undefined) {
					dispatcher.dispatch(params);
				}
				// Return dispatched handle object.
				return dispatcher;
			},
			
			/**
			*
			*
			*
			*/
			enable : function(buttonName, enable) {
				this.toolboxes.each(
					function() {
						var button = this.CJTToolBox.buttons[buttonName];
						button.enable(enable);
					}
				);
			},
			
			/**
			*
			*
			*
			*/
			isEnabled : function(buttonName) {
				var isEnabled = true;
				this.toolboxes.each(
					function() {
						var button = this.CJTToolBox.buttons[buttonName];
						isEnabled &= button.isEnabled();
					}
				);
				return isEnabled;
			},
			
			/*
			*
			*
			*
			*/
			switchState : function(state) {
				var buttonsToHide;
				switch (state) {
					case 'restore':
						// Hide Add New Block, Save all changes, location tools and state tools buttons.
						buttonsToHide = ['save-changes', 'add-block', 'state-tools', 'location-tools'];
					break;
					default:
					  // Hide Restore & Cancel Restore buttons.
					  buttonsToHide = ['restore', 'cancel-restore'];
					break;
				}
				// Hide buttons.
				this.toolboxes.each(
					// Get all toolboxes.
					function(tbIndex, toolbox) {
						// Hide all buttons for each toolbox.
						$.each(buttonsToHide,
							function(btnIndex, buttonName) {
								var button = toolbox.CJTToolBox.buttons[buttonName];
								button.jButton.css('display', 'none');
							}
						);
					}
				);
				// Display Toolboxes.
				this.css('visibility', 'visible');
			}
		},
				
		/**
		*
		*
		*
		*/
		_onaddnew : function(event, params) {
			// Server request.
			var requestData = {
				// Server paramerers.
				viewName : 'blocks/new',
				// Thick box parameters.
				width : 450,
				height: 230,
				position : params.toolbox.position,
				TB_iframe : true // Must be last one Thickbox removes this and later params.
			};
			var url = CJTBlocksPage.server.getRequestURL('blocksPage', 'get_view', requestData);
			// Popup form.
			tb_show(CJTBlocksPageI18N.addNewBlockDialogTitle, url);
		},
		
		/**
		* put your comment there...
		* 
		*/
		_oncancelrestore : function() {
			window.location.href = window.location.href.replace(/&backupId=\d+/, '');
		},
		
		/**
		* put your comment there...
		* 
		*/
		_onmanagesettings : function() {
			var params = {width: 700, height: 600,TB_iframe : true};
			var settingsFormURL = CJTBlocksPage.server.getRequestURL('settings', 'manageForm', params);
			tb_show(CJTBlocksPageI18N.settingsFormTitle, settingsFormURL);
		},
		
		/**
		* put your comment there...
		* 
		*/
		_onmanagetemplates : function() {
			var params = {width: '100%', height: '100%', TB_iframe : true};
			var url = CJTBlocksPage.server.getRequestURL('templatesManager', 'display', params);
			tb_show(CJTBlocksPageI18N.manageTemplatesFormTitle, url);
			// Get thickbox form element.
			var thickboxForm = $('#TB_window');
			// Style thickbox.
			thickboxForm.css({
				'position' : 'fixed', 
				'left' : '0px',
				'top' : '4px', 
				'margin-left' : '5px',
				'margin-top': '0px',
				'width' : '99%',
				'height' : ((jQuery(window).height() - 40) + 'px'),
				'z-index' : 1000000
			});
			// Set Iframe style.
			thickboxForm.find('iframe').css({
				width : '100%',
				height : '100%'
			});
		},
		
		/**
		*
		*
		*
		*
		*/
		_onmanagebackups : function() {
			// Server request.
			var requestData = {
				// Thick box parameters.
				width : 480,
				height: 400,
				TB_iframe : true // Must be last one Thickbox removes this and later params.
			};
			var url = CJTBlocksPage.server.getRequestURL('blocksBackups', 'list', requestData);
			tb_show(CJTBlocksPageI18N.manageBackupsDialogTitle, url);
		},
		
		/**
		* put your comment there...
		* 
		*/
		_onrestore : function() {
			// Confirm restore.
			var doRestore = confirm(CJTBlocksPageI18N.confirmRestoreBlocks);
			if (doRestore) {
				// Disable restore button for all toolboxes.
				var ibCancelRestore = CJTBlocksPage.toolboxes.getIButton('cancel-restore', 'enable', [false]);
				// SHow loading for restore buttons.
				var ibRestoreLoader = CJTBlocksPage.toolboxes.getIButton('restore', 'loading', [true, false]);
				// Send request to server.
				var requestData = {backupId : CJTBlocksPage.isRestore()};
				CJTBlocksPage.server.send('blocksBackups', 'restore', requestData)
				.success(
					function() {
						// Refresh the page without backupId parameter.
						CJTBlocksPage._oncancelrestore();
					}
				)
				.error(
					function() {
						// Notify user error.
						alert(CJTBlocksPageI18N.unableToRestoreBackup);
						// Stop loading progress.
						ibCancelRestore.dispatch([true]);
						ibRestoreLoader.dispatch([false, true]);
					}
				);
			}
		},
		
		/**
		*
		*
		*
		*
		*/
		_onsavechanges : function() {
			var multiOperationServer = CJTBlocksPage.server.multiOperation;
			var data = {
				deletedBlocks : CJTBlocksPage.deletedBlocks,
				calculatePinPoint : 1,
				createRevision : 1
			};
			// Save block data.
			multiOperationServer.trigger('save').send('post', data).success(
				function() {
					// Reset deleted blocks array.
					CJTBlocksPage.deletedBlocks = [];
					CJTBlocksPage.changes = [];
					CJTBlocksPage.toolboxes.enable('save-changes', false);
					// Save blocks order.
					CJTBlocksPage.saveBlocksOrder();
					// Save closed postboxes.
					postboxes.save_state(CJTBlocksPage.pageId);
				}
			)
		},
		
		/**
		* put your comment there...
		* 
		*/
		_onupdateorder : function() {
			var container = CJTBlocksPage.blocksContainer;
			var orders = container.data('cjtOrders');
			var newOrders = container.sortable('toArray');
			var isChanged = (orders.join('') != newOrders.join(''));
			// Notify changes!
			CJTBlocksPage.blockContentChanged(0, isChanged);
		},
		
		/**
		*
		*
		*
		*
		*
		*/
		_onunload : function() {
			// If there is any deleted blocks or any block changed
			// notify user that there is a change need to be saved;
			if (!CJTBlocksPage.deletedBlocks.length) {
				// If there is no changes in any block save-changed button shouild be disabled.
				if (!CJTBlocksPage.toolboxes.isEnabled('save-changes')) {
					return;
				}
			}
			return CJTBlocksPageI18N.confirmNotSavedChanges;
		},
		
		/**
		*
		*
		*
		*/
		addBlock : function(position, content) {
			var sortable = CJTBlocksPage.blocksContainer;
			// New Block positions to jQuery methods mapping.
			var positions = {top : 'prepend', bottom : 'append'};
			var positionMethod = positions[position];
			// Apply toggling: The only way to apply postboxes it via postboxes.add_postbox_toggles method.
			// Method finding all .postbox elements and bind to click.
			// Exists .postbox(s) will bind to click event twice and the result is
			// not toggling. We need to remove .postbox of exists and apply only
			// to the newly added one.
			var currentBlocks = CJTBlocksPage.blocks.getBlocks();
			currentBlocks.removeClass('postbox').addClass('applying-postbox-to-new-block');
			// Add block to the selected position.
			sortable[positionMethod](content);
			// Note: Only new block will be returned because its the only one with .postbox class.
			var newAddedBlock = CJTBlocksPage.blocks.getBlocks().eq(0);
			// Add block element.
			var blockId =newAddedBlock.CJTBlock({}).get(0).CJTBlock.block.get('id');
			// SET ORDER: Add the new block as first or last Block without saving the unsave orders! //
			// JUST USE THE CURRENT HASHED (SAVED ON SERVER) + ADDING THE NEW BLOCK!
			var newBlockOrderName = CJTBlocksPage.blocks.getSortableName(blockId);
			var order = $.merge([], sortable.data('cjtOrders'));
			(position == 'top') ? order.unshift(newBlockOrderName) : order.push(newBlockOrderName);
			CJTBlocksPage.saveCustomOrder(order);
			// If this is the first block hide the intro and show normal sortable.
			if (!CJTBlocksPage.blocks.hasBlocks()) {
				// Remove intro text.
				CJTBlocksPage.intro.css({display : 'none'});
				CJTBlocksPage.blocksContainer.css({display : 'block'});
				// Set has block value.
				CJTBlocksPage.blocks.hasBlocks(true);
			}
			// Refresh toggling.
			postboxes.add_postbox_toggles('cjtoolbox');
			currentBlocks.removeClass('applying-postbox-to-new-block').addClass('postbox');
			// Put new block into focus.
			newAddedBlock.get(0).CJTBlock.focus();
			return newAddedBlock;
		},

		/**
		*
		*
		*
		*
		*
		*/
		blockContentChanged : function(id, isChanged) {
			var enable = CJTBlocksPage.blocks.calculateChanges(CJTBlocksPage.changes, id, isChanged);
			// Enable/Disable save button in all Toolboxes.
			CJTBlocksPage.toolboxes.enable('save-changes', enable);
		},
		
		/**
		*
		*
		*
		*/
		deleteBlocks : function(blocks) {
			// Delete block.
			$.each(blocks,
				function(index, block) {
					var blockPlg = block.CJTBlock;
					var blockId = blockPlg.block.get('id');
					CJTBlocksPage.deletedBlocks.push(blockId);
					// Notify Code Files Manager.
					// Only for Loaded Blocks.
					blockPlg.codeFile && blockPlg.codeFile.ondeleteblock();	
					$(block).remove();
					// Notify save change.
					CJTBlocksPage.blockContentChanged(blockId, true);
				}
			);
			// If last block call _ondeleteall.
			var existsBlocks = CJTBlocksPage.blocks.getBlocks();
			if (existsBlocks.length == 0) {
				CJTBlocksPage.blocksContainer.css('display', 'none');
				CJTBlocksPage.intro.css('display', 'block');
				// Mark as has no blocks.
				CJTBlocksPage.blocks.hasBlocks(false);
			}
		},
		
		/*
		*
		*
		*
		*/		
		getStateName : function() {
			var stateName = this.isRestore() ? 'restore' : '';
			return stateName;
		},
		
		/*
		*
		*
		*
		*/
		init : function() {
			// Initialize object vars.
			CJTBlocksPage.blocksForm = $('#cjtoolbox-blocks-page-form');
			// Prevent form submission, ALL is done through AJAX.
			// Pressing Enter in text fields might caused the whole page to be refreshed.
			CJTBlocksPage.blocksForm.get(0).onsubmit = function() {return false;}
			CJTBlocksPage.blocksContainer = $('div#normal-sortables');
			CJTBlocksPage.intro = CJTBlocksPage.blocksForm.find('#cjt-noblocks-intro');
			CJTBlocksPage.server = CJTServer;
			CJTBlocksPage.server.multiOperation = new CJTBlocksAjaxMultiOperations('blocksPage', 'save_blocks');
			// Initilize Global-Blocks Conponents.
			CJTBlockCodeFileView.initialize();
			// Make sure CJTBlocks is ready.
			CJTBlocksPage.blocks = new CJTBlocks();
			// Initialize Toolboxes.
			CJTBlocksPage.toolboxes.toolboxes = CJTBlocksPage.blocksForm.find('.cjt-toolbox-blocks').CJTToolBox({
				handlers : {
					'state-tools' : {
						type : 'Popup',
						params : {_type : {targetElement : '.state-tools'}}
					},
					'location-tools' : {
						type : 'Popup',
						params : {_type : {targetElement : '.location-tools'}}
					},
					'admin-tools' : {
						type : 'Popup',
						params : {_type : {targetElement : '.admin-tools'}}
					},
					'save-changes' : {callback : CJTBlocksPage._onsavechanges, params : {enable : false}},
					'add-block' : {callback : CJTBlocksPage._onaddnew},
					'restore' : {callback : CJTBlocksPage._onrestore},
					'cancel-restore' : {callback : CJTBlocksPage._oncancelrestore},
					'reset-order' : {callback : CJTBlocksPage._onresetorder},
					'manage-backups' : {callback : CJTBlocksPage._onmanagebackups},
					'templates-manager' : {callback : CJTBlocksPage._onmanagetemplates},
					'global-settings' : {callback : CJTBlocksPage._onmanagesettings},
				} 
			});
			
			$( document ).trigger( 'cjtmanagertoolboxloaded', [ CJTBlocksPage ] );
			
			var jBlocks = CJTBlocksPage.blocks.getBlocks();
			
			$( document ).trigger( 'cjtmanagerpreloadblocks', [ CJTBlocksPage.blocksForm, jBlocks ] );
			
			// Activate blocks.
			jBlocks.CJTBlock({state : CJTBlocksPage.getStateName()});
			
			// Hide loading image. #cjt-blocks-loader will be used for other loading later.
			CJTBlocksPage.loadingImage = CJTBlocksPage.blocksForm.find('#cjt-blocks-loader');
			CJTBlocksPage.loadingImage.find('.loading-text').remove();
			CJTBlocksPage.loadingImage.css({
				display : 'none',
				position : 'absolute'
			});
			// If has no blocks hide normal sortable (it takes 50px as min-height).
			if (!CJTBlocksPage.blocks.hasBlocks()) {
				CJTBlocksPage.blocksContainer.css({display : 'none'});
			}
			// Show blocks.
			CJTBlocksPage.blocksForm.find('#post-body').css('display', 'block');
			//// Setup postboxes ////
			postboxes.add_postbox_toggles('cjtoolbox');
			// Cache blocks order to detect order change!
			CJTBlocksPage.blocksContainer.data('cjtOrders', CJTBlocksPage.blocksContainer.sortable('toArray'));
			// Detect order change.
			CJTBlocksPage.blocksContainer.sortable('option', {update: CJTBlocksPage._onupdateorder});				
			// Stop auto save order, orders should be saved only with "Save All Changes" button.
			// Move it to another method that allow us to save order later manually.
			postboxes.manual_save_order = postboxes.save_order;
			postboxes.save_order = function() {};
			// Notify block when postbox get opened.
			postboxes.pbshow = function(id) {
				$('#' + id).get(0).CJTBlock._onpostboxopened();
			};
			// When navigating away notify saving changes.
			window.onbeforeunload = CJTBlocksPage._onunload;
			// Switch blocks page state.
			CJTBlocksPage.switchState(CJTBlocksPage.getStateName());
		},

		/*
		*
		*
		*
		*/		
		isRestore : function() {
			// If there is backupId parameter then this is a restore state.
			var regEx = /backupId=(\d+)/;
			var backupId = false;
			if (regEx.test(window.location.href)) {
				backupId = parseInt(window.location.href.match(regEx)[1]);
			}
			return backupId;
		},
		
		/*
		*
		*
		*
		*/
		main : function()	{
			// Add indexOf function for IE7.
			if (Array.indexOf == undefined) {
				Array.prototype.indexOf = function(value) {
					var index = -1;
					var array = this;
					jQuery.each(array, function(sIndex, sValue) {
						if (sValue == value) {
							index = sIndex;
						  return;
						}
					});
					return index;
				}
			}
			if (String.ucFirst == undefined) {
				String.prototype.ucFirst = function() {
					var newString = [];
					var words = this.split(' ');
					$(words).each(
						function(index, word) {
							newString.push(word.substr(0, 1).toUpperCase() + word.substr(1));
						}
					)
					newString = newString.join(' ');
					return newString;
				}
			}
			// Initialize CJTBlocks page vars and ui.
			jQuery(document).ready(CJTBlocksPage.init);
		},
		
		/**
		* 
		*/
		saveCustomOrder : function(order) {
			// Override jquery sortable plugin!!
			// We  need to handle toArray method when called by postboxes.save_order method!
			 var originalSortable = $.fn.sortable;
			 $.fn.sortable = function(method) {
				 if (method != 'toArray') {
					 throw 'Dummy CJT::jquery.sortable Plugin: only toArray method is supported!';
				 }
				 // Return the passed order instead of the real order!
				 return order;
			 }
			 // Save order.
			 CJTBlocksPage.saveBlocksOrder();
			 // Reset original sortable!
			 $.fn.sortable = originalSortable;
		},
		
		/**
		*
		*
		*
		*
		*
		*/
		saveBlocksOrder : function() {
			var ordersArray = CJTBlocksPage.blocksContainer.sortable('toArray');
			var request = {order : ordersArray.join(',')};
			// Save Blocks order!
			CJTBlocksPage.server.send('blocksPage', 'saveOrder', request).success($.proxy(
				function() {
					// Refresh local cache order!
					CJTBlocksPage.blocksContainer.data('cjtOrders', ordersArray);
				}, this)
			);
		},
		
		/*
		*
		*
		*
		*/
		switchState : function(state) {
			// For now only toolboxes need to switch state.
			CJTBlocksPage.toolboxes.switchState(state);
		}
		
	} // End class.
	
	// This is the entry point to all Javascript codes.
	CJTBlocksPage.main();
	
})(jQuery); // Dont wait for document to be loaded.