/**
 *Create the free form editor. Look at the example directory for usage.
 */
//===========================================================================>
/**
 *Start the editor. This should be placed in the document onload.
 *This is needed to start the editing.
 *Also looks at at a gloabl variable loadIntoEditor. Which is, well, loaded
 *into the editor.
 */
function FreeFormEditorStart( editor, editor_IFrame ){
  
  var element = document.getElementById( editor_IFrame );

  if( element ){
    element.contentWindow.document.designMode = "on";

    if( editor )
      if( loadIntoEditor )
	editor.load( loadIntoEditor );
  }
 
};
//===========================================================================>
/**
 *Copy data into a destination.
 *Intended to copy a string into a hidden text element's value.
 *Intended to be used in a form's onSubmit handler.
 *@return true always.
 */
function FreeFormEditor_Copy( to, arg){
  to.value = arg;

  return true;
}
//===========================================================================>
/**
 *Constructor for FreeFormEditor objects.
 *@param editorName (string).
 *@param editorDivElement The name of the enclosing div element.
 *@param graphicsPrefix Where to find the icons for buttons and so on. This is 
 *the path to the editor javascript code. There MUST be a trailing slash.
 */
function FreeFormEditor( editorName, 
			 editorDivElement,
			 graphicsPrefix){
  
  //myassert( typeof(editorName      ) == 'string' );
  //myassert( typeof(editorDivElement) == 'string' );

  this.editorName       = editorName;
  this.editorDivElement = editorDivElement;
  this.graphicsPrefix   = graphicsPrefix;

  this.construct();
}
//############################################################################
/**
 *Add a button to the ToolBar. This is meant to be used internally.
 *@param ToolBar the toolbar (a div) the button should be added to.
 *@param name Used in tooltips.
 *@param iconPath the graphic to use.
 *@param callback what to call if the button is pressed.
 *@access private
 */
FreeFormEditor.prototype.addButton = function( ToolBar,
					       name, 
					       iconPath,
					       callback  ){
  
  var button = document.createElement('img' );
  button.src = this.graphicsPrefix + iconPath;
  button.title = name;
  button.className = 'normal';

  button.onmouseover = function(){ button.className = 'select';}
  button.onmouseout  = function(){ button.className = 'normal';}

  button.onclick = callback;

  ToolBar.appendChild( button );
};
//############################################################################
/**
 *Construct the button list in the toolbar.
 */
FreeFormEditor.prototype.constructButtonList = function( toolbar ){
  
  var editor = this;

  this.addButton( toolbar,
		  'Bold',
		  'graphics/FreeFormEditor/bold.png',
		  function(){ editor.applyCommand( 'bold' ); }
		  );
  
  this.addButton( toolbar,
		  'Italic',
		  'graphics/FreeFormEditor/italic.png',
		  function(){ editor.applyCommand('italic'); }
		  );
  
  this.addButton( toolbar,
		  'Underline',
		  'graphics/FreeFormEditor/underline.png',
		  function(){ editor.applyCommand( 'underline' ); }
		  );

  this.addButton( toolbar,
		  'Copy',
		  'graphics/FreeFormEditor/copy.png',
		  function(){ editor.applyCommand( 'copy' ); }
		  );
  
  this.addButton( toolbar,
		  'Cut',
		  'graphics/FreeFormEditor/cut.png', 
		  function(){ editor.applyCommand( 'cut' ); }
		  );
  
  this.addButton( toolbar,
		    'Paste',
		  'graphics/FreeFormEditor/paste.png',
		  function(){ editor.applyCommand( 'paste' ); }
		  );
  
  this.addButton( toolbar,
		  'Undo',
		  'graphics/FreeFormEditor/undo.gif',
		  function(){ editor.applyCommand( 'undo' ); }
		  );
  
  this.addButton( toolbar,
		  'Redo',
		  'graphics/FreeFormEditor/redo.gif',
		  function(){ editor.applyCommand( 'redo' ); }
		  );
  
  this.addButton( toolbar,
		  'Left justify',
		  'graphics/FreeFormEditor/left.png',
		  function(){ editor.applyCommand( 'justifyleft' ); }
		  );
  
  this.addButton( toolbar,
		  'Center',
		  'graphics/FreeFormEditor/center.png',
		  function(){ editor.applyCommand( 'justifycenter' ); }
		  );
  
  this.addButton( toolbar,
		  'Right justify',
		  'graphics/FreeFormEditor/right.png',
		  function(){ editor.applyCommand( 'justifyright' ); }
		  );
  
  this.addButton( toolbar,
		  'Indent',
		  'graphics/FreeFormEditor/indent.png',
		  function(){ editor.applyCommand( 'indent' ); }
		  );
  
  this.addButton( toolbar,
		  'Outdent',
		  'graphics/FreeFormEditor/outdent.png',
		  function(){ editor.applyCommand( 'outdent' ); }
		  );
  
  this.addButton( toolbar,
		  'Ordered list',
		  'graphics/FreeFormEditor/ordlist.png',
		  function(){ editor.applyCommand( 'insertorderedlist' ); }
		  );
  
  this.addButton( toolbar,
		  'Bulleted list',
		  'graphics/FreeFormEditor/bullist.png',
		  function(){ editor.applyCommand( 'insertunorderedlist' ); }
		  );
  
  this.addButton( toolbar,
		  'Insert a link',
		  'graphics/FreeFormEditor/link.png',
		  function(){ 
		    var arg = window.prompt('Enter a url for new link', 'http://');
		    editor.applyCommand( 'createlink', arg );
		  }
		  );
}
//############################################################################
/**
 *Add in an options menu.
 */
