﻿// -------------------------------- //
// CLASSE: BBCodeEditor             //
// Rappresenta un editor di BBCode  //
// -------------------------------- //
function BBCodeEditor(editorID)
{
	this.editorID = editorID;
	this.buttons = new Array();
	this.popups = new Array();
	this.history = new BBCodeEditorHistory();

    // Inizializza l'editor
	this.initControl();
}

// Inizializza un editor registrandone i suoi controlli
BBCodeEditor.prototype.initControl = function()
{
    // Il contenitore dell'editor specificato non esiste
    if (!getObject(this.editorID))
    {
        return;
    }
    
    // Registra il contenitore dell'editor
    this.editorControl = getObject(this.editorID);
    
    // L'editor specificato non contiene una casella di testo
    if (getObjects(this.editorControl, 'textarea').length == 0)
    {
        return;
    }
    
    // Registra la casella di testo dell'editor
    this.textControl = getObjects(this.editorControl, 'textarea')[0];
    
    // Inizializza la barra dei menu
    this.initMenuBar();
};

// Inizializza la barra del menu dell'editor
BBCodeEditor.prototype.initMenuBar = function()
{
    var buttons = getObjects(this.editorControl, 'div');
    
    // Inizializza ogni singolo pulsante
	for (var i = 0; i < buttons.length; i++)
	{
	    if (buttons[i].className == 'editor-menu-button')
	    {
	        if (buttons[i].id.indexOf('_command_') != -1)
	        {
	            this.initCommandButton(buttons[i]);
	        }
	    }
	}
};

// Inizializza un singolo pulsante della barra del menu di un editor
BBCodeEditor.prototype.initCommandButton = function(buttonObject)
{
    // Registra comando del pulsante ed editor associato
    buttonObject.command = buttonObject.id.substr(buttonObject.id.indexOf('_command_') + 9);
    buttonObject.editorID = this.editorID;
    
    // Aggiunge il pulsante a quelli disponibili
    this.buttons[buttonObject.command] = buttonObject;
    
    // Imposta lo stato iniziale
    buttonObject.mode = 'normal';
    
    // Imposta i gestori degli eventi associati al pulsante
    buttonObject.onclick = buttonObject.onmousedown = buttonObject.onmouseup = buttonObject.onmouseover = buttonObject.onmouseout = BBCodeEditorEvents.prototype.commandButton_onmouseevent;
};

// Assegna il focus alla casella di testo
BBCodeEditor.prototype.setFocus = function()
{
	if (!this.textControl.hasfocus)
	{
		this.textControl.focus();
	}
};

// Applica un comando in seguito alla pressione del pulsante
BBCodeEditor.prototype.applyCommand = function(e, command)
{
    e = getEvent(e);
    
    // Assegna il focus alla casella di testo
    this.setFocus();
    
    // Registra lo stato attuale dell'editor se non stiamo ripetendo
    if (command != 'redo')
	{
		this.history.addItem(this.textControl.value);
	}
	
	// Il comando ha una funzione di gestione personalizzata
	if (this[command])
	{
	    this[command]();
	}
	// Il comando è generico
    else
    {
        switch (command)
	    {
		    case 'bold':
		    case 'italic':
		    case 'underline':
		    {
			    this.formatCommandTags(command.substr(0, 1));
			    break;
		    }
		    case 'left':
		    case 'center':
		    case 'right':
		    {
			    this.formatCommandTags(command);
			    break;
		    }
	    }
	}
	
	// Registra il nuovo stato attuale dell'editor se non stiamo annullando
	if (command != 'undo')
	{
		this.history.addItem(this.textControl.value);
	}
};

// Applica i tag di un comando al testo eventualmente selezionato
BBCodeEditor.prototype.formatCommandTags = function(tagName, selection, option)
{
    tagName = tagName.toUpperCase();
	
	// Recupera la selezione corrente se non è stata specificata
	if (typeof selection == 'undefined' || selection == null)
	{
	    selection = this.getSelection();
	
	    if (selection === false)
	    {
		    selection = '';
	    }
	}
	
	// Imposta tag di apertura e chiusura
	var openTag = '[' + tagName + ']';
	var closeTag = '[/' + tagName + ']';
	
	// Inserisce l'opzione eventualmente specificata nel tag di apertura
	if (typeof option != 'undefined')
	{
	    openTag = '[' + tagName + '=' + option + ']';
	}

    // Inserisce il testo selezionato nell'editor
	this.insertText(openTag + selection + closeTag, openTag.length, closeTag.length);
};

// Controlla il risultato di un prompt all'utente
BBCodeEditor.prototype.checkPrompt = function(option)
{
    switch(option)
	{
		case 'http://':
		case 'null':
		case 'undefined':
		case 'false':
		case '':
		case null:
		case false:
			return false;
		default:
			return true;
	}
};

