
/*
	This is DirectionDetector, a jquery plugin for setting direction of
	RTL languages

	Copyright (c) 2009 behrooz shabani <behrooz@rock.com>

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

(function($){
	var __ignore_chars = false; // mean all characters are valid
	var __isRTL = function(str){
		if(typeof str != typeof "" || str.length<1)
			return false;
		var cc = str.charCodeAt(0);
		if(cc>=1536 && cc<=1791) // arabic, persian, ...
			return true;
		if(cc>=65136 && cc<=65279) // arabic peresent 2
			return true;
		if(cc>=64336 && cc<=65023) // arabic peresent 1
			return true;
		if(cc>=1424 && cc<=1535) // hebrew
			return true;
		if(cc>=64256 && cc<=64335) // hebrew peresent
			return true;
		if(cc>=1792 && cc<=1871) // Syriac
			return true;
		if(cc>=1920 && cc<=1983) // Thaana
			return true;
		if(cc>=1984 && cc<=2047) // NKo
			return true;
		if(cc>=11568 && cc<=11647) // Tifinagh
			return true;
		return false;
	};
	var __fisrt_child = function(par){
		var res=par.firstChild;
		while (res) {
			if (!__is_ignorable(res))
				return res;
			res = res.nextSibling;
		}
		return null;
	};
	var __is_ignorable = function(nod){
		return ( nod.nodeType != 1 && nod.nodeType != 3 ) || // none text or element
			((nod.nodeType == 3) && __is_all_ws(nod) ) || // a text node, all ws
			((nod.nodeType == 3) && __is_all_ignore_chars(nod) ); // a text node, all ignore characters
	};
	var __is_all_ws = function(nod){
		return !(/[^\t\n\r ]/.test(nod.data));
	};
	var __is_all_ignore_chars = function(node){
		if(__ignore_chars==false)
			return false;
		return __ignore_chars.test(node.data);
	};
	var __node_after = function(sib){
		while ((sib = sib.nextSibling))
			if(!__is_ignorable(sib) && !__is_all_ignore_chars(sib))
				return sib;
		return null;
	};
	var __firstData = function(p, n){
		var fc = __fisrt_child(p);
		if(fc && fc.nodeType==3)
			return fc;
		while(fc!=null){
			var fcc = false;
			if(fc && n && fc.nodeType==1 && fc.hasChildNodes())
				fcc = __firstData(fc, true);
			if(fcc && fcc.nodeType == 3)
				return fcc;
			if(fc && fc.nodeType==3)
				return fc;
			fc = __node_after(fc);
		}
		return false;
	};
	var __node_before = function(sib){
		while ((sib = sib.previousSibling))
			if (!__is_ignorable(sib) && !__is_all_ignore_chars(sib))
				return sib;
		return null;
	};
	var __last_child = function(par){
		var res=par.lastChild;
		while (res){
			if(!__is_ignorable(res))
				return res;
			res = res.previousSibling;
		}
		return null;
	};
	var __lastData = function(p, n){
		var fc = __last_child(p);
		if(fc && fc.nodeType==3)
			return fc;
		while(fc!=null){
			var fcc = false;
			if(fc && n && fc.nodeType==1 && fc.hasChildNodes())
				fcc = __lastData(fc, true);
			if(fcc && fcc.nodeType == 3)
				return fcc;
			if(fc && fc.nodeType==3)
				return fc;
			fc = __node_before(fc);
		}
		return false;
	};
	var __data_of = function(txt){
		if(!txt)
			return "";
		var data = txt.data;
		// Use ECMA-262 Edition 3 String and RegExp features
		data = data.replace(/[\t\n\r ]+/g, " ");
		if(__ignore_chars != false)
			data = data.replace(__remove_chars, "");// remove ignored characters from start
		if (data.charAt(0) == " ")
			data = data.substring(1, data.length);
		if (data.charAt(data.length - 1) == " ")
			data = data.substring(0, data.length - 1);
		return data;
	};
	$.fn.setDirections = function(op, fromEnd, nestedCheck, ignoreChars){
		if(typeof nestedCheck != typeof true) // if we don't have a boolean type
			nestedCheck = true;
		if(typeof ignoreChars == typeof ''){ // set it if it's a string
			var xFind = ["\\", "[", "]", "{", "}", "\n", "\t", "\r"]; // replace usable characters in RegExp
			var xReplace = ["\\\\", '\\[', '\\]', '\\{', '\\}', '\\n', '\\t', '\\r'];
			for(var i=0; i<xReplace.length; i++)
				ignoreChars = ignoreChars.replace(xFind[i], xReplace[i]);
			__ignore_chars = new RegExp('^['+ignoreChars+']+$', 'g'); // all ignore chars
			__remove_chars = new RegExp('^['+ignoreChars+']+', 'g'); // remove chars
		} else
			__ignore_chars = false;
		return this.each(
			function(){
				if(this.tagName.toLowerCase()=='textarea' || this.tagName.toLowerCase()=='input' && this.getAttribute('type') && this.getAttribute('type').toLowerCase()=='text')
					xStr = __ignore_chars==false?$(this).val():$(this).val().replace(__remove_chars, '');
				else {
					if(fromEnd == true)
						var xStr = __data_of(__lastData(this, nestedCheck));
					else
						var xStr = __data_of(__firstData(this, nestedCheck));
				}
				if(typeof op == typeof function(){})
					op(this, __isRTL(xStr), xStr);
				else if(__isRTL(xStr)){
					if(typeof op == typeof "")
						$(this).addClass(op);
					else if(typeof op == typeof {})
						$(this).css(op);
					else
						this.setAttribute("dir", "rtl");
				}
			}
		);
	};
	$.fn.isRTL = function(str){
		return __isRTL(str);
	};
})(jQuery);