FreeFormEditor.prototype.addOptions = function( title,
						options,
						callback ){
  
  var editor = this;

  var form = document.getElementById( this.editorName + 'form' );

  var menu = document.createElement('select');
  menu.setAttribute('id', this.editorName + 'form' + 'user' + title );

  menu.onchange = function(){
    callback(editor, menu.getAttribute('id') );
  };

  {//Add in the title.
    var op = document.createElement('option');
    op.appendChild( document.createTextNode( title ));
    op.value = '';

    menu.appendChild( op );
  }

  for( var k in options){ //Set up the options.
    
    var op = document.createElement('option');
    op.appendChild( document.createTextNode( options[k] ));
    op.value = k;

    menu.appendChild( op );  
  }
  
  form.appendChild( menu );
};
//############################################################################
/**
 *Construct the button list in the toolbar.
 */
FreeFormEditor.prototype.constructMenus = function( toolbar ){

  //Make sure the object is reference-able on the stack.
  var editor = this;
  
  //Build the form.
  var form = document.createElement( 'form' );
  form.className = 'form';
  
  form.setAttribute( 'id',   editor.editorName + 'form' );
  form.setAttribute( 'name', editor.editorName + 'form' );
  
  {//Set up the font names.
    var selectFontName = document.createElement( 'select' );   
    
    selectFontName.setAttribute( 'id', this.editorName + 'form' + 'fontname');
    
    selectFontName.onchange = function(){
      editor.handleSelectFontName( selectFontName.getAttribute('id'),
				   'fontname' );
    };

    var data = new Array();
    data[0] = 'Font name';
    data[1] = 'Arial';
    data[2] = 'Courier';
    data[3] = 'Times New Roman';
    
    for( var k in data){
      var option = document.createElement('option');
      option.appendChild( document.createTextNode( data[k] ));
      option.value = data[k];
      
      selectFontName.appendChild( option );
    }

    form.appendChild( selectFontName );
  }
    
  {//Set up the select font size.
    var selectFontSize = document.createElement( 'select' );
    selectFontSize.setAttribute('id', this.editorName + 'form' + 'fontsize');
    
    selectFontSize.onchange = function(){
      editor.handleSelectFontName( selectFontSize.getAttribute('id'),
				   'fontsize' );
    };
   
    var data = new Array();
    data['Font size'] = 0;

    data['xx-small'] = 1;
    data[ 'x-small'] = 2;
    data[   'small'] = 3;
    data[  'medium'] = 4;
    data[   'large'] = 5;
    data[ 'x-large'] = 6;
    data['xx-large'] = 7;

    for( var k in data){
      var option = document.createElement('option');
      option.appendChild( document.createTextNode( k ));
      option.value = data[k];
      
      selectFontSize.appendChild( option );
    }
    
    form.appendChild( selectFontSize );
  }
  
  {//Set up the format options.
    var format = document.createElement('select');
    format.setAttribute('id', this.editorName + 'form' + 'format' );
    
    format.onchange = function(){
      editor.handleSelectFontName( format.getAttribute('id'),
				   'formatblock' );
    };
    
    var data = new Array();
    
    data['Style'    ] = ''; 
    data['Paragraph'] = '<p>';
    data['Heading 1'] = '<h1>';
    data['Heading 2'] = '<h2>';
    data['Heading 3'] = '<h3>';
    data['Heading 4'] = '<h4>';
    data['Heading 5'] = '<h5>';
    data['Heading 6'] = '<h6>';
    data['Address'  ] = '<address>';
    data['Formatted'] = '<pre>';

    for( var k in data){
      var option = document.createElement('option');
      option.appendChild( document.createTextNode( k ));
      option.value = data[k];
      
      format.appendChild( option );
    }

    form.appendChild( format );
  }
  
  toolbar.appendChild( form );
};
//############################################################################
/**
 *Construct the editor in place.
 */
FreeFormEditor.prototype.construct = function(){

  var editor = this;

  var element = document.getElementById( this.editorDivElement );
  element.setAttribute( 'class', 'FreeFormEditor');
  element.className = 'FreeFormEditor';

  {//Add in the required elements and make the display editable.
    /*
    var toolbar = document.createElement( 'div' );
    toolbar.setAttribute( 'id', this.editorName + 'ToolBar');

    element.appendChild( toolbar );

    var iframe = document.createElement( 'iframe' );
    iframe.setAttribute( 'id', this.editorName + 'Display' );

    element.appendChild( iframe );
    */
  }

  {//ToolBar.
    var toolbar = document.getElementById( this.editorName + 'ToolBar');
    toolbar.setAttribute( 'class', 'ToolBar' );
    toolbar.className = 'ToolBar';

    //The selection forms.
    this.constructMenus( toolbar );

    //Buttons.
    this.constructButtonList( toolbar );
  }

  {//RTE.
    var rte = document.getElementById( this.editorName + 'Display' );
    rte.className = 'display';

    rte.setAttribute( "contentEditable", true);
    rte.contentEditable = true;

    rte.contentWindow.document.designMode = 'On';
  }
};
//############################################################################
/**
 *Apply a rich edit command.
 */
