﻿/*
MDBG Javascript Pinyin IME v1.0.1

Copyrights MDBG 2007

Last modified: 2007-04-24
*/

browser=null;

cancelNextKeyPress=false;
passNextKeyPress=false;

txbInputArea = null;
ckbEnglishMode = null;
ckbDoubleWidthMode = null;

imeSize=0;
initialInputAreaRows=0;
initialInputAreaCols=0;
initialWindowWidth=480;
initialWindowHeight=480;
largeWindowWidth=850;
largeWindowHeight=700;

/*
āáǎàaōóǒòoēéěèeīíǐìiūúŭùuǖǘǚǜü

āáǎà a
ōóǒò o
ēéěè e
īíǐì i
ūúŭù u
ǖǘǚǜ ü
*/
toneMarksArray = new Array();
toneMarksArray['a'] = {1:'ā',2:'á',3:'ǎ',4:'à',5:'a'}
toneMarksArray['o'] = {1:'ō',2:'ó',3:'ǒ',4:'ò',5:'o'}
toneMarksArray['e'] = {1:'ē',2:'é',3:'ě',4:'è',5:'e'}
toneMarksArray['i'] = {1:'ī',2:'í',3:'ǐ',4:'ì',5:'i'}
toneMarksArray['u'] = {1:'ū',2:'ú',3:'ŭ',4:'ù',5:'u'}
toneMarksArray['ü'] = {1:'ǖ',2:'ǘ',3:'ǚ',4:'ǜ',5:'ü'}

toneMarksArray['A'] = {1:'Ā',2:'Á',3:'Ǎ',4:'À',5:'A'}
toneMarksArray['O'] = {1:'Ō',2:'Ó',3:'Ǒ',4:'Ò',5:'O'}
toneMarksArray['E'] = {1:'Ē',2:'É',3:'Ě',4:'È',5:'E'}
toneMarksArray['I'] = {1:'Ī',2:'Í',3:'Ǐ',4:'Ì',5:'I'}
toneMarksArray['U'] = {1:'Ū',2:'Ú',3:'Ŭ',4:'Ù',5:'U'}
toneMarksArray['Ü'] = {1:'Ǖ',2:'Ǘ',3:'Ǚ',4:'Ǜ',5:'Ü'}

function GetSelectionPos(element) {
	var selectionStart = element.value.length;
	var selectionEnd = selectionStart;
	switch (browser) {
		case 1: // IE
		
		
	 
			selectionStart = getSelectionStart(element);
			selectionEnd = getSelectionEnd(element);

/*
			// use a range to add it to the text area
			var range=document.selection.createRange();

			// We'll use this as a 'dummy'
			var stored_range = range.duplicate();
			// Select all text
			stored_range.moveToElementText(element);
			// Now move 'dummy' end point to end point of original range
			stored_range.setEndPoint('EndToEnd', range);
			// Now we can calculate start and end points
			selectionStart = stored_range.text.length - range.text.length;
			selectionEnd = selectionStart + range.text.length;
*/

			break;
		case 2: // Gecko
		case 4: // Safari
			// get current selection location
			selectionStart = txbInputArea.selectionStart;
			selectionEnd = txbInputArea.selectionEnd;
	}

	return new Array(selectionStart, selectionEnd);
}

function insertIntoString(originalString, insertString, selectionStart, selectionEnd) {
	// replace selection with new text
	var textBeforeSelection = originalString.substring(0, selectionStart);
	var textAfterSelection = originalString.substring(selectionEnd);
	return textBeforeSelection + insertString + textAfterSelection;
}

function SendString(s) {
	return SendString(s, false);
}

// send a string to the textarea
function SendString(element, s, backwardsReplace) {
	if (s!="") {
		switch (browser) {
			case 1: // IE
				// use a range to add it to the text area
				var range = document.selection.createRange();
				if(backwardsReplace) {
					range.moveStart('character', -s.length);
					range.text = s;
				}
				else {
					range.text = s;
				}
				range.select();
				break;
			case 2: // Gecko
			case 4: // Safari
				// Remember previous scroll position and text area length
				var previousScrollTop = element.scrollTop;
				var previousScrollHeight = element.scrollHeight;
				var previousLen = element.value.length;

				// get current selection location
				selectionStart = element.selectionStart;
				selectionEnd = element.selectionEnd;

				if(backwardsReplace) {
					selectionStart -= s.length;
				}
				
				// replace selection with new text
				element.value = insertIntoString(element.value, s, selectionStart, selectionEnd);

				// move cursor
				element.selectionStart = element.selectionEnd = selectionStart + s.length;

				// correct the scroll position of the textarea, because gecko resets it to 0
				if (element.scrollHeight > previousScrollHeight) {
					// if the text area's height increased, scroll down the amount it increased in height
					element.scrollTop = previousScrollTop + (element.scrollHeight - previousScrollHeight);
				}
				else {
					// else scroll to original scroll positon
					element.scrollTop = previousScrollTop;
				}
	
				break;
			case 3: // Opera
			default: // Other browsers
				if(selectionStart == -1) {
					// just add it to the end of the text area, don't move cursor / selection
					element.value += s;
				}
				else {
					// add it in place, don't move the cursor / selection
					element.value = insertIntoString(element.value, s, element.value - s.length, element.value);
				}
		}
	}
}