// Inserisce il testo specificato nella casella di testo dell'editor, muovendo in maniera corrispondente la selezione
BBCodeEditor.prototype.insertText = function(text, moveStart, moveEnd)
{
    this.setFocus();

	if (typeof(this.textControl.selectionStart) != 'undefined')
	{
		var oldPosition = this.textControl.selectionStart + 0;
		var scrollPosition = this.textControl.scrollTop;

		this.textControl.value = this.textControl.value.substr(0, this.textControl.selectionStart) + text + this.textControl.value.substr(this.textControl.selectionEnd);

		if (moveStart === false)
		{
		}
		else if (typeof moveStart != 'undefined')
		{
			this.textControl.selectionStart = oldPosition + moveStart;
			this.textControl.selectionEnd = oldPosition + text.length - moveEnd;
		}
		else
		{
			this.textControl.selectionStart = oldPosition;
			this.textControl.selectionEnd = oldPosition + text.length;
		}
		
		this.textControl.scrollTop = scrollPosition;
	}
	else if (document.selection && document.selection.createRange)
	{
		var selection = document.selection.createRange();
		selection.text = text.replace(/\r?\n/g, '\r\n');

		if (moveStart === false)
		{
		}
		else if (typeof moveStart != 'undefined')
		{
			selection.moveStart('character', -text.length + moveStart);
			selection.moveEnd('character', -moveEnd);
		}
		else
		{
			selection.moveStart('character', -text.length);
		}
		
		selection.select();
	}
	else
	{
		this.textControl.value += text;
	}
};

// Funzione specializzata per l'inserimento di una dimensione del testo
BBCodeEditor.prototype.insertSize = function()
{
	var size = prompt('Inserisci la dimensione desiderata per il testo in pixel.\nI valori accettati vanno da 8 a 24 pixel:');

	if (this.checkPrompt(size))
	{
		this.formatCommandTags('size', null, size);
	}
};

// Funzione specializzata per l'inserimento di una colore del testo
BBCodeEditor.prototype.insertColor = function()
{
	var color = prompt('Inserisci il colore desiderato per il testo.\nPer un riepilogo dei valori accettati consulta l\'aiuto:');

	if (this.checkPrompt(color))
	{
		this.formatCommandTags('color', null, color);
	}
};

// Funzione specializzata per l'inserimento di una citazione
BBCodeEditor.prototype.insertQuote = function()
{
	var quote = prompt('Inserisci il nome dell\'autore che vuoi citare (lascia vuoto per non specificarlo):');

	if (this.checkPrompt(quote))
	{
		this.formatCommandTags('quote', null, quote);
	}
	else
	{
	    this.formatCommandTags('quote');
	}
};

// Funzione specializzata per l'inserimento di un'immagine
BBCodeEditor.prototype.insertImage = function()
{
	var image = prompt('Inserisci l\'indirizzo completo dell\'immagine:', 'http://');

	if (this.checkPrompt(image))
	{
		this.formatCommandTags('img', image);
	}
};

// Funzione specializzata per l'inserimento di un collegamento ipertestuale
BBCodeEditor.prototype.insertLink = function()
{
	var link = prompt('Inserisci l\'indirizzo completo della pagina web:', 'http://');

	if (this.checkPrompt(link))
	{
	    if (this.getSelection())
	    {
		    this.formatCommandTags('url', null, link);
		}
		else
		{
		    this.formatCommandTags('url', link, link);
		}
	}
};

// Funzione specializzata per l'inserimento di un indirizzo e-mail
BBCodeEditor.prototype.insertMail = function()
{
	var mail = prompt('Inserisci l\'indirizzo e-mail:');

	if (this.checkPrompt(mail))
	{
	    if (this.getSelection())
	    {
		    this.formatCommandTags('email', null, mail);
		}
		else
		{
		    this.formatCommandTags('email', mail, mail);
		}
	}
};

// Funzione specializzata per l'inserimento di un elenco numerato
BBCodeEditor.prototype.insertOrderedList = function()
{
	this.insertList('1');
};

// Funzione specializzata per l'inserimento di un elenco puntato
BBCodeEditor.prototype.insertUnorderedList = function()
{
	this.insertList('');
};

// Funzione specializzata per l'inserimento di una lista generica
BBCodeEditor.prototype.insertList = function(listType)
{
	var openTag = '[LIST' + (listType.length == 1 ? ('=' + listType) : '') + ']\n';
	var closeTag = '[/LIST]';

    var text;

	if (text = this.getSelection())
	{
		var regex = new RegExp('([\r\n]+|^[\r\n]*)(?!\\[\\*\\]|\\[\\/?list)(?=[^\r\n])', 'gi');
		text = openTag + text.replace(regex, '$1[*]') + '\n' + closeTag;
		this.insertText(text, text.length, 0);
	}
	else
	{
		this.insertText(openTag + closeTag, openTag.length, closeTag.length);

        var listItem;

		while (listItem = prompt('Inserisci il prossimo elemento dell\'elenco.\nLascia vuoto o premi \'Annulla\' per terminare la lista:'))
		{
			listItem = '[*]' + listItem + '\n';
			this.insertText(listItem, listItem.length, 0);
		}
	}
};

