/***************************************************************************************************
 *	Texyla
 *  Version:            0.4.1
 *  Latest update: 		13. června 2007 12:39
 ***************************************************************************************************
 *  Encoding:           UTF-8
 ***************************************************************************************************
 *	Vytvořil: 			Jan Marek
 *						Petr Vaněk aka krteczek
 *						Lukáš Voda
 *
 *	Web: 				http://texyla.jaknato.com
 *
 *  Licence:            Texyla je k dispozici pod GPL licencí
 *  					(její český překlad naleznete v souboru gpl.cs.html)
 *
 *  Tento program je volný software; můžete jej šířit a modifikovat podle
 *  ustanovení Obecné veřejné licence GNU, vydávané Free Software
 *  Foundation; a to buď verze 2 této licence anebo (podle vašeho uvážení)
 *  kterékoli pozdější verze.
 *
 *  Tento program je rozšiřován v naději, že bude užitečný, avšak BEZ
 *  JAKÉKOLI ZÁRUKY; neposkytují se ani odvozené záruky PRODEJNOSTI anebo
 *  VHODNOSTI PRO URČITÝ ÚČEL. Další podrobnosti hledejte ve Obecné
 *  veřejné licenci GNU.
 *
 *  Kopii Obecné veřejné licence GNU jste měl obdržet spolu s tímto
 *  programem; pokud se tak nestalo, napište o ni Free Software Foundation,
 *  Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **************************************************************************************************/
 
// Nastavení
Texyla.configurator = {
	defaultCfg: function(textarea) {	
		return {
			// Textarea do které se vkládá Texy
			textarea: textarea,
			
			// Lišta
			toolbar: null,
			
			// Povolit náhled HTML kódu
			allowHtmlPreview: null,
			
			// Typ ikonek - silk | old
			iconType: 'silk',
			
			// Formát ikonek - silk -> png, old -> gif
			iconFormat: 'png',
			
			// Vzhled (default | win_xp)
			theme: 'default',
			
			// Hezký vzhled tlačítek
			coolButtons: true,
			
			// 'auto' -> zachová původní šířku | číslo -> šířka editoru v pixelech
			editorWidth: 'auto',
			
			// odsazení textarey
			textareaMargin: 6,
			
			// Funkce, která se volá při odpovědi na XHR, vrací string - HTML
			AjaxProcessor: null,
			
			// Funkce, která modifikuje nastavení XHR
			AjaxPreProcessor: null,
					
			// Konfigurace Texy, dostupné jsou: default, admin, forum.
			texyCfg: 'default',
			
			// smajlíky
			emoticons: 'texy'
		}
	},
	
	admin: function(textarea) {
		var options = Texyla.configurator.defaultCfg(textarea);
		
		options.toolbar = 'admin';
		options.allowHtmlPreview = true;
		options.texyCfg = 'admin';
		
		return options;
	},
	
	forum: function(textarea) {
		var options = Texyla.configurator.defaultCfg(textarea);
		
		options.toolbar = 'forum';
		options.allowHtmlPreview = false;
		options.texyCfg = 'forum';
		
		return options;
	}
}

Texyla.toolbars = {
	admin: [
		'h1', 'h2', 'h3', 'h4',
		null,
		'bold', 'italic', 'del',
		null,
		'center', ['left', 'right', 'justify'],
		null,
		'ul', 'ol', 'blockquote',
		null,
		'sup', 'sub',
		null,
		'link', 'img', 'table', 'acronym', 'emoticon',
		null,
		['hr', 'code', 'inlineCode', 'html', 'notexy', 'web']
	],
	forum: [
		'bold', 'italic', 'del', 'blockquote', 'code', 'ul', 'ol', 'link', 'img', 'emoticon', 'web'
	]
}


Texyla.defaultAddrs = function () {
	return {
		css: 'themes/',
		icons: 'icons/',
		ajax: 'texyla.php'
	}
}

Texyla.emoticons = {
	texy: function() {
		this.root = Texyla.addrBase + 'emoticons/texy/';
		this.iconFormat = 'gif';
		this.width = 15;
		this.height = 15;
		this.icons = {};
		this.icons[':-)'] = 'smile';
		this.icons[':-('] = 'sad';
		this.icons[';-)'] = 'wink';
		this.icons[':-D'] = 'biggrin';
		this.icons['8-O'] = 'eek';
		this.icons['8-)'] = 'cool';
		this.icons[':-?'] = 'confused';
		this.icons[':-x'] = 'mad';
		this.icons[':-P'] = 'razz';
		this.icons[':-|'] = 'neutral';
		this.icons[':_?'] = '1';
		this.icons[':_!'] = '2';
	},
	silk: function() {
		this.root = Texyla.addrBase + 'emoticons/silk/';
		this.iconFormat = 'png';
		this.width = 16;
		this.height = 16;
		this.icons = {};
		this.icons[':-)'] = 'smile';
		this.icons[':-('] = 'unhappy';
		this.icons[';-)'] = 'wink';
		this.icons[':-D'] = 'grin';
		this.icons[':-O'] = 'surprised';
		this.icons[':-P'] = 'tongue';
	}
}
	

// Texty
Texyla.lng = {
	btn_h1: "Největší nadpis",
	btn_h2: "Velký nadpis",
	btn_h3: "Střední nadpis",
	btn_h4: "Nejmenší nadpis",
	btn_bold: "Tučně",
	btn_italic: "Kurzíva",
	btn_del: "Přeškrtnuto",
	btn_center: "Zarovnání na střed",
	btn_left: "Zarovnání vlevo",
	btn_right: "Zarovnání vpravo",
	btn_justify: "Zarovnání do bloku",
	btn_ul: "Seznam",
	btn_ol: "Číslovaný seznam",
	btn_blockquote: "Bloková citace",
	btn_sub: "Dolní index",
	btn_sup: "Horní index",
	btn_link: "Odkaz",
	btn_img: "Obrázek",
	btn_table: "Tabulka",
	btn_acronym: "Vysvětlení zkratky",
	btn_hr: "Čára",
	btn_code: "Kód",
	btn_inlineCode: "Inline kód",
	btn_html: "Vypnutí texy (HTML)",
	btn_notexy: "Vypnutí texy (inline text)",
	btn_web: "Web editoru Texyla",
	btn_emoticon: "Smajlík",
	
	texy_heading_text: "Text nadpisu",
	texy_link_url: "Adresa odkazu",
	texy_acronym_title: "Titulek",
	
	view_edit: "Upravit",
	view_preview: "Náhled",
	view_html: "HTML",
	view_syntax: "Texy syntaxe",
	view_wait: "Prosím čekejte",
	
	img_heading: "Vložit obrázek",
	img_src: "Adresa obrázku",
	img_alt: "Popis",
	img_align: "Zarovnání",
	img_al_none: "žádné",
	img_al_left: "vlevo",
	img_al_right: "vpravo",
	
	tab_heading: "Vložit tabulku",
	tab_cols: "Počet sloupců",
	tab_rows: "Počet řádek",
	tab_th: "Hlavička",
	tab_th_none: "žádná",
	tab_th_top: "nahoře",
	tab_th_left: "vlevo",
	
	emoticon_heading: "Vložit smajlík",
	
	win_ins: "Vložit",
	win_close: "Zavřít"
}

