/**
 * Wrapper for CKEditor based goodness
 * Written by Matt Mecham for his sins.
 * (c) 2011 IPS, Inc.
 */

IPSCKTools = {
	/**
	 * Get the selected HTML from the editor
	 * @param	object
	 */
	getSelectionHtml: function( editor )
	{
		var selection = editor.getSelection();
		
		if ( CKEDITOR.env.ie )
		{
			try {
				selection.unlock(true);
			} catch(e){}
			
			var text = selection.getNative().createRange().htmlText;
		
			if ( text.toLowerCase().strip() == '<p>&nbsp;</p>' )
			{
				return false;
			}
			
			return text;
		}
		else if ( CKEDITOR.env.opera )
		{
			var selection = selection.getNative();
		
			var range = selection ? selection.getRangeAt(0) : selection.createRange();
			var div   = document.createElement('div');
			div.appendChild( range.cloneContents() );
			
			return div.innerHTML.replace( /<p><\/p>/g, '<p><br /></p>' );
		}
		else
		{
			var range = selection.getNative().getRangeAt( selection.rangeCount -1 ).cloneRange();
			var div   = document.createElement('div');
			div.appendChild( range.cloneContents() );
			
			return div.innerHTML;
		}
	},
	/**
	 * Clean HTML for inserting between tags
	 * @param	object
	 */
	cleanHtmlForTagWrap: function( html )
	{
		var text = html.replace( /<br( \/)?>$/, '' );
		
		return text;
	}
}

/*
 * This is just a wrapper class around the objects to give it a global interface
 */