// convert characters to doublewidth
function ToDoubleWidthLetter(s) {
	var result="";

	for (idx=0;idx<s.length;idx++) {
		var charCode = s.charCodeAt(idx);

		if (charCode>=65 && charCode<=90) {
			// capital letters
			result += String.fromCharCode(charCode - 65 + 65313);
		}
		else if (c>=97 && c<=122) {
			// small caps
			result += String.fromCharCode(charCode - 97 + 65345);
		}
		else {
			result += s.charAt(idx);
		}
	}
	
	return result;
}

// handle keydown events
function ImeKeyDown(e) {
	// get key code
	var key = e.which ? e.which : e.keyCode;

	var s="";
	passNextKeyPress=false;

	// Toggle english mode upon ctrl-space
	if(key==32 && (e.ctrlKey || e.metaKey)) {
		ckbEnglishMode.checked = !ckbEnglishMode.checked;
		cancelNextKeyPress = true;
		return false;		
	}

	// Toggle double width mode upon shift-space
	if(key==32 && e.shiftKey) {
		ckbDoubleWidthMode.checked = !ckbDoubleWidthMode.checked;
		cancelNextKeyPress = true;
		return false;
	}

	// let key events where control or metakey is pressed pass through
	if (e.ctrlKey || e.metaKey) {
		return true;
	}

	switch (key) {
		case 8: // Backspace
			// just pass it for now
			return true;
/*
			if (inpComposeInput.value!="") {
				s=inpComposeInput.value;
				s=s.substr(0, s.length-1);
				inpComposeInput.value=s;
				
				ProcessInput(s);

				//TODO: how to cancel a Backspace KeyDown in Opera 7.x?
				cancelNextKeyPress = true;
				return false;
			}
			else {
				ProcessInput(s);
				return true;
			}
 */
		case 9: // Tab
			// just pass it for now
			return true;
/*
			SendString('???');
			cancelNextKeyPress = true;
			return false; 
*/
		case 27: // Esc
			// just pass it for now
			return true;
/*
			inpComposeInput.value="";
			ClearCandidatesList();
			FetchCandidatesList();

			// cancel ESC, it could cause things to get deleted
			cancelNextKeyPress = true;
			return false;
*/
		case 32: // Space
			if (ckbDoubleWidthMode.checked) {
				// double width space
				SendString(String.fromCharCode(12288));
				return false;
			}
			return true;

		case 13: // Enter
			// just pass it for now
			return true;

		case 122: // F11
		case 57355: // F11 - Opera
			ckbDoubleWidthMode.checked = !ckbDoubleWidthMode.checked;
			cancelNextKeyPress = true;
			return false;

		case 123: // F12
		case 57356: // F12 - Opera
			ckbEnglishMode.checked = !ckbEnglishMode.checked;
			cancelNextKeyPress = true;
			return false;

		case 36: // home
		case 35: // end
		case 37: // left
		case 38: // up
		case 39: // right
		case 40: // down
		case 45: // insert
		case 46: // del
		case 91: // windows key
		case 112: // F1
		case 113: // F2
		case 114: // F3
		case 115: // F4
		case 116: // F5
		case 117: // F6
		case 118: // F7
		case 119: // F8
		case 120: // F9
		case 121: // F10
//		case 122: // F11
//		case 123: // F12
			// let these keys pass through unprocessed in the next keypress events
			passNextKeyPress = true;
			break;
	}

	return true;
}