// Konstruktor
function Texyla(options, addr) {
	var _this = this;
	this.options = options;
	
	// Tlačítka
	if (typeof(options.toolbar) == "string") {
		this.options.toolbar = Texyla.toolbars[options.toolbar];
	}
	
	// Addresy
	if (addr) {
		this.addr = addr;
	} else {
		this.addr = new Texyla.defaultAddrs;
	}
	
	if (this.addr.base === undefined) {
		this.addr.base = Texyla.addrBase;
	}
	
	// Přidání prefixu před všechny adresy
	if (this.addr.base) {
		for (i in this.addr) {
			if (this.addr.hasOwnProperty(i) && i !== 'base') {
				this.addr[i] = this.addr.base + this.addr[i];
			}
		}
	}
	
	// Buď najdeme textareu podle ID, nebo již máme objekt Textarea
	this.textarea = typeof(options.textarea) === 'string' ? document.getElementById(options.textarea) : options.textarea;
	
	// smajlíky
	switch (typeof(options.emoticons)) {
		case 'string':
			switch (options.emoticons) {
				case 'silk':
					this.emoticons = new Texyla.emoticons.silk();
				break;
				case 'texy':
					this.emoticons = new Texyla.emoticons.texy();
				break;
			}
		break;
		case 'object':
			this.emoticons = options.emoticons;
		break;
	}
	
	// Zjistí Internet Explorer
	this.IE = this.isIE();
	
	this.Buttons = this.Buttons(this);
	this.Texy = this.Texy();
	this.Dom = this.Dom();
	this.View = this.View();
	this.Windows = this.Windows();
	
	this.Dom.Texyla = this;
	this.View.Texyla = this;
	this.Texy.Texyla = this;
	this.Windows.Texyla = this;
	this.Windows.img.Texyla = this;
	this.Windows.table.Texyla = this;
	this.Windows.emoticon.Texyla = this;
	
	this.Dom.init();
}