FreeFormEditor.prototype.applyCommand = function( commandName, 
						  argument    ){

  var element = document.getElementById( this.editorName + 'Display' );
  
  try{
    element.contentWindow.document.execCommand( commandName, false, argument);
  
  }catch( e ){
    window.alert( 'Unfortulately, your web browser does not support this operation: ' + commandName );
  }
  
  element.contentWindow.focus();
};
//############################################################################
/**
 *Change the font name.
 */
FreeFormEditor.prototype.handleSelectFontName = function(id, command){
  
  var select = document.getElementById( id );

  if( select ){

    var cmd = select.selectedIndex;
    
    if( cmd ){

      var options = select.options;
     
      if( options ){
	
	if( cmd <  options.length ){
 
	  var index = options.item( cmd );

	  if( index.value )
	    if( index.value.length )
	      this.applyCommand( command, index.value );
	}
      }
    }
  }
};
//############################################################################
/**
 *Get the selected text.
 */
FreeFormEditor.prototype.getSelection = function(){

  var element = document.getElementById( this.editorName + 'Display' );
  
  var text = '';
  
  if( element.contentWindow.document.getSelection )//Moz
    text = element.contentWindow.document.getSelection();

  else if( element.contentWindow.document.selection)//IE
    text = element.contentWindow.document.selection.createRange().htmlText;

  else
    window.alert( 'NBang!' );
  
  element.contentWindow.focus();

  return text;
};
//############################################################################
/**
 *Insert something at cursor position.
 */
FreeFormEditor.prototype.insertElement = function( arg ){

  var element = document.getElementById( this.editorName + 'Display' );

  var range = null;

  if( element.contentWindow.getSelection ){//Moz
    range = element.contentWindow.getSelection();

    if( range.rangeCount > 0){
      
      range = range.getRangeAt(0);
      range.insertNode( arg );
    }

  }else if( element.contentWindow.document.selection){//IE
    range = element.contentWindow.document.selection.createRange();

    this.applyCommand( 'InsertInputText' );
    
    var pe = range.parentElement();
    
    var grandpa = pe.parentNode;
    
    grandpa.replaceChild( arg, pe );
  }
  
  element.contentWindow.focus();
};
//############################################################################
/**
 *Get the contents of the editor window (as HTML).
 */
FreeFormEditor.prototype.getContents = function(){

  var element = document.getElementById( this.editorName + 'Display' );
  
  return element.contentWindow.document.body.innerHTML;
};
//############################################################################
/**
 *Create an element on the editor iframe.
 *This shoudl be used in preference to document.createElement
 */
FreeFormEditor.prototype.createElement = function( arg ){

  var element = document.getElementById( this.editorName + 'Display' );

  return element.contentWindow.document.createElement( arg );
};
//############################################################################
/**
 *Create a text node on the editor iframe.
 *This shoudl be used in preference to document.createElement
 */
FreeFormEditor.prototype.createTextNode = function( arg ){

  var element = document.getElementById( this.editorName + 'Display' );

  return element.contentWindow.document.createTextNode( arg );
};
//############################################################################
/**
 *Load some data into the editor. Overwrites any previous edits.
 *This is good for loading the editor.
 */
FreeFormEditor.prototype.load = function( arg ){

  var element = document.getElementById( this.editorName + 'Display' );

  //window.alert( 'Loading: ' + unescape(arg) );

  if( element ){

    element.contentWindow.document.body.innerHTML = unescape(arg);
    
    element.contentWindow.focus();
  }
};
//############################################################################
/**
 *Paste (insert) some html at the end of the doc. Adding an <br/> at the end
 *of non line elements like <hr/> is a good idea.
 */
FreeFormEditor.prototype.pasteHTML = function( arg ){

  var element = document.getElementById( this.editorName + 'Display' );
  
  //var sel = element.contentWindow.getSelection();
  //var sel = window.getSelection();
  
  var range = null;

  if( element.contentWindow.getSelection ){//Moz
    range = element.contentWindow.getSelection();
  
    if( range.rangeCount > 0){
      range.collapseToEnd();
      range = range.getRangeAt(0);
      range.insertNode( document.createTextNode( arg ) );
    }

  }else if( element.contentWindow.document.selection ){//IE
    range = element.contentWindow.document.selection.createRange();
    
    this.applyCommand( 'InsertInputText' );
    
    var pe = range.parentElement();
    
    var grandpa = pe.parentNode;
    
    grandpa.replaceChild( element.contentWindow.document.createTextNode(arg), pe );
    
  }else{
    window.alert( 'Bang!' );
  }
  
  element.contentWindow.focus();
};
//############################################################################
//===========================================================================>