IPBoard.prototype.textEditor = {
		
	mainStore: $H(),
	lastSetUp: null,
	_tmpContent: '',
	IPS_TEXTEDITOR_POLLING:	10000,			/* 10 seconds */
	IPS_NEW_POST_POLLING:	(2 * 60000),	/* 2 mins */
	IPS_SAVED_MSG:			"<a href='javascript:void()' class='_as_explain desc'>" + ipb.lang['ck_auto_saved'] + "</a>",
	IPS_AUTOSAVETEMPLATE:	"<a href='javascript:void()' class='_as_launch desc'>" + ipb.lang['ck_view_saved'] + "</a>",
	IPS_AUTOSAVEVIEW:		"<div><h3>" + ipb.lang['ck_saved'] + "</h3><div class='row2' style='padding:4px'><div class='as_content'>#{content}</div><div class='as_buttons'><input type='button' class='input_submit _as_restore' value='" + ipb.lang['ck_restore'] + "' /></div>",
	IPS_AUTOSAVEEXPLAIN:	"<div><h3>" + ipb.lang['ck_saved_title'] + "</h3><div class='row2' style='padding:8px'>" + ipb.lang['ck_saved_desc'] + "</div>",
	ajaxUrl:				'',
	
	initialize: function( editorId, options )
	{
		if ( inACP )
		{
			ipb.textEditor.ajaxUrl  = ipb.vars['front_url']; 
			ipb.vars['secure_hash'] = ipb.vars['md5_hash'];
		}
		else
		{
			ipb.textEditor.ajaxUrl  = ipb.vars['base_url'];
		}
		
		/* Insert into main store */
		if ( ! ipb.textEditor.mainStore.get( editorId ) )
		{
			newEditorObject = new ipb.textEditorObjects( editorId, options );
			
			ipb.textEditor.mainStore.set( editorId, newEditorObject );
		}
		
		/* Set up */
		ipb.textEditor.lastSetUp = editorId;
	},
	
	/**
	 * Switches an editor from rte to std or vice-versa
	 */
	switchEditor: function()
	{
		textObj = ipb.textEditor.getEditor();
		isRte   = textObj.isRte();
		ourcontent = textObj.getText();

		var _url  = ipb.textEditor.ajaxUrl + '&app=core&module=ajax&section=editor&do=switch&secure_key=' + ipb.vars['secure_hash'];
		Debug.write( _url );
		Debug.write( 'Fetched editor content: ' + ourcontent );

		new Ajax.Request( _url,
							{
								method: 'post',
								parameters: { 'content' : ourcontent.encodeParam(),
											  'isRte'   : isRte },
								onSuccess: function(t)
								{										    	
									/* No Permission */
									if ( t.responseText != 'nopermission' )
									{
										Debug.write( 'Converted to: ' + t.responseText );
										
										/* Switch the text editor around */
										if ( textObj.isRte() )
										{
											/* Reset flag */
											textObj.setIsRte( false );
											
											/* Hackery! Passing t.responseText through to .setData doesn't allow html entities to parse in the text area
											 * literally, if you pass &#123; it will show &#123; - not good.
											 */
											$$('body').first().insert( new Element( 'code', { 'class': 'hide', 'id': 'xx-new-contents-xx' } ).update( t.responseText ) );
											
											/* Can it sister */
											textObj.CKEditor.setMode( 'source' );
											textObj.insert( $('xx-new-contents-xx').innerHTML, false, true );
											
											$('xx-new-contents-xx').remove();
											
											ipb.Cookie.set( 'rteStatus', 'std' );
											
											/* Update all other editors */
											ipb.textEditor.toggleEditors( 'std' );
											
											/* Update text-direction, since CKE forces LTR in 'source' mode */
											if( isRTL )
											{
												$$('.cke_contents > textarea').each( function(elem) {
													$(elem).setStyle( { textAlign: 'right' } );
												});
											}
										}
										else
										{
											/* Reset flag */
											textObj.setIsRte( true );
											
											try
											{
												textObj.CKEditor.setData( ipb.textEditor.ckPre( t.responseText ) );
											}
											catch( err )
											{
												Debug.write( "CKEditor error: " + err );
											}

											/* Init editor */
											textObj.CKEditor.setMode( 'wysiwyg' );
											
											ipb.Cookie.set( 'rteStatus', 'rte' );

											/* Update all other editors */
											ipb.textEditor.toggleEditors( 'rte' );
										}
									}
								}.bind(this),
								onException: function (t)
								{
									Debug.dir( t );
								}
							} );
		
	},
	
	/*
	 * Change all editor modes besides the current one
	 * (current one is changed inside switchEditor)
	 */
	toggleEditors: function( mode )
	{
		ipb.textEditor.mainStore.each( function( instance ){ 
			if( instance.key != ipb.textEditor.lastSetUp )
			{
				if( mode == 'std' )
				{
					instance.value.setIsRte( false );
					instance.value.CKEditor.setMode( 'source' );
				}
				else
				{
					instance.value.setIsRte( true );
					instance.value.CKEditor.setMode( 'wysiwyg' );
				}
			}
		});
	},
	
	/*
	 * Fetches an editor by ID
	 */
	getEditor: function( editorId )
	{
		editorId = ( ! editorId ) ? ipb.textEditor.getCurrentEditorId() : editorId;

		return ipb.textEditor.mainStore.get( editorId );
	},
	
	/**
	 * Fetches the current focused editor or the last one set up
	 * @returns string	editor id
	 */
	getCurrentEditorId: function()
	{
		if( Object.isUndefined( CKEDITOR ) ){
			return ipb.textEditor.lastSetUp;
		} else {
			if ( CKEDITOR.currentInstance && ipb.textEditor.mainStore.get( CKEDITOR.currentInstance.name ).CKEditor )
			{
				return CKEDITOR.currentInstance.name;
			}
		    else
		    {
		    	return ipb.textEditor.lastSetUp;
		    }
		}
	},
	
	/**
	 * Make safe for CKEditor
	 */
	ckPre: function( text )
	{
		text = text.replace( '<script', '&#60;script' );
		text = text.replace( '</script', '&#60;/script' );
		
		// If the first content is text and not an HTML element, CKEditor throws an error
		// Error: body.getFirst().hasAttribute is not a function
		// Similar to: http://dev.ckeditor.com/ticket/6152
		// We'll just wrap in a span tab to be safe if it doesn't look like HTML is there
		if( text.charAt(0) != '<' )
		{
			// Disabled as we're not using BR mode
			//text = '<p>' + text + '</p>';
			
		}
		
		return text;
	},
	
	/**
	 * Make safe for std editor
	 */
	stdPre: function( text )
	{
		/* &lt; / &gt; is made safe by CKEditor */
		text = text.replace( /&lt;/g, '<' );
		text = text.replace( /&gt;/g, '>' );
		
		/* Properly encoded HTML &amp;#39; isn't parsed in the text area */
		text = text.replace( /&amp;/g, '&' );
				
		text = text.replace( /<br([^>]+?)?>(\n)?/g, '\n' );
		
		return text;
	},
	
	/**
	 * 0 pad times
	 * @param n
	 * @returns
	 */
	pad: function(n)
	{
		return ("0" + n).slice(-2);
	}
};