Texyla.prototype = {	
	// Pole, ve kterém editujeme Texy
	textarea: null,
	
	// Internet Explorer
	IE: null,
	
	isIE: function() {
		// Opera, Firefox
		if (this.textarea.selectionStart || this.textarea.selectionStart==0) {
			return false;
			
		// IE
		} else {
			if (document.selection) {
				return true;
			}
		}
	},
	
	// Tlačítka	
	Buttons: function(_this) {
		var lng = Texyla.lng;
		return {
			h1:
				{icon:"h1", name:lng.btn_h1, func: function() {_this.Texy.heading('#')} },
			h2:
				{icon:"h2", name:lng.btn_h2, func: function() {_this.Texy.heading('*')} },
			h3:
				{icon:"h3", name:lng.btn_h3, func: function() {_this.Texy.heading('=')} },
			h4:
				{icon:"h4", name:lng.btn_h4, func: function() {_this.Texy.heading('-')} },
			bold:
				{icon:"bold", name:lng.btn_bold, func: function() {_this.Texy.tag('**', '**')} },
			italic:
				{icon:"italic", name:lng.btn_italic, func: function() {_this.Texy.tag('//', '//')} },
			del:
				{icon:"del", name:lng.btn_del, func: function() {_this.Texy.tag('--', '--')} },
			center:
				{icon:"center", name:lng.btn_center, func: function() {_this.Texy.align('<>')} },
			left:
				{icon:"left", name:lng.btn_left, func: function() {_this.Texy.align('<')} },
			right:
				{icon:"right", name:lng.btn_right, func: function() {_this.Texy.align('>')} },
			justify:
				{icon:"justify", name:lng.btn_justify, func: function() {_this.Texy.align('=')} },
			ul:
				{icon:"ul", name:lng.btn_ul, func: function() {_this.Texy.list('ul')}},
			ol:
				{icon:"ol", name:lng.btn_ol, func: function() {_this.Texy.list('ol')}},
			blockquote:
				{icon:"blockquote", name:lng.btn_blockquote, func: function() {_this.Texy.list('bq')}},
			sub:
				{icon:"sub", name:lng.btn_sub, func: function() {_this.Texy.tag('__', '__')} },
			sup:
				{icon:"sup", name:lng.btn_sup, func: function() {_this.Texy.tag('^^', '^^')} },
			link:
				{icon:"link", name:lng.btn_link, func: function() {_this.Texy.link()}},
			img:
				{icon:"img", name:lng.btn_img, func: function() {_this.Windows.img.open(this)} },
			table:
				{icon:"table", name:lng.btn_table, func: function() {_this.Windows.table.open(this)} },
			acronym:
				{icon:"acronym", name:lng.btn_acronym, func: function() {_this.Texy.acronym()} },
			hr:
				{icon:"hr", name:lng.btn_hr, func: function() {_this.Texy.line()} },
			code:
				{icon:"tag", name:lng.btn_code, func: function() {_this.Texy.block('code')} },
			inlineCode:
				{icon:"inline_code", name:lng.btn_inlineCode, func: function() {_this.Texy.tag('`', '`')} },
			html:
				{icon:"html", name:lng.btn_html, func: function() {_this.Texy.block('html')}},
			notexy:
				{icon:"notexy", name:lng.btn_notexy, func: function() {_this.Texy.tag("''", "''")} },
			web:
				{icon:"web", name:lng.btn_web, func: function() {window.open('http://texyla.jaknato.com/')}},
			emoticon:
				{icon:"emoticon", name:lng.btn_emoticon, func: function() {_this.Windows.emoticon.open(this)}}
		}
	},
	
	Texy: function() {
		return {
			selection: {
				txt: null,
				len: null,
				start: null,
				end: null,
				cursor: null
			},
			
			lineFeed: '\r\n',
			lineFeedKnown: false,
			
			tag: function(firstText, secondText) {
				this.changeSelection(false, firstText, secondText);
			},
			
			replaceSelection: function(replacement) {
				this.changeSelection(true, replacement,'');
			},
			
			changeSelection: function(replacement, firstText, secondText) {
				/*
				zmena vyberu
				replacement = true -----> vyber je nahrazen promennou firstText
				replacement = false ----> vyber je obalen firstText a secondText
				*/
				this.doSelect();
				
				// Kolik je odrolováno
				var scrolled = this.Texyla.textarea.scrollTop;
				
				// Změna textu
				var changedText = replacement ? firstText : (firstText + this.selection.txt + secondText);
				this.Texyla.textarea.value =
					this.Texyla.textarea.value.substring(0, this.selection.start) + changedText + this.Texyla.textarea.value.substring(this.selection.start + this.selection.len);
				
				// Pri vyberu zohlední: a) je-li vyber nahrazovan b) je-li obalen vyber ci kurzor
				var from = this.selection.start + ((replacement || !this.selection.cursor) ? 0 : firstText.length);
				if (replacement) {
					var length = firstText.length;
				}
				if (this.selection.cursor && !replacement) {
					var length = this.selection.len;
				}
				if (!this.selection.cursor && !replacement) {
					var length = firstText.length + this.selection.len + secondText.length;
				}
				this.select(from, length);
				
				// Odrolovat na původní pozici
				this.Texyla.textarea.scrollTop = scrolled;
			},
		
			// Funkce zjistí pravděpodobnou podobu formátu nového řádku.
			getLineFeedFormat: function() {
				if (!this.lineFeedKnown) {
					// Pokusí se ho nalézt:
					var unix = this.Texyla.textarea.value.indexOf('\n');
					var mac = this.Texyla.textarea.value.indexOf('\r');
					var win = this.Texyla.textarea.value.indexOf('\r\n');
					
					if ( unix >= 0) {
						this.lineFeed = '\n';
					}
					if (mac >= 0) {
						this.lineFeed = '\r';
					}
					if (win >= 0) {
						this.lineFeed = '\r\n';
					}
					
					// V případě úspěchu nastaví proměnnou this.lineFeedKnown na true a funkce již později hledání neopakuje.
					if (unix >= 0 || mac >= 0 || win >= 0) {
						this.lineFeedKnown = true;
					}
					
					// Jinak se nový řádek nastaví provizorně podle prohlížeče.
					if (!this.lineFeedKnown) {
						// O, IE -> win
						if (document.selection) {
							this.lineFeed = '\r\n';
						// FF -> unix
						} else {
							this.lineFeed = '\n';
						}
					}
				}
			},
			
			// Ulož vlastnosti výběru
			saveSelectionProperties: function() {
				this.Texyla.textarea.focus();
				
				// IE
				if (this.Texyla.IE) {
					var backup = this.Texyla.textarea.value;
					
					var ieSelection = document.selection.createRange();
					var bookmark = "[~Z~A~L~O~Z~K~A~]";
					var selectedText = ieSelection.text;
					ieSelection.text = bookmark + selectedText;
					
					var start = this.Texyla.textarea.value.indexOf(bookmark);
					var end = start + selectedText.length;
					
					this.Texyla.textarea.value = backup;
					
				// O, FF
				} else { 
					var start = this.Texyla.textarea.selectionStart,
						end = this.Texyla.textarea.selectionEnd,
						selectedText = this.Texyla.textarea.value.substring(start, end);
				}
				
				// Aktualizuje promennou this.selection
				var cursor = (end == start);
				this.selection = {
					txt: selectedText,
					len: selectedText.length,
					start: start,
					end: end,
					cursor: cursor
				};
			},
			
			doSelect: function() {
				this.saveSelectionProperties();
				this.select(this.selection.start, this.selection.len); //IE
				this.getLineFeedFormat();
			},
			
			select: function(from, length) {
				if (this.Texyla.IE) {
					var lfCount = this.Texyla.textarea.value.substring(0, from).split("\r\n").length - 1;
					from -= lfCount;
					this.Texyla.textarea.focus();
					this.Texyla.textarea.select();
					ieSelected = document.selection.createRange();
					ieSelected.collapse(true);
					ieSelected.moveStart("character", from);
					ieSelected.moveEnd("character", length);
					ieSelected.select();
					this.Texyla.textarea.focus();
				} else {
					this.Texyla.textarea.selectionStart = from;
					this.Texyla.textarea.selectionEnd = from + length;
				}
				
				this.Texyla.textarea.focus();
			},
			
			selectBlock: function() {
				this.doSelect()
				var workFrom = this.Texyla.textarea.value.substring(0, this.selection.start).lastIndexOf(this.lineFeed);
				if (workFrom != -1) {
					workFrom += this.lineFeed.length;
				}
				var from = Math.max(0, workFrom);
				
				var ta = this.Texyla.textarea;
				var workLength = ta.value.substring(workFrom, this.selection.start).length + this.selection.len;
				var fromSelectionEnd = ta.value.substring(this.selection.end, ta.value.length);
				var lineFeedPos = fromSelectionEnd.indexOf(this.lineFeed);
				workLength += lineFeedPos==-1 ? fromSelectionEnd.length : lineFeedPos;
				this.select(from, workLength);
				this.doSelect();
			},
					
			// konkrétní fce
			align: function(type) {
				this.doSelect();
			
				var start = '.' + type + this.lineFeed,
					newPar = this.lineFeed + this.lineFeed,
					found = this.Texyla.textarea.value.substring(0, this.selection.start).lastIndexOf(newPar),
					beforePar = found + newPar.length;
				
				if (found ==- 1) {
					this.Texyla.textarea.value = start + this.Texyla.textarea.value;
				} else {
					this.Texyla.textarea.value = this.Texyla.textarea.value.substring(0, beforePar) + start + this.Texyla.textarea.value.substring(beforePar);
				}
				this.select(this.selection.start + start.length, this.selection.len);
			},
			
			list: function(type) {
				this.selectBlock();
				
				var lines = this.selection.txt.split(this.lineFeed);
				var lineCount = this.selection.cursor ? 3 : lines.length;
				var replacement = '';
				
				for (i = 1; i <= lineCount; ++i) {
					// UL
					if (type === 'ul') {
						replacement += '- ';
					// OL
					} else if (type === 'ol') {
						replacement += i+') ';
					// Blockquote
					} else if (type === 'bq') {
						replacement += '> ';
					}
					if (this.selection.cursor && i === 1) {
						var firstLength = replacement.length;
					}
					if (!this.selection.cursor) {
						replacement += lines[i - 1];
					}
					if (i !== lineCount) {
						replacement += this.lineFeed;
					}
				}
				
				if (this.selection.cursor) {
					this.tag(replacement.substring(0, firstLength), replacement.substring(firstLength));
				} else {
					this.replaceSelection(replacement);
				}
			},
			
			// Vrátí string, kde bude 'length'krát za sebou 'type'
			headingCreate: function(type, length) {
				var underline = '';
				for (var i=0; i < length; ++i) {
					underline += type;
				}
				return underline;
			},
			
			heading: function(type) {
				this.selectBlock();
				// Nový nadpis
				if (this.selection.cursor) {
					var headingText = prompt(Texyla.lng.texy_heading_text, "");
					if (headingText) {
						this.tag(
							headingText + this.lineFeed + this.headingCreate(type, headingText.length) + this.lineFeed,
							''
						);
					}
				// Vyrobí nadpis z výběru
				} else {
					this.tag(
						'',
						this.lineFeed + this.headingCreate(type, this.selection.len)
					);
				}
			},
			
			link: function() {
				var addr = prompt(Texyla.lng.texy_link_url, 'http://');
				if (addr != undefined) {
					this.tag('"', '":' + addr);
				}
			},
			
			acronym: function() {
				this.doSelect();
				var title = prompt(this.Texyla.texy_acronym_title, '');
				if (title != undefined) {
					// Nejsou potřeba uvozovky. př.: slovo((titulek))
					if (this.selection.txt.match(/^[a-zA-ZěščřžýáíéúůĚŠČŘŽÝÁÍÉÚŮ]{2,}$/)) {
						this.tag('','((' + title + '))');
						
					// Jsou potřeba uvozovky. př.: "třeba dvě slova"((titulek))
					} else {
						this.tag('"', '"((' + title + '))');
					}
				}
			},
			
			line: function() {
				this.doSelect();
				var lineText = this.lineFeed + this.lineFeed + '-------------------' + this.lineFeed + this.lineFeed;
				if (this.selection.cursor) {
					this.tag(lineText, '');
				} else {
					this.replaceSelection(lineText);
				}
			},
			
			block: function(what) {
				this.getLineFeedFormat();
				this.tag('/---' + what + this.lineFeed, this.lineFeed + '\\---');
			},
			
			img: function(src, alt, align, descr) {
				var imgT = '[* ' + src + ' ';
				
				// Popis
				if(alt) {
					imgT += '.('+ alt +') ';
				}
				
				//zarovnání
				imgT += align +']';
				
				// Popisek
				if (descr) {
					imgT += ' *** ' + alt;
				}
				
				this.replaceSelection(imgT);
			},
			
			table: function(cols, rows, header) {
				this.getLineFeedFormat();
				var tabTxt = this.lineFeed;
				
				for (i = 0; i < rows; ++i) {
					// Hlavička nahoře
					if (header === 'n' && i < 2) {
						tabTxt += '|';
						for (j = 0; j < cols; ++j) {
							tabTxt += '--------';
						}
						tabTxt += this.lineFeed;
					}
					
					// Buňky
					for (j = 0; j < cols; ++j) {
						// Hlavička vlevo
						if (header === 'l' && j === 0) {
							tabTxt += "|* \t";
							
						// Buňka bez hlavičky
						} else {
							tabTxt += "| \t"; 
						}
						if (i === 0 && j === 0) {
							var firstLength = tabTxt.length - 1;
						}
					}
					tabTxt += '|' + this.lineFeed;
				}
				tabTxt += this.lineFeed;
				
				// Vloží tabulku
				this.tag(tabTxt.substring(0, firstLength), tabTxt.substring(firstLength));
			}
		}
	},
	Dom: function() {
		return {
			//Kontejner na texylu
			container: null,
			
			// Načtení texyly
			init: function() {
				// načíst CSS
				Texyla.loadStylesheet(this.Texyla.addr.css + 'base.css');
				Texyla.loadStylesheet(this.Texyla.addr.css + this.Texyla.options.theme +'/'+ this.Texyla.options.theme + '.css');
				
				// Automatická šířka
				if (this.Texyla.options.editorWidth == 'auto') {
					this.Texyla.options.editorWidth = this.Texyla.textarea.offsetWidth;
				}
				
				// Kontejner na Texylu
				var skinCont = this.Texyla.textarea.parentNode.insertBefore(
					_('div', { className: this.Texyla.options.theme }),
					this.Texyla.textarea
				);
				this.container = skinCont.appendChild( _('div', { className: 'Texyla' }) );
				this.container.style.width = this.Texyla.options.editorWidth + 'px';
				
				// Vytvořit bloky
				this.editBlock();
				this.viewBlock();
				if (this.Texyla.options.allowHtmlPreview) {
					this.htmlBlock();
				}
				
				// Tlačítka pod textareou
				this.createBottomBar();
				
				// Zobrazit
				this.Texyla.View.switchView('edit');
			},
			
			// Editační blok
			editBlock: function() {
				var editBlock = this.container.appendChild(_('div'));
				var View = this.Texyla.View;
				
				editBlock.appendChild(this.createTopBar());		// Vložení horní lišty
				var textareaParent = editBlock.appendChild( _('div', {className: 'textareaParent' }) );
				textareaParent.appendChild(this.Texyla.textarea);
				
				// Margin textarey
				if (this.Texyla.options.textareaMargin) {
					this.Texyla.textarea.style.width = ( this.Texyla.options.editorWidth - 2 * this.Texyla.options.textareaMargin ) + 'px';
					this.Texyla.textarea.style.margin = this.Texyla.options.textareaMargin + 'px 0';
				}
				
				// Přidá pohled
				View.views.push({
					block: editBlock,
					control: this.button(Texyla.lng.view_edit, "edit", function() { View.switchView('edit') }),
					btn: this.button(Texyla.lng.view_syntax, "help", function() { window.open('http://texy.info/cs/syntax/') })
				});
			},
			
			// Náhled
			viewBlock: function() {
				var viewBlock =  this.container.appendChild(_('div'));
				var View = this.Texyla.View;
				viewBlock.appendChild(this.createHeading('view',Texyla.lng.view_preview));
				View.previewDiv = viewBlock.appendChild( _('div', { className: 'preview' }) );
				
				View.views.push({
					block: viewBlock,
					control: this.button(Texyla.lng.view_preview, "view", function() { View.switchView('preview') }),
					btn: null
				});
			},
			
			// Náhled HTML
			htmlBlock: function() {
				var htmlBlock =  this.container.appendChild(_('div'));
				var View = this.Texyla.View;
				htmlBlock.appendChild(this.createHeading('source', Texyla.lng.view_html));
				View.htmlPreviewDiv = htmlBlock.appendChild( _('div', { className: 'htmlPreview' }) );
				
				View.views.push({
					block: htmlBlock,
					control: this.button(Texyla.lng.view_html, "source", function() { View.switchView('HTML') }),
					btn: null
				});
			},
			
			// Hlavička
			createHeading: function(icon, text) {
				var dom = _('div', { className: 'heading' });
				dom.appendChild(this.img(icon, text));
				dom.appendChild(_t(text));
				return dom;
			},
			
			// Zobrazení a nápověda
			createBottomBar: function() {
				var blockBtn = this.container.appendChild( _('div', {
					className: 'bottomBar' + (this.Texyla.options.coolButtons ? ' cool' : '')
				}));
				var _this = this.Texyla;
				
				// Tlačítko vpravo dole
				this.bottomRightBar = blockBtn.appendChild( _("span", { className: 'bottomRightBar' }) );
		
				// Tlačítka vlevo dole
				var views = this.Texyla.View.views;
				for (var i=0; i<views.length; i++) {
					var block = blockBtn.appendChild(views[i].control);
				}
			},
			
			// Vytvoří tlačítkovou lištu
			createTopBar: function() {
				var domBar = _("ul", { className: 'toolbar' });
				
				// Tlačítka
				var toolbar = this.Texyla.options.toolbar;
				var buttons = this.Texyla.Buttons;
				
				for (var i=0; i<toolbar.length; i++) {
					// Oddělovač
					if (toolbar[i] == null) {
						domBar.appendChild( _("li", { className: 'separator' }) );
						continue;
					}
					
					// Ikonka
					if (typeof(toolbar[i]) == "string") {
						var li = domBar.appendChild(_("li"));
						var img = li.appendChild(this.img(buttons[toolbar[i]].icon, buttons[toolbar[i]].name));
						img.className = 'link';
						img.onclick = buttons[toolbar[i]].func;
						this.hover(img);
						continue;
					}
					
					// Menu
					if (typeof(toolbar[i]) == "object") {
						var li = domBar.appendChild( _("li", { className: typeof(toolbar[i-1]) == "string" ? "btnmenu" : "menu" }) );
						var menu = li.appendChild(_("ul"));
						var menuArray = toolbar[i];
						this.hover(li);
						
						// Položky
						for (var j=0;j<menuArray.length;j++) {
							var item = menu.appendChild(_("li"));
							item.onclick = buttons[menuArray[j]].func;
							item.appendChild(this.img(buttons[menuArray[j]].icon));
							var span = item.appendChild(_('span'));
							span.appendChild(_t(buttons[menuArray[j]].name));
							this.hover(item);
						}
						continue;
					}
				}
				
				return domBar;
			},
			
			// Hover efekt
			hover: function(el) {
				el.onmouseover = function() { Texyla.hover(el, true); }
				el.onmouseout = function() { Texyla.hover(el, false); }
			},
			
			// vložit element někam
			setContent: function(ref, el) {
				while (ref.hasChildNodes()) {
					ref.removeChild(ref.childNodes[0]);
				}
				if (el) {
					ref.appendChild(el);
				}
			},
			
			button: function(title, icon, func) {
				// Hezké tlačítko
				if (this.Texyla.options.coolButtons == true) {
					var tab = this.table(3,1);
					var btn = tab.table;
					
					btn.className = 'coolButton';
					btn.onclick = func;
					this.hover(tab.table);
					
					//strany
					tab.cells[0][0].className = 'left';
					tab.cells[0][2].className = 'right';
					
					// střed
					var middle = tab.cells[0][1].appendChild( _('div', { className: 'middle' }) );
					if (icon) {
						middle.appendChild(this.img(icon));
					}
					middle.appendChild(_t(title));
					
				// Normální tlačítko
				} else {
					var btn = _('button', { type: 'button' });
					if (icon) {
						btn.appendChild(this.img(icon));
					}
					if (title) {
						btn.appendChild(_t(" " + title));
					}
				}
				
				btn.onclick = func;
				return btn;
			},
			
			img: function(file, title) {
				var opt = {
					src: this.Texyla.addr.icons + this.Texyla.options.iconType + "/" + file + "." + this.Texyla.options.iconFormat,
					width: 16,
					height: 16
				}
				if (title) {
					opt.title = title;
					opt.alt = title;
				}
				return _('img', opt);
			},
			
			// vrátí tabulku o rozměrech x × y
			table: function(x, y) {
				var div = _('div');
				div.innerHTML = '<table cellspacing="0" cellpadding="0"></table>';
				var table = div.getElementsByTagName('table')[0];
				var tbody = table.appendChild(_('tbody'));
				var rows = [];
				var cells = [];
				
				if (x!==undefined && y!==undefined) {
					// řádky
					for (var i=0; i<y; i++) {
						rows[i] = tbody.appendChild(_('tr'));
						
						// buňky
						cells[i] = [];
						for (var j=0; j<x; j++) {
							cells[i][j] = rows[i].appendChild(_('td'));
						}
					}
				}
				
				return {
					table: table,
					tbody: tbody,
					rows: rows,
					cells: cells
				}
			},
			
			formInput: function(options) {
				var dom = _('tr');
				
				// th
				var th = dom.appendChild(_('th'));
				var label = th.appendChild(_('label'));
				label.appendChild(_t(options.name));
				
				// td
				var td = dom.appendChild(_('td'));
				switch (options.type) {
					case 'input':
						var inp = td.appendChild(_('input', options.attributes));
						inp.onfocus = function() { this.select() };
					break;
					case 'select':
						var inp = td.appendChild(_('select', options.attributes));
						// options
						for (var i = 0; i < options.options.length; i++) {
							var opt = inp.appendChild( _('option', { value: options.options[i][0] }) );
							opt.appendChild(_t(options.options[i][1]));
							if (options.options[i][2] == true) {
								opt.selected = true;
							}
						}
					break;
				}	
				
				// label for
				label.setAttribute('for', 'winInp' + ++Texyla.Window.maxInput);
				inp.setAttribute('id', 'winInp' + Texyla.Window.maxInput);
				
				return {
					dom: dom,
					inp: inp
				}
			}
		}
	},
	
	View: function() {
		return {
			views: [],
			
			// Náhled zpracovaného Texy
			previewDiv: null,
			
			// Div s náhledem HTML
			htmlPreviewDiv: null,
			
			// Tlačítka vpravo dole
			bottomRightBar: null,
			
			// Poslední zpracované Texy
			lastPreviewTexy: null,
			
			switchView: function(viewName) {			
				var changed = this.lastPreviewTexy !== this.Texyla.textarea.value;
				
				if (changed && viewName !== 'edit') {
					var msg = _('p', {className: 'wait' });
					msg.appendChild(_t(Texyla.lng.view_wait));
					
					this.Texyla.Dom.setContent(this.previewDiv, msg);
					
					if (this.Texyla.options.allowHtmlPreview) {
						this.Texyla.Dom.setContent(this.htmlPreviewDiv, msg.cloneNode(true));
					}
					
					this.lastPreviewTexy = this.Texyla.textarea.value;
					this.getPreview();
				}
				
				var viewId = {
					// Upravit
					edit: 0,
					
					// Náhled
					preview: 1,
					
					// HTML zdroj
					HTML: 2
				}
				
				// Bloky
				for (var i=0; i < this.views.length; i++) {
					this.views[i].block.style.display = i === viewId[viewName] ? 'block' : 'none';
				}
				
				// Tlačítka dole vlevo
				for (var i=0; i<this.views.length; i++) {
					this.views[i].control.style.display = i === viewId[viewName] ? 'none' : 'inline';
				}
				
				// Tlačítko dole vpravo
				var bar = this.Texyla.Dom.bottomRightBar;
				var btn = this.views[viewId[viewName]].btn;
				this.Texyla.Dom.setContent(bar, btn ? btn : null);
			},
			
			getPreview: function() {
				var _this = this;
				function onLoad(res) {
					return _this.onPreviewLoad(res);
				}
				var options = { onComplete: onLoad, jsonRes: true };
				var vars = { texylaContent: this.Texyla.textarea.value, texylaTexyCfg: this.Texyla.options.texyCfg};
				if (this.Texyla.options.AjaxPreProcessor) {
					this.Texyla.options.AjaxPreProcessor(options);
				}
				new Texyla.Ajax(this.Texyla.addr.ajax, options, vars);
			},
			
			onPreviewLoad: function(res) {
				if (this.Texyla.options.AjaxProcessor) {
					res = this.Texyla.options.AjaxProcessor(res);
				}
				this.previewDiv.innerHTML = res;
				
				// Zobrazí zdrojový kód (HTML)
				if (this.Texyla.options.allowHtmlPreview) {
					var pre = _('pre');
					var innerText = _t( res.replace(/\n/g, this.Texyla.Texy.lineFeed) );
					pre.appendChild(innerText);
					this.Texyla.Dom.setContent(this.htmlPreviewDiv, pre);
				}
			}
		}
	},
	
	Windows: function () {
		return {
			// otevřená okna
			open: {
				img: false,
				table: false,
				emoticon: false
			},
			
			// obrázek
			img: {
				window: null,
				src: null,
				alt: null,
				align: null,
				descr: null,
				
				open: function(btnClicked) {
					if (this.Texyla.Windows.open.img == true) {
						this.window.focus();
						return false;
					}
					this.Texyla.Windows.open.img = true;
					
					var _this = this;
					
					var properties = {
						heading: Texyla.lng.img_heading,
						content: null,
						func: function() {
							_this.Texyla.View.switchView('edit');
							_this.Texyla.Texy.img(_this.src.value, _this.alt.value, _this.align[_this.align.selectedIndex].value, _this.descr.checked);
							_this.window.close();
						},
						_this: this,
						open: 'img',
						btnClicked: btnClicked
					};
					
					// Obsah
					properties.content = _('div');
					var tab = this.Texyla.Dom.table();
					var table = properties.content.appendChild(tab.table);
					
					var attr = {type: 'text', className: 'textField'};
					
					// Adresa
					var tr = this.Texyla.Dom.formInput({name: Texyla.lng.img_src, type: 'input', attributes: attr});
					tab.tbody.appendChild(tr.dom);
					this.src = tr.inp;
					
					// Alt
					tr = this.Texyla.Dom.formInput( {name: Texyla.lng.img_alt, type: 'input', attributes: attr} );
					tab.tbody.appendChild(tr.dom);
					this.alt = tr.inp;
					
					// Popisek
					tr = tab.tbody.appendChild(_('tr'));
					tr.appendChild(_('td'));
					td = tr.appendChild(_('td'));
					
					var label = td.appendChild(_('label'));
					this.descr = label.appendChild( _('input', {type: 'checkbox'}) );
					label.appendChild(_t('Zobrazit jako popisek'));
					
					// Hlavička
					tr = this.Texyla.Dom.formInput({
						name: Texyla.lng.img_align,
						type: 'select',
						options: [
							['*', Texyla.lng.img_al_none, true],
							['<', Texyla.lng.img_al_left, false],
							['>', Texyla.lng.img_al_right, false]
						]
					});
					tab.tbody.appendChild(tr.dom);
					this.align = tr.inp;
					
					this.window = new Texyla.Window(properties);
				}
			},
			
			// smajlík
			emoticon: {
				window: null,
				
				open: function(btnClicked) {
					if (this.Texyla.Windows.open.emoticon == true) {
						this.window.focus();
						return false;
					}
					this.Texyla.Windows.open.emoticon = true;
					
					var _this = this;
					
					var properties = {
						heading: Texyla.lng.emoticon_heading,
						content: null,
						func: null,
						_this: this,
						open: 'emoticon',
						btnClicked: btnClicked
					};
					
					// Obsah
					properties.content = _('div');
					
					var emDiv = properties.content.appendChild(_('div', {className: 'emoticons'}));
					var emCt = 0;
					for (var i in this.Texyla.emoticons.icons) {
						//jednou za 5 smajlíků odřádkuje
						if (emCt%12 == 0 && emCt > 0) {
							emDiv.appendChild(_('br'));
						}
						emCt++;
						
						//vloží obrázek
						var img = emDiv.appendChild(_('img', {
							width: this.Texyla.emoticons.width,
							height: this.Texyla.emoticons.height,
							alt: i,
							title: i,
							src: this.Texyla.emoticons.root + this.Texyla.emoticons.icons[i] + '.' + this.Texyla.emoticons.iconFormat
						}));
						img.onclick = function() {_this.Texyla.Texy.replaceSelection(this.title); _this.window.close()}
						this.Texyla.Dom.hover(img);
					}
					
					this.window = new Texyla.Window(properties);
				}
			},
			
			// tabulka
			table: {
				window: null,
				
				// formulářové prvky
				cols: null,
				rows: null,
				select: null,
				
				// rychlá tabulka
				select: null,
				table: null,
				
				open: function(btnClicked) {
					if (this.Texyla.Windows.open.table == true) {
						this.window.focus();
						return false;
					}
					this.Texyla.Windows.open.table = true;
					
					var _this = this;
					
					var properties = {
						heading: Texyla.lng.tab_heading,
						content: null,
						func: function() {
							_this.Texyla.View.switchView('edit');
							_this.Texyla.Texy.table(_this.cols.value, _this.rows.value, _this.header[_this.header.selectedIndex].value);
							_this.window.close();
						},
						_this: this,
						open: 'table',
						btnClicked: btnClicked
					};
					
					// Obsah
					properties.content = _('div');
					var tab = this.Texyla.Dom.table();
					var table = properties.content.appendChild(tab.table);
					table.className = 'table';
					
					var attr = {type: 'number', value: 2, min: 1, maxlength: 2, className: 'number'};
					
					// Sloupce
					var tr = this.Texyla.Dom.formInput( {name: Texyla.lng.tab_cols, type: 'input', attributes: attr} );
					tab.tbody.appendChild(tr.dom);
					this.cols = tr.inp;
					
					// Řádky
					tr = this.Texyla.Dom.formInput( {name: Texyla.lng.tab_rows, type: 'input', attributes: attr} );
					tab.tbody.appendChild(tr.dom);
					this.rows = tr.inp;
					
					// Hlavička
					tr = this.Texyla.Dom.formInput({
						name: Texyla.lng.tab_th,
						type: 'select',
						options: [
							['', Texyla.lng.tab_th_none, false],
							['n', Texyla.lng.tab_th_top, true],
							['l', Texyla.lng.tab_th_left, false]
						]
					});
					tab.tbody.appendChild(tr.dom);
					this.header = tr.inp;
					
					// rychlá tabulka
					this.table = properties.content.appendChild(_('div', { className: 'tabBackground' }));
					this.select = this.table.appendChild(_('div', { className: 'tabSelection' }));
					var tabControl = this.table.appendChild(_('div', { className: 'tabControl' }));
					
					// Vybírání velikosti myší
					tabControl.onmousemove = function(e) { var event = e || window.event; _this.doSelect(event); };
					tabControl.onmouseover = function() { _this.tabSelect = true };
					tabControl.onclick = function() { _this.tabSelect = !_this.tabSelect; _this.cols.focus(); };
					tabControl.ondblclick = properties.func;
					
					function setColor(el) {
						var func = function() { _this.setColor(_this.cols.value, _this.rows.value); }
						el.onkeyup = func;
						el.onchange = func;
					}
					setColor(this.cols);
					setColor(this.rows);
					
					this.window = new Texyla.Window(properties);
				},
				
				// Velikost čtverečku
				tabRectangle: 8,
				
				// Povolena změna rozměrů tabulky
				tabSelect: true,
				
				getDimensions: function(event) {
					var posEl = Texyla.getPosition(this.table);
					var mouseX = event.x + document.documentElement.scrollLeft || event.pageX;
					var mouseY = event.y + document.documentElement.scrollTop || event.pageY;
					var posX = mouseX - posEl.left;
					var posY = mouseY - posEl.top;
					
					// Rozměry
					return {
						cols: Math.max(1, Math.ceil(posX / this.tabRectangle)),
						rows: Math.max(1, Math.ceil(posY / this.tabRectangle))
					}
				},
				
				doSelect: function(event) {
					if (this.tabSelect) {
						var dimensions = this.getDimensions(event);
						this.setColor(dimensions.cols, dimensions.rows);
						this.cols.value = dimensions.cols;
						this.rows.value = dimensions.rows;
					}
				},
				
				setColor: function(cols, rows) {
					this.select.style.width = (Math.min(cols, 10) * this.tabRectangle) + 'px';
					this.select.style.height = (Math.min(rows, 10) * this.tabRectangle) + 'px';
				}
			}
		}
	}
}