// Funzione personalizzata per l'annullamento di un comando
BBCodeEditor.prototype.undo = function()
{
	this.history.addItem(this.textControl.value);
	this.history.moveCursor(-1);
	
	if ((text = this.history.getItem()) !== false)
	{
		this.textControl.value = text;
	}
};

// Funzione personalizzata per la ripetizione di un comando
BBCodeEditor.prototype.redo = function()
{
	this.history.moveCursor(1);
	
	if ((text = this.history.getItem()) !== false)
	{
		this.textControl.value = text;
	}
};

// Recupera la selezione eventualmente presente nella casella di testo
BBCodeEditor.prototype.getSelection = function()
{
	if (typeof(this.textControl.selectionStart) != 'undefined')
	{
		return this.textControl.value.substr(this.textControl.selectionStart, this.textControl.selectionEnd - this.textControl.selectionStart);
	}
	else if (document.selection && document.selection.createRange)
	{
		return document.selection.createRange().text;
	}
	else if (window.getSelection)
	{
		return window.getSelection() + '';
	}
	else
	{
		return false;
	}
};

// Imposta lo stato di un bottone in base all'evento specificato
BBCodeEditor.prototype.setButtonState = function(buttonObject, state)
{
    switch (state)
	{
		case 'mouseover':
		{
			this.setControlStyle(buttonObject, 'hover');
			break;
		}
		case 'mousedown':
		{
			this.setControlStyle(buttonObject, 'pressed');
			break;
		}
		case 'mouseup':
		{
		    this.setControlStyle(buttonObject, 'hover');
			break;
		}
		case 'mouseout':
		{
			this.setControlStyle(buttonObject, 'normal');
			break;
		}
	}
};

// Imposta lo stile di un bottone in base allo stato specificato
BBCodeEditor.prototype.setControlStyle = function(buttonObject, mode)
{
    if (buttonObject.mode == mode)
	{
	    return;
	}
	
	buttonObject.mode = mode;
	
	switch (mode)
	{
	    case 'hover':
	    {
	        buttonObject.style.borderRight = "1px solid buttonshadow";
		    buttonObject.style.borderTop = "1px solid buttonhighlight";
		    buttonObject.style.borderBottom = "1px solid buttonshadow";
		    buttonObject.style.borderLeft = "1px solid buttonhighlight";
		    break;
		}
		case 'pressed':
		{
		    buttonObject.style.borderTop = "1px solid buttonshadow";
		    buttonObject.style.borderBottom = "1px solid buttonhighlight";
		    buttonObject.style.borderLeft = "1px solid buttonshadow";
		    buttonObject.style.borderRight = "1px solid buttonhighlight";
		    break;
		}
		case 'normal':
		{
		    buttonObject.style.border = "1px solid buttonface";
		}
	}
};

// ------------------------------------------------ //
// CLASSE: BBCodeEditorEvents                       //
// Rappresenta il gestore degli eventi degli editor //
// ------------------------------------------------ //
function BBCodeEditorEvents() { }

// Gestisce tutti gli eventi generati dal mouse su un pulsante
BBCodeEditorEvents.prototype.commandButton_onmouseevent = function(e)
{
	e = getEvent(e);

	if (e.type == 'click')
	{
		BBCodeEditors[this.editorID].applyCommand(e, this.command);
	}

	BBCodeEditors[this.editorID].setButtonState(this, e.type);
};

// ------------------------------------------------------------------ //
// CLASSE: BBCodeEditorHistory                                        //
// Rappresenta la cronologia delle operazioni effettuate su un editor //
// ------------------------------------------------------------------ //
function BBCodeEditorHistory()
{
    this.cursor = -1;
    this.stack = new Array();
}

// Muove il cursore della cronologia avanti o indietro
BBCodeEditorHistory.prototype.moveCursor = function(increment)
{
	var test = this.cursor + increment;
	
	if (test >= 0 && this.stack[test] != null && typeof this.stack[test] != 'undefined')
	{
		this.cursor += increment;
	}
};

// Aggiunge una fotografia del'editor alla cronologia
BBCodeEditorHistory.prototype.addItem = function(text)
{
    if (this.stack[this.cursor] == text)
	{
		return;
	}
	else
	{
		this.cursor++;
		this.stack[this.cursor] = text;

		if (typeof this.stack[this.cursor + 1] != 'undefined')
		{
			this.stack[this.cursor + 1] = null;
		}
	}
};

// Recupera la fotografia dell'editor associata al cursore
BBCodeEditorHistory.prototype.getItem = function()
{
	if (typeof this.stack[this.cursor] != 'undefined' && this.stack[this.cursor] != null)
	{
		return this.stack[this.cursor];
	}
	else
	{
		return false;
	}
};