/*
 * Each CKEditor object is referenced via this class
 */
IPBoard.prototype.textEditorObjects = Class.create( {
	
	editorId: {},
	popups: [],
	cookie: 'rte',
	timers: {},
	options: {},
	CKEditor: null,
	EditorObj: null,
	
	/*------------------------------*/
	/* Constructor 					*/
	initialize: function( editorId, options )
	{
		this.editorId = editorId;
		this.cookie   = ipb.Cookie.get('rteStatus');
		
		this.options  = Object.extend( { type: 	              'full',
										 ips_AutoSaveKey:      false,
										 height:			   0,
										 minimize:             0,
										 minimizeNowOpen:      0,
										 isRte:				   1,
										 bypassCKEditor:	   0,
										 isTypingCallBack:     false,
										 delayInit:			   false,
										 ips_AutoSaveData:     {},
										 ips_AutoSaveTemplate: new Template( ipb.textEditor.IPS_AUTOSAVETEMPLATE ) }, arguments[1] );
		
		/* Do we have an override? */
		this.setIsRte( this.cookie == 'rte' ? 1 : ( this.cookie == 'std' ? 0 : 1 ) );
		
		/* Force STD if iDevice */
		if ( ipb.vars['is_touch'] !== false )
		{
			this.setIsRte( 0 );
			this.options.bypassCKEditor = 1;
		}
	
		/* Create the CKEditor */
		if ( ! this.options.delayInit )
		{
			this.initEditor();
		}
	},
	
	/**
	 * Set RTe status of current editor
	 */
	setIsRte: function( value )
	{
		this.options.isRte = ( value ) ? 1 : 0;
		
		/* Set cookie */
		ipb.Cookie.set( 'rteStatus', ( value ) ? 'rte' : 'std' );
		
		if ( $( 'isRte_' + this.editorId ) )
		{
			 $F( 'isRte_' + this.editorId ) = this.options.isRte;
		}
	},
	
	/**
	 * Returns whether current editor is RTE (ckeditor)
	 */
	isRte: function()
	{
		return this.options.isRte ? 1 : 0;
	},
	
	/**
	 * Fetch editor contents 
	 */
	getText: function()
	{		
		if ( ! this.options.bypassCKEditor && this.CKEditor )
		{
			return this.CKEditor.getData();
		}
		else
		{
			/* If CKEditor isn't beingn used (iOS, etc) */
			if( $( this.editorId ) )
			{
				return $( this.editorId ).value;
			}

			return '';	
		}
	},
	
	/**
	 * Create the CKEditor
	 */
	initEditor: function(initContent)
	{
		/* Bypassing the CKEditor completely? Why so mean? */
		if ( this.options.bypassCKEditor )
		{
			if ( this.options.minimize )
			{
				this.options.minimizeNowOpen = 1;
			}
			
			if ( typeof( initContent ) == 'string' )
			{
				$( this.editorId ).value = initContent;
			}

			return;
		}
		
		/* Start the process of initiating */
		if ( $( this.editorId ).value && this.isRte() )
		{
			$( this.editorId ).value = ipb.textEditor.ckPre( $( this.editorId ).value );
		}
		
		/* RTE init */
		try
		{
			var config	= {
							toolbar:			( this.options.type == 'mini' ? 'ipsmini' : 'ipsfull' ),
							height:				( Object.isNumber( this.options.height ) && this.options.height > 0 ) ? this.options.height : ( this.options.type == 'mini' ? 150 : 300 ),
							ips_AutoSaveKey:	this.options.ips_AutoSaveKey
			};

			/* STD editor? */
			if ( ! this.isRte() )
			{
				config.startupMode	= 'source';
			}
			
			/* Minimized - force ipsmini */
			if ( this.options.minimize )
			{
				config.toolbarStartupExpanded = false;
			}
			
			CKEDITOR.replace( this.editorId, config );
		}
		catch( err )
		{
			Debug.write( 'CKEditor error: ' + err );
		}

		this.CKEditor = CKEDITOR.instances[ this.editorId ];
		
		/* Bug in ckeditor init which treats initContent as event object inside an .on() */
		ipb.textEditor._tmpContent = ( Object.isString(initContent) || Object.isNumber(initContent) ) ? initContent : '';
		
		/* Got any saved data to show? */
		CKEDITOR.on( 'instanceReady', function( ev )
		{
			if ( ev.editor.name == this.editorId )
			{
				/* This is dumb and only way to access editor object */
				this.EditorObj = ev;
				
				/* Quickly make some changes if minimized */
				if ( this.options.minimize )
				{
					$('cke_top_' + this.editorId ).down('.cke_toolbox_collapser').hide();
					$('cke_bottom_' + this.editorId ).hide();
					
					$('cke_' + this.editorId ).down('.cke_wrapper').addClassName('minimized');
					
					if ( ! this.isRte() )
					{
						$('cke_' + this.editorId ).down('.cke_wrapper').addClassName('std');
					}
					else
					{
						/* IE bug when clicking the text editor to expand and it also registers a toolbar click*/
						if ( Prototype.Browser.IE9 )
						{
							$('cke_top_' + this.editorId ).down('.cke_toolbox').setStyle( { 'position': 'absolute', 'left': '-2000px' } );
						}
					}
					
					ev.editor.on('focus', function()
					{
						try
						{
							if ( ! this.options.minimizeNowOpen )
							{ 
								this.showEditor().bind(this);
							}
						}catch(e){}
					}.bind(this) );
				}
				
				/* Fix for some tags */
				new Array( 'p', 'ul', 'li', 'blockquote', 'div' ).each( function ( tag )
				{
					ev.editor.dataProcessor.writer.setRules( tag, {
																	indent : false,
																	breakBeforeOpen : true,
																	breakAfterOpen : false,
																	breakBeforeClose : false,
																	breakAfterClose : true
																  } );
				} );
				
				/* Insert */
				if ( ipb.textEditor._tmpContent.length )
				{
					if ( ! this.isRte() )
					{
						ev.editor.setData( ipb.textEditor.stdPre( ipb.textEditor._tmpContent ) );
					}
					else
					{
						ev.editor.setData( ipb.textEditor.ckPre( ipb.textEditor._tmpContent ) );
					}
				}
				
				/* Clear tmp content */
				ipb.textEditor._tmpContent = '';
				
				this.displayAutoSaveData();
				
				if ( this.options.isTypingCallBack !== false )
				{
					this.timers['dirty'] = setInterval( this.checkForInput.bind(this), ipb.textEditor.IPS_TEXTEDITOR_POLLING );
				}
				
				/* Make sure our menus close */
				if ( $('cke_contents_' + this.editorId ).down('iframe') )
				{
					try
					{
						$('cke_contents_' + this.editorId ).down('iframe').contentWindow.document.onclick = parent.ipb.menus.docCloseAll;
					} catch( e ) { }
				}				
				
				/* Some ACP styles conflict */
				$$('.cke_top').each( function(elem) { elem.setStyle('background: transparent !important; padding: 0px !important'); } );
				$$('.cke_bottom').each( function(elem) { elem.setStyle('background: transparent !important; padding: 0px !important'); } );
				$$('.cke_contents').each( function(elem) { elem.setStyle('padding: 0px !important'); } );
				
				/* CKEditor tends to add a bunch of inline styles to cke_top_x which messes up custom styles */
				$('cke_top_' + this.editorId ).writeAttribute( 'style', '' );
				
				/* Update text-direction, since CKE forces LTR in 'source' mode */
				if( isRTL && !this.isRte() )
				{
					$$('.cke_contents > textarea').each( function(elem) {
						$(elem).setStyle( { textAlign: 'right' } );
					});
				}
			}
		}.bind(this) );		
	},
	
	/**
	 * Init CKEditor
	 */
	showEditor: function( content )
	{
		if ( this.options.minimize )
		{						
			this.options.minimizeNowOpen = 1;					
			
			$('cke_top_' + this.editorId ).down('.cke_toolbox_collapser').show();
			$('cke_bottom_' + this.editorId ).show();
			$('cke_' + this.editorId ).down('.cke_wrapper').removeClassName('minimized');
			
			this.EditorObj.editor.execCommand('toolbarCollapse');
			
			/* IE bug when clicking the text editor to expand and it also registers a toolbar click*/
			if ( Prototype.Browser.IE9 )
			{
				setTimeout( function() { $('cke_top_' + this.editorId ).down('.cke_toolbox').setStyle( { 'position': 'relative', 'left': '0px' } ) }.bind(this), 300 );
			}
			
			/* Shift screen if need be */
			try
			{
				var dims       = document.viewport.getDimensions();
				var editorDims = $('cke_' + this.editorId).getDimensions();
				var cOffset    = $('cke_' + this.editorId).cumulativeScrollOffset();
				var pOffset    = $('cke_' + this.editorId).positionedOffset();
				
				var bottomOfEditor = pOffset.top + editorDims.height;
				var bottomOfScreen = cOffset.top + dims.height;
				
				if ( bottomOfEditor > bottomOfScreen )
				{
					var diff = bottomOfEditor - bottomOfScreen;
					
					/* Scroll but with 100 extra pixels for comfort */
					window.scrollTo( 0, cOffset.top + diff + 100 );
				}
			}
			catch(e){ }
		}
	},
	
	/**
	 * Check for dirty status and throw it to a callback then cancel timer
	 */
	checkForInput: function()
	{
		if ( this.options.minimize == 1 && this.options.minimizeNowOpen == 0 )
		{
			return false;
		}

		var content = this.getText();
		
		if ( content && content.length && Object.isFunction( this.options.isTypingCallBack ) )
		{
			/* We have content, so throw to call back */
			this.options.isTypingCallBack();
			
			/* And cancel timer */
			clearInterval( this.timers['dirty'] );
			this.timers['dirty'] = '';
		}
	},
	
	/**
	 * Close previously minimized editor
	 */
	minimizeOpenedEditor: function()
	{
		if ( this.options.minimize == 1 && this.options.minimizeNowOpen == 1 )
		{ 
			if ( ! this.options.bypassCKEditor && this.CKEditor )
			{
				if ( $('cke_' + CKEDITOR.plugins.ipsemoticon.editor.name + '_stray') )
				{
					$('cke_' + CKEDITOR.plugins.ipsemoticon.editor.name + '_stray').remove();
					
					if ( $('ips_x_smile_show_all') )
					{
						$('ips_x_smile_show_all').remove();
					}
				}
				
				/* Re-shrink editor */
				this.EditorObj.editor.execCommand('toolbarCollapse');
				$('cke_top_' + this.editorId ).down('.cke_toolbox_collapser').hide();
				$('cke_bottom_' + this.editorId ).hide();
				$('cke_' + this.editorId ).down('.cke_wrapper').addClassName('minimized');
				
				if ( this.isRte() )
				{
					this.EditorObj.editor.setData('<p></p>');
					this.EditorObj.editor.focusManager.forceBlur();
				}
				else
				{
					this.EditorObj.editor.setData('');
					
					try
					{
						$('cke_' + this.editorId).down('textarea').blur();
					}
					catch(error){ Debug.write( error ); }
					
				}
				
				this.options.minimizeNowOpen = 0;
			}
			
			if ( this.options.bypassCKEditor )
			{
				$( this.editorId ).value = '';
			}
			
			try
			{
				if ( ! Object.isUndefined( $H( this.timers ) ) )
				{
					$H( this.timers ).each( function (timer)
					{
						var name = timer.key;
						
						if ( name.match( /^interval_/ ) )
						{
							clearInterval( this.timers[ name ] );
							Debug.write( 'Cleared Interval ' + name );
						}
						else
						{
							clearTimeout( this.timers[ name ] );
							Debug.write( 'Cleared Timeout ' + name );
						}
						
						this.timers[ name ] = '';
					}.bind(this) );
				}
			}
			catch(e) { Debug.error(e); }
		}
	},
	
	/**
	 * Make sure editor is in view
	 * 
	 */
	scrollTo: function()
	{
		var dims = document.viewport.getDimensions();
		var where = $( this.editorId ).positionedOffset();
		var offsets = document.viewport.getScrollOffsets();

		/* Is editor off the page? */
		if ( offsets.top + dims.height < where.top )
		{
			window.scroll( 0, ( parseInt( where.top ) - 200 ) );
		}
	},
	
	/**
	 * Remove editor completely
	 */
	remove: function()
	{
		this.CKEditor.destroy( true );
		
		this.CKEditor	= null;
		
		/* Remove object */
		ipb.textEditor.mainStore.unset( this.editorId );
		
		/* Remove timers */
		if ( ! Object.isUndefined( $H( this.timers ) ) )
		{
			$H( this.timers ).each( function (timer)
			{
				var name = timer.key;
				
				if ( name.match( /^interval_/ ) )
				{
					clearInterval( this.timers[ name ] );
					Debug.write( 'Cleared Interval ' + name );
				}
				else
				{
					clearTimeout( this.timers[ name ] );
					Debug.write( 'Cleared Timeout ' + name );
				}
				
				this.timers[ name ] = '';
			}.bind(this) );
		}
	},
	
	/**
	 * Inserts content into the text editor
	 */
	insert: function( content, scrollOnInit, clearFirst )
	{
		/* Minimized... */
		if ( this.options.minimize == 1 && this.options.minimizeNowOpen != 1 )
		{
			/* Scroll to editor when it loads? */
			if( scrollOnInit )
			{
				$( this.editorId ).scrollTo();
			}
			
			this.showEditor();
		}
		
		if ( ! this.options.bypassCKEditor )
		{
			if ( this.isRte() )
			{
				// Using insertHtml() because if you have content in the editor and insert more (i.e. click reply on two posts in a topic),
				// subsequent inserts will show the HTML instead of formatting it properly
				this.CKEditor.insertHtml( content );
			}
			else
			{
				if ( this.CKEditor.getData() )
				{
					if ( clearFirst )
					{
						this.CKEditor.setData( ipb.textEditor.stdPre( content ) );
					}
					else
					{
						this.CKEditor.setData( this.CKEditor.getData() + ipb.textEditor.stdPre( content ) );
					}
				}
				else
				{
					this.CKEditor.setData( ipb.textEditor.stdPre( content ) );
				}				
			}
		}
		else
		{
			$( this.editorId ).value = content;
		}
		
	},
	
	/**
	 * Show any display data we might have
	 */
	displayAutoSaveData: function()
	{
		if ( inACP )
		{
			return;
		}
		
		/* Keep looping until editor is ready */
		try
		{
			if ( Object.isUndefined( this.CKEditor ) || ! this.CKEditor.name || ! $('cke_' + this.editorId ) )
			{
				setTimeout( this.displayAutoSaveData.bind(this), 1000 );
				return;
			}
		} catch(e) { }
		
		Debug.write( 'Ready to show saved data: ' + 'cke_' + this.editorId );
	
		var sd = this.options.ips_AutoSaveData;
		
		if ( sd.key )
		{
			html  = this.options.ips_AutoSaveTemplate.evaluate( sd );
			
			if ( $('cke_' + this.editorId ).down('.cke_bottom').select('.cke_path').length < 1 )
			{
				$('cke_' + this.editorId ).down('.cke_resizer').insert( { before: new Element('div').addClassName('cke_path').update(html) } );
				
				ipb.delegate.register('._as_launch', this.launchViewContent.bind(this) );
			}
		}
	},
	
	/**
	 * Show the saved content in a natty little windah
	 */
	launchViewContent: function(e)
	{
		Event.stop(e);
		
		if ( ! Object.isUndefined( this.popups['view'] ) )
		{
			this.popups['view'].show();
		}
		else
		{			
			/* easy one this... */
			this.popups['view'] = new ipb.Popup( 'view', { type: 'modal',
											               initial: new Template( ipb.textEditor.IPS_AUTOSAVEVIEW ).evaluate( { content: this.options.ips_AutoSaveData.parsed } ),
											               stem: false,
											               warning: false,
											               hideAtStart: false,
											               w: '600px' } );
			
			ipb.delegate.register('._as_restore', this.restoreAutoSaveData.bind(this) );
		}
	},
	
	/**
	 * Show the about saved content in a natty little windah
	 */
	launchExplain: function(e)
	{
		Event.stop(e);
		
		var s = '__last_update_stamp_' + this.editorId;
		
		if ( ! Object.isUndefined( this.popups['explain'] ) )
		{
			this.popups['explain'].kill();
		}
					
		/* easy one this... */
		this.popups['explain'] = new ipb.Popup( 'explain', { type: 'balloon',
											                 initial: ipb.textEditor.IPS_AUTOSAVEEXPLAIN,
											                 stem: true,
											                 warning: false,
											                 hideAtStart: false,
											                 attach: { target: $$('.' + s ).first() },
											                 w: '300px' } );						
		
	},
	
	/**
	 * Restore auto saved content
	 */
	restoreAutoSaveData: function(e)
	{
		Event.stop(e);
		
		this.popups['view'].hide();
		
		if ( this.isRte() )
		{
			setTimeout( function() { this.CKEditor.setData( ipb.textEditor.ckPre( this.options.ips_AutoSaveData.restore_rte ) ); }.bind(this), 500 );
		}
		else
		{
			setTimeout( function() { this.CKEditor.setData( this.options.ips_AutoSaveData.restore_std ); }.bind(this), 500 );
		}
	},
	
	/**
	 * Save contents of the editor
	 * @param	object	Current editor object (passed via plugin)
	 * @param	object	Current command object (passed via plugin)
	 */
	save: function( editor, command )
	{
		if ( inACP )
		{
			return;
		}
		
		var _url  = ipb.textEditor.ajaxUrl + '&app=core&module=ajax&section=editor&do=autoSave&secure_key=' + ipb.vars['secure_hash'] + '&autoSaveKey=' + this.options.ips_AutoSaveKey;
		Debug.write( _url );
		
		/* Fetch data */
		var content = this.CKEditor.getData();
		
		Debug.write( 'Fetched editor content: ' + content );
		
		new Ajax.Request( _url,
							{
								method: 'post',
								evalJSON: 'force',
								hideLoader: true,
								parameters: { 'content' : content.encodeParam() },
								onSuccess: function(t)
								{										    	
									/* No Permission */
									if ( t.responseJSON && t.responseJSON['status'] == 'ok' )
									{
										/* Reset 'dirty' */
										editor.resetDirty();
						
										/* No longer busy */
										command.setState( CKEDITOR.TRISTATE_OFF );
										
										this.updateSaveMessage();
									}
								}.bind(this)
							} );	
		
	},
	
	/**
	 * Display the time the post was last auto saved
	 */
	updateSaveMessage: function()
	{
		var s = '__last_update_stamp_' + this.editorId;
		var d = new Date();
		var c = new Template( ipb.textEditor.IPS_SAVED_MSG ).evaluate( { time: d.toLocaleTimeString() } );
		
		/* remove old */
		$$('.' + s ).invoke('remove');
		
		/* Add new */
		$('cke_' + this.editorId ).down('.cke_resizer').insert( { before: new Element('div').addClassName('cke_path ' + s).update(c) } );
		
		ipb.delegate.register('._as_explain', this.launchExplain.bind(this) );
	}
} );