Texyla.Window = function(properties) {
	var _this = this;
	this.properties = properties;
	this.Texyla = properties._this.Texyla;
	
	// okno
	this.skinCont = document.body.appendChild( _('div', {className: this.Texyla.options.theme}) );
	var tab = this.Texyla.Dom.table(1,1);
	this.skinCont.appendChild(tab.table);
	tab.table.className = 'TexylaPopup';
	this.win = tab.table;
	this.win.onmousedown = function() { _this.focus(); }
	
	this.form = tab.cells[0][0].appendChild(_('form'));
	if (properties.func) {
		this.form.onsubmit = function() {properties.func(); return false;}
	}
	var submit = this.form.appendChild( _('button', {type: 'submit'}) );
	submit.style.display = 'none';
	
	// hlavička
	this.header();
	
	// obsah
	properties.content.className = 'winForm';
	this.form.appendChild(properties.content);
	
	// spodní lišta
	if (properties.func) {
		var bottomBar = this.form.appendChild( _('div', {
			className: 'bottomBar' + (this.Texyla.options.coolButtons ? ' cool' : '')
		}) );
		bottomBar.appendChild(this.Texyla.Dom.button(Texyla.lng.win_ins, "tick", properties.func));
	}

	var leftPos = Math.min(document.body.offsetWidth - this.win.offsetWidth, Texyla.getPosition(this.properties.btnClicked).left)
	this.win.style.left = Math.max(0, leftPos) + 'px';
	this.win.style.top = Texyla.getPosition(this.Texyla.textarea).top + 5 + 'px';
	
	//focus
	var firstInput = this.win.getElementsByTagName('input')[0];
	if (firstInput) {
		firstInput.focus();
	}
}
Texyla.Window.maxZIndex = 0;
Texyla.Window.maxInput = 0;