// handle keypress events
function ImeKeyPress(e) {
	// get key code
	var key = e.which ? e.which : e.keyCode;

	// pass keypress without processing it
	if(passNextKeyPress) {
		return true;
	}

	// cancel keypress if 'cancelNextKeyPress' is set and browser is not IE (IE keys are cancelled in keydown)
	// Gecko can only cancel keys in OnKeyPress
	if (browser>1) {
		if (cancelNextKeyPress) {
			cancelNextKeyPress = false;
			return false;
		}
	}

	// let key events where control or metakey is pressed pass through
	if (e.ctrlKey || e.metaKey) {
		return true;
	}

	if (ckbDoubleWidthMode.checked) {
		if (key>=48 && key<=57) {
			// double width number
			SendString(txbInputArea, String.fromCharCode(key - 48 + 65296));
			return false;
		}
		else if (key==46) {
			// double width '.'
			SendString(txbInputArea, String.fromCharCode(12290));
			return false;
		}
		else if(key==96) {
			// double width '`'
			SendString(txbInputArea, String.fromCharCode(65344));
			return false;
		}
		else if ((key>=33 && key<=47) || (key>=58 && key<=63) || (key>=91 && key<=95) || (key>=123 && key<=126)) {
			// double width punctuation and marks
			SendString(txbInputArea, String.fromCharCode(key + 65248));
			return false;
		}
		else if ( key>=65 && key<=90 ) {
			// double width A-Z
			SendString(txbInputArea, String.fromCharCode(key + 65248));
			return false;
		}
		else if (key>=97 && key<=122) {
			// double width a-z
			SendString(txbInputArea, String.fromCharCode(key + 65248));
			return false;
		}
	}
	else
	{
		if (!ckbEnglishMode.checked) {
			if (key>=49 && key<=53) {
				// number 1-5
				var toneNumber = key - 48;
				
				var selectionPos = GetSelectionPos(txbInputArea);
				var selectionStart = selectionPos[0];
				var selectionEnd = selectionPos[1];
				if (selectionStart != selectionEnd) {
					// a selection was made, pass key trough
					return true;
				}

				var text = txbInputArea.value;

				var cursorPos = selectionStart;

				// trace back to first vowel
				var finalEndPos = cursorPos;
				var finalStartPos = cursorPos - 1;
				var vowelFound = false;
				while(finalStartPos >= 0) {
					var character = text.substr(finalStartPos,1);
					if(character.match(/[^a-züāáǎàōóǒòēéěèīíǐìūúŭùǖǘǚǜ]/i)) {
						vowelFound = false;
						break;
					}
					else if(character.match(/[āáǎàaōóǒòoēéěèeīíǐìiūúŭùuǖǘǚǜüv]/i)) {
						vowelFound = true;
						break;
					}
					finalStartPos--;
				}

				if(vowelFound) {
					// trace back to first non-vowel
					while(finalStartPos >= 0) {
						var character = text.substr(finalStartPos,1);
						if(character.match(/[^āáǎàaōóǒòoēéěèeīíǐìiūúŭùuǖǘǚǜüv]/i)) {
							break;
						}
						finalStartPos--;
					}
					finalStartPos++;

					var finalString = text.substring(finalStartPos,finalEndPos);
					finalString = finalString.replace('v','ü');
					finalString = finalString.replace('V','Ü');

					// neutralize all tones
					finalString = finalString.replace(/[āáǎà]/, 'a');
					finalString = finalString.replace(/[ōóǒò]/, 'o');
					finalString = finalString.replace(/[ēéěè]/, 'e');
					finalString = finalString.replace(/[īíǐì]/, 'i');
					finalString = finalString.replace(/[ūúŭù]/, 'u');
					finalString = finalString.replace(/[ǖǘǚǜ]/, 'ü');
					finalString = finalString.replace(/[ĀÁǍÀ]/, 'A');
					finalString = finalString.replace(/[ŌÓǑÒ]/, 'O');
					finalString = finalString.replace(/[ĒÉĚÈ]/, 'E');
					finalString = finalString.replace(/[ĪÍǏÌ]/, 'I');
					finalString = finalString.replace(/[ŪÚŬÙ]/, 'U');
					finalString = finalString.replace(/[ǕǗǙǛ]/, 'Ü');

					// add tone to final
					var matchResult = null;
					if(matchResult = finalString.match(/a/i)) {
						// has a ?
						finalString = finalString.replace(/a/i, toneMarksArray[matchResult[0]][toneNumber]);
					}
					else if(matchResult = finalString.match(/e/i)) {
						// has e ?
						finalString = finalString.replace(/e/i, toneMarksArray[matchResult[0]][toneNumber]);
					}
					else if(matchResult = finalString.match(/ou/i)) {
						// has ou ? on o
						finalString = finalString.replace(/ou/i, toneMarksArray[matchResult[0].substr(0,1)][toneNumber] + matchResult[0].substr(1,1));
					}
					else {
						// place mark on last vowel
						var characterPos = 0;
						var character = '';
						for(characterPos = finalString.length - 1 ; characterPos >= 0 ; characterPos--) {
							character = finalString.substr(characterPos,1);
							if(character.match(/[aeuiovü]/i)) {
								break;
							}
						}

						finalString = insertIntoString(finalString, toneMarksArray[character][toneNumber], characterPos, characterPos + 1);
					}

					// write string back
					SendString(txbInputArea, finalString, true);

					return false;
				}

				return true;
			}
		}
	}

	return true;
}