Texyla.Window.prototype = {
	lastX: 0,
	lastY: 0,
	dragging: false,
	
	close: function() {
		this.Texyla.Windows.open[this.properties.open] = false;
		document.body.removeChild(this.skinCont);
	},
	
	focus: function() {
		this.win.style.zIndex = ++Texyla.Window.maxZIndex;
	},
	
	header: function() {
		var _this = this;
		var header = this.form.appendChild(_('div', { className: 'heading' }));
		this.dragger = header.appendChild(_('div'));
		header.appendChild(this.Texyla.Dom.img(this.properties.open));
		this.dragger.appendChild(_t(this.properties.heading));
		var close = header.appendChild(_('span', { className: 'close', title: Texyla.lng.win_close }));
		close.onclick = function() { _this.close(); }
		this.Texyla.Dom.hover(close);
		
		// fce
		this.dragger.onmousedown = function(event) { _this.dragStart(event || window.event); return false; };
		this.dragger.onmouseup = function() { _this.dragEnd() };
		this.dragger.onmouseout = function(event) { _this.doDrag(event || window.event) };
	},
	
	dragStart: function(event) {
		var _this = this;
		this.dragging = true;
		this.lastX = event.x || event.pageX;
		this.lastY = event.y || event.pageY;
		document.body.onmousemove = function(event) {
			_this.doDrag(event || window.event);
			return false;
		};
	},
	
	dragEnd: function() {
		document.body.onmousemove = null;
		this.dragging = false;
	},
	
	doDrag: function(event) {
		if (!this.dragging) {
			return;
		}
		var mouseX = event.x || event.pageX;
		var mouseY = event.y || event.pageY;
		
		this.win.style.left = (parseInt(this.win.style.left) + mouseX - this.lastX) + 'px';
		this.win.style.top = (parseInt(this.win.style.top) + mouseY - this.lastY) + 'px';
		
		this.lastX = mouseX;
		this.lastY = mouseY;
	}
}

// Hover efekty, při najetí myší přiřadí nebo ubere třídu hover
Texyla.hover = function(el, hover) {
	if (hover) {
		el.className += (el.className ? ' ' : '') + 'hover';
	} else {
		el.className = el.className.replace(/ ?hover/,'');
	}
}

// Zjištění pozice elementu na stránce, počítá i s offsetParent
Texyla.getPosition = function(el) {
	var left = 0;
	var top = 0;
	while (el) {
		left += el.offsetLeft;
		top += el.offsetTop;
		el = el.offsetParent;
	}
	return {
		left: left,
		top: top
	}
}

Texyla.Ajax = function(url, options, params) {
	var _this = this;
	this.xmlhttp = Texyla.Try(
		function() { return new XMLHttpRequest() },
		function() { return new ActiveXObject('Msxml2.XMLHTTP') },
		function() { return new ActiveXObject('Microsoft.XMLHTTP') }
	);
	this.onComplete = options.onComplete;
	this.options = options;
	function onStateChange() {
		if (_this.xmlhttp.readyState == 4) {
			var res = _this.xmlhttp.responseText;
			_this.onComplete(res);
		}
	};
	this.onStateChange = this;
	this.xmlhttp.onreadystatechange = onStateChange;
	this.xmlhttp.open('post', url + '?str=' + (new Date().getTime()), true);
	this.xmlhttp.setRequestHeader(
		'Content-Type', 'application/x-www-form-urlencoded'
	);
	post = 'texylaAjax=1';
	esc = encodeURIComponent || escape;
	for (i in params) {
		if (params.hasOwnProperty(i)) {
			post += '&' + i + '=' + esc(params[i]);
		}
	}
	this.xmlhttp.send(post);
}