// handle keyup events
function ImeKeyUp(e) {
	passNextKeyPress=false;

//	// get key code
//	var key = e.which ? e.which : e.keyCode;

	return true;
}

// select all text in the textarea
function SelectAll() {
	switch(browser) {
		case 1:
			txbInputArea.select();
			txbInputArea.focus();
			// copy to clipboard, only works for IE
			window.clipboardData.setData('Text', txbInputArea.value);
			break;
		default:
			txbInputArea.select();
			txbInputArea.focus();
			break;
	}
}

// clear the textarea
function ClearAll() {
	txbInputArea.value='';
	focusInput();
}

// handle the body onload event
function BodyOnLoad() {
	if(navigator.userAgent.indexOf('AppleWebKit') != -1) {
		browser=4; // Safari
	}
	else if(navigator.userAgent.indexOf('Opera') != -1) {
		browser=3; // Opera
	}
	else if(navigator.userAgent.indexOf('Gecko') != -1) {
		browser=2; // Netscape
	}
	else if(navigator.userAgent.indexOf('MSIE') != -1) {
		browser=1; // IE
		// IE allows copy to clipboard, change button text:
		//document.getElementById("ButtonSelectAll").innerHTML="Select &amp; Copy";
	}
	else {
		browser=5; // Unknown browser, hope it 'just works???' ;)
	}
	//alert("here");
	// fetch HTML elements  
	txbInputArea = document.getElementById("b_search_field");
	ckbEnglishMode = document.getElementById("EnglishMode");
	ckbEnglishMode.onfocus = focusInput;
	ckbDoubleWidthMode = document.getElementById("DoubleWidth");
	ckbDoubleWidthMode.onfocus = focusInput;

	//top.resizeTo(initialWindowWidth,initialWindowHeight);

	// copy inital inputarea size from HTML
	initialInputAreaRows=1;//txbInputArea.rows;
	initialInputAreaCols=1;//txbInputArea.cols;

	// make sure the input area is focussed
	//focusInput();	
}

function focusInput() {
	txbInputArea.focus();
	GetSelectionPos(txbInputArea);
}

function changeSize(btn) {
	if(imeSize == 0) {
		imeSize = 1;
		top.resizeTo(largeWindowWidth,largeWindowHeight);
		txbInputArea.rows=18;
		txbInputArea.cols=73;
		btn.innerHTML = 'Small size';
	}
	else {
		imeSize = 0;
		top.resizeTo(initialWindowWidth,initialWindowHeight);
		txbInputArea.rows=initialInputAreaRows;
		txbInputArea.cols=initialInputAreaCols;
		btn.innerHTML = 'Large size';
	}
}


var is_gecko = /gecko/i.test(navigator.userAgent);
var is_ie    = /MSIE/.test(navigator.userAgent);

function setSelectionRange(input, start, end) {
	if (is_gecko) {
		input.setSelectionRange(start, end);
	} else {
		// assumed IE
		var range = input.createTextRange();
		range.collapse(true);
		range.moveStart("character", start);
		range.moveEnd("character", end - start);
		range.select();
	}
};

function getSelectionStart(input) {
	if (is_gecko)
		return input.selectionStart;
	var range = document.selection.createRange();
	var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0;
	if (!isCollapsed)
		range.collapse(true);
	var b = range.getBookmark();
	return b.charCodeAt(2) - 2;
};

function getSelectionEnd(input) {
	if (is_gecko)
		return input.selectionEnd;
	var range = document.selection.createRange();
	var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0;
	if (!isCollapsed)
		range.collapse(false);
	var b = range.getBookmark();
	return b.charCodeAt(2) - 2;
};