Texyla.Try = function() {
	var retval;
	for (i = 0; i < arguments.length; ++i) {
		try {
				retval = new arguments[i];
		} catch(e) {
				continue;
		}
		return retval;
	}
}

Texyla.getAddrBase = function() {
	var scripts = document.getElementsByTagName("head")[0].getElementsByTagName("script");
	var src = scripts[scripts.length - 1].src;
	var file = /\/[\w-]+\.js$/;
	var addrBase = src.replace(file, '') + '/';
	
	return addrBase;
}

Texyla.addrBase = Texyla.getAddrBase();

// Načte css soubor, pokud již není načten
Texyla.loadStylesheet = function(href) {
	var stylesheets = document.styleSheets;
	for (var i = 0; i < stylesheets.length; i++) {
		if (href == stylesheets[0].href) {
			return;
		}
	}
	//alert(stylesheets.length);
	var link = _('link');
	link.setAttribute('href', href);
	link.setAttribute('type', 'text/css');
	link.setAttribute('rel', 'stylesheet');
	document.getElementsByTagName('head')[0].appendChild(link);
}

// zkusí přednačíst základní css v defaultním umístění
Texyla.loadStylesheet(Texyla.addrBase + Texyla.defaultAddrs().css + 'base.css');

// Helper funkce

function _(name, attr) {
	var el = document.createElement(name);
	
	if (attr) {
		for (var prop in attr) {
			if (attr.hasOwnProperty(prop)) {
				var val = attr[prop];
				if (prop == 'className') {
					el.className = val;
				} else {
					var Opera = navigator.userAgent.indexOf('Opera') != -1;
					if (name=="input" && prop == "type" && val == "number" && !Opera) {
						val = "text";
					}
					el.setAttribute(prop, val);
				}
			}
		}
	}
	
	return el;
}

function _t(txt) {
	return document.createTextNode(txt);
}
