/*
# ------------------------------------------------------------------------
# JA Translate for joomla 1.5
# ------------------------------------------------------------------------
# Copyright (C) 2004-2010 JoomlArt.com. All Rights Reserved.
# @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
# Author: JoomlArt.com
# Websites: http://www.joomlart.com - http://www.joomlancers.com.
# ------------------------------------------------------------------------
*/
google.load("language", "1");

/* Cross-Browser Split 1.0.1
(c) Steven Levithan <stevenlevithan.com>; MIT License
An ECMA-compliant, uniform cross-browser split method */

var cbSplit;

// avoid running twice, which would break `cbSplit._nativeSplit`'s reference to the native `split`
if (!cbSplit) {

cbSplit = function (str, separator, limit) {
    // if `separator` is not a regex, use the native `split`
    if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
        return cbSplit._nativeSplit.call(str, separator, limit);
    }

    var output = [],
        lastLastIndex = 0,
        flags = (separator.ignoreCase ? "i" : "") +
                (separator.multiline  ? "m" : "") +
                (separator.sticky     ? "y" : ""),
        separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
        separator2, match, lastIndex, lastLength;

    str = str + ""; // type conversion
    if (!cbSplit._compliantExecNpcg) {
        separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
    }

    /* behavior for `limit`: if it's...
    - `undefined`: no limit.
    - `NaN` or zero: return an empty array.
    - a positive number: use `Math.floor(limit)`.
    - a negative number: no limit.
    - other: type-convert, then use the above rules. */
    if (limit === undefined || +limit < 0) {
        limit = Infinity;
    } else {
        limit = Math.floor(+limit);
        if (!limit) {
            return [];
        }
    }

    while (match = separator.exec(str)) {
        lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser

        if (lastIndex > lastLastIndex) {
            output.push(str.slice(lastLastIndex, match.index));

            // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
            if (!cbSplit._compliantExecNpcg && match.length > 1) {
                match[0].replace(separator2, function () {
                    for (var i = 1; i < arguments.length - 2; i++) {
                        if (arguments[i] === undefined) {
                            match[i] = undefined;
                        }
                    }
                });
            }

            if (match.length > 1 && match.index < str.length) {
                Array.prototype.push.apply(output, match.slice(1));
            }

            lastLength = match[0].length;
            lastLastIndex = lastIndex;

            if (output.length >= limit) {
                break;
            }
        }

        if (separator.lastIndex === match.index) {
            separator.lastIndex++; // avoid an infinite loop
        }
    }

    if (lastLastIndex === str.length) {
        if (lastLength || !separator.test("")) {
            output.push("");
        }
    } else {
        output.push(str.slice(lastLastIndex));
    }

    return output.length > limit ? output.slice(0, limit) : output;
};

cbSplit._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group
cbSplit._nativeSplit = String.prototype.split;

} // end `if (!cbSplit)`

// for convenience...
String.prototype.split = function (separator, limit) {
    return cbSplit(this, separator, limit);
};
/**
 * JAGoogleTranslate
 * Refer: http://code.google.com/apis/ajaxlanguage/documentation/reference.html
 */
JAGoogleTranslate = new Class({
	initialize: function (pageLanguage, autoDetect) {
		this.autoDetect = autoDetect;
		this.pageLanguage = pageLanguage;
		this.lang = pageLanguage;
		//google character limit
		this.limitChar = 800;
		
		this.segmentSeparator = '|$|';
		this.segmentSeparatorRegex = /\|\$\|/gi;
		 
		this.dTitle = 'ja-backup-title-';
		this.dContent = 'ja-translate-content-';
		this.dBackup = 'ja-translate-backup-';
		this.dLoading = 'ja-translate-loading-';
		this.dLanguages = 'ja-translate-languages-';
		this.openLang = true;
	},
	
	translateTitle: function(Id, toLang) {
		var contentId = this.dContent + Id;
		var backupTitle = this.dTitle + Id;
		
		
		var oldTitle = $(backupTitle).innerHTML;
		oldTitle = oldTitle.trim();
		
		google.language.translate(oldTitle, this.lang, toLang, function(result) {
			if (result.translation) {
				newTitle = result.translation;
				
				var aTitles = $$('.contentheading a');
				
				if(aTitles.length < 1) {
					aTitles = $$('.contentheading');
				}
				if(aTitles.length > 0) {
					//aTitles[Id].setHTML(title);
					for(var i=0; i< aTitles.length; i++) {
						if(aTitles[i].innerHTML.trim() == oldTitle || aTitles[i].getProperty('data-oldtitle') == oldTitle) {
							aTitles[i].setProperty('data-oldtitle', oldTitle);
							aTitles[i].innerHTML = newTitle;
						}
					}
				}
			}
		});
	},
	
	translate: function(Id, toLang) {
		this.toggleLanguages(Id);
		if(!google) {
			alert('Could not load data from google!.');
			return false;
		}
		
		
		this.showLoading(Id);
		
		var contentId = this.dContent + Id;
		var loadingId = this.dLoading + Id;
		var backupId = this.dBackup + Id;
		
		var content = this.getContent(Id);
		
		if(this.lang == 'la' || this.lang == '') {
			alert('Invalid translation language pair. Please make sure your article is written in valid language.');
			return false;
		}
		//alert(content);
		if(this.lang == toLang) {
			this.applyTranslate(Id, content);
							
			//update title
			this.translateTitle(Id, toLang);
			//hide loading			
			this.hideLoading(Id);
			
			this.markActive(Id, toLang);
		} else {
			
			var nodes = content.split(this.segmentSeparatorRegex);
			var checkIntegrity = 0;
			var translateFail = 0;
			var numPart = nodes.length;
			var aResponse = new Array();
			
			var oTrans = new JAGoogleTranslate('en', 1);
			
			for(i=0; i<numPart; i++) {
				if(this.trim(nodes[i]) == '') {
					checkIntegrity++;
				}
			}
			
			for(i=0; i<numPart; i++) {
				if(translateFail) break; //one or more part can not translate
				
				aResponse[i] = nodes[i];
				
				if(this.trim(nodes[i]) != '') {
					var request = i + ' ' + nodes[i];
					
					google.language.translate(request, this.lang, toLang, function(result) {
						if (result.translation) {
							checkIntegrity++;
							
							//
							var trans = result.translation;
							var no = trans.replace(/.*?([0-9]+)[\s\S]*/gi, '$1');
							no = no.toInt();
							
							var sCut = no + '';
							var newString = oTrans.convertEntities(trans.substr(sCut.length, trans.length - sCut.length));
							if(newString != '') {
								aResponse[no] = newString;
							}
							
							if(checkIntegrity == numPart) {
								
								sResponse = aResponse.join(oTrans.segmentSeparator);
								
								//prompt('test', sResponse);
								oTrans.applyTranslate(Id, sResponse);
								//update title
								oTrans.translateTitle(Id, toLang);
								//hide loading
								$(loadingId).setStyles({'display': 'none'});
								
								oTrans.markActive(Id, toLang);
							}
							
						} else {
							if(!translateFail) {
								translateFail = 1;
								alert('Sorry, The article can not be properly tranlated to selected language.');
								return false;
							}
						}
					});
				}
			}
		}
		
		return false;
	},
	
	markActive: function(Id, language) {
		var popupId = 'ja-translate-languages-'+Id;
		$$('#'+popupId+' div.languages a').removeClass('active');
		$('ja-lang-'+Id+'-'+language).addClass('active');
	},
	
	applyTranslate: function(Id, languages) {
		var contentId = this.dContent + Id;
		
		//hack for IE8, since split work incorrectly
		languages = ' ' + languages;
		
		var orgnode = $(contentId);
		var nodes = languages.split(this.segmentSeparatorRegex);
		var skip = false;
		var node = orgnode;
		var index = 0;
		
		if(!node) {
			return false;
		}
		do {
			if (node.nodeType == 3) {
				//text node & not empty node
				//Fix bug for IE8
				if(this.trim(node.nodeValue) != '' && this.trim(nodes[index]) != '') {
					//prompt('test', index + '\r\n' + node.nodeValue + '\r\n' + nodes[index]);
					node.nodeValue = nodes[index];
				}
				index++;
			}
			
			//scan to childNode if it is not scanned
			if (!skip && node.firstChild) {
				var nodeName = node.nodeName.toLowerCase();
				if(nodeName != 'script' && nodeName != 'pre' && nodeName != 'code' && node.id != 'jac-wrapper') {
					node = node.firstChild;
				} else {
					skip = true;
				}
			} else if (node.nextSibling) {
				//scan next node
				node = node.nextSibling;
				skip = false;
			} else {
				//scan up
				node = node.parentNode;
				skip = true;
			}
		} while (node && node != orgnode);
	},
	
	/**
	 * Get safe position to cut content that don't make break tags and sentence
	 */
	getSafePos: function(content, begin, limit) {
		var end = begin + limit;
		var len = content.length;
		
		if(len > end) {
			var lastestClose = content.lastIndexOf(this.segmentSeparator, end);
			lastestClose -= 1;
			//fix break sentence
			var lastPoint = content.lastIndexOf('.', end);
			if((lastPoint > -1) && (lastestClose < lastPoint)) {
				end = lastPoint;
			}
		} else {
			end = len;
		}
		
		return end;
	},
	
	getContent: function(Id) {
		var backupId = this.dBackup + Id;
		var contentId = this.dContent + Id;
		
		this.lang = this.pageLanguage;
		
		if($(backupId).getProperty('rel') == 'saved') {
			if(this.autoDetect) {
				var lang = $(backupId).getProperty('lang');
				if(lang != '' && lang != null) {
					this.lang = lang;
				}
			}
			
			return $(backupId).innerHTML;
		}
		
		//for the first translate
		//save original content
		//detect language
		
		var orgnode = $(contentId);
		var nodes = new Array();
		var skip = false;
		var node = orgnode;
		
		if(!node) {
			return false;
		}
		do {
			//if (node.nodeType == 3 && node.data.trim() != '') {
			if (node.nodeType == 3) {
				//get all node (include empty node) to make sure DOM structure is always kept in right
				nodes.push(node);
			}
			
			//scan to childNode if it is not scanned
			if (!skip && node.firstChild) {
				var nodeName = node.nodeName.toLowerCase();
				if(nodeName != 'script' && nodeName != 'pre' && nodeName != 'code' && node.id != 'jac-wrapper') {
					node = node.firstChild;
				} else {
					skip = true;
				}
			} else if (node.nextSibling) {
				//scan next node
				node = node.nextSibling;
				skip = false;
			} else {
				//scan up
				node = node.parentNode;
				skip = true;
			}
		} while (node && node != orgnode);
		
		//test - add [] to all text
		var txt = '';
		for(var i=0;i<nodes.length;i++) {
			//nodes[i].data = '[' + nodes[i].data + ']';
			var nodeData = nodes[i].data.replace(/\r*\n/gi, '');
			txt += nodeData + this.segmentSeparator;
		}
		//txt += 'jatransend';
		
		//save original content
		$(backupId).innerHTML = txt;
		if(this.autoDetect) {
			this.detectLanguage(Id);
		}
		$(backupId).setProperty('rel', 'saved');
		//
		return txt;
	},
	
	detectLanguage: function(Id) {
		var backupId = this.dBackup + Id;
		var langPrefix = 'ja-lang-' + Id;
		var content = $(backupId).innerHTML;
		var len = content.length;
		var start = 0;
		
		var end = this.getSafePos(content, start, 500);
		if(end > len) {
			end = len;
		}
		limit = end - start;
		var text = content.substr(start, limit);
		
		google.language.detect(text, function(result) {
			if (!result.error) {
				var langCode = result.language;
				if(langCode == 'la' || langCode == '') langCode = 'en';
				$(backupId).setProperty('lang', langCode);
				
				if($(langPrefix + '-' +langCode)) {
					//markup on languages list
					$(langPrefix + '-' +langCode).addClass('original');
				}
			}
		});
	},
	
	showLoading: function(Id) {
		$(this.dLoading + Id).setStyles({'display': 'block'});
	},
	
	hideLoading: function(Id) {
		$(this.dLoading + Id).setStyles({'display': 'none'});
	},
	
	toggleLanguages: function(Id) {
		var popupId = 'ja-translate-popup';
		var display = $(popupId).getStyle('display');
		var curId = $(popupId).getProperty('rel');
		
		//save content of other block
		if(curId != '' && curId != null && curId != Id && display == 'block') {
			this.savePopupContent(curId);
			display = 'none';
		}
		
		if(display == 'none') {
			var aParam = $('ja-translate-' + Id).getCoordinates();
			
			var styles = {'display': 'block', 'top': aParam.top + 20, 'left': aParam.left};
		
			$(popupId).setStyles(styles);
			$(popupId).setProperty('rel', Id)
			var aContent = $$('#ja-translate-languages-' + Id + ' div.languages');
			aContent[0].inject(popupId);
		} else {
			$(popupId).setStyle('display', 'none');
			$(popupId).setProperty('rel', '');
			this.savePopupContent(Id);
		}
		
		return false;
	},
	
	savePopupContent: function(Id) {
		var popupId = 'ja-translate-popup';
		var aContent = $$('#' + popupId + ' div.languages');
		if(aContent.length > 0) {
			for(var i=0; i< aContent.length; i++) {
				aContent[i].inject('ja-translate-languages-' + Id);
			}
		}
	},
	
	convertEntities: function( text )  {
		var matches = text.match( /\&\#(\d+);/g );
		if(matches) {
			for ( var i = 0; i < matches.length; i++ ) { 
				//console.log( "Replacing: " + matches[i] ); 
				//console.log( "With: " + this.convertEntity( matches[i] ) ); 
				text = text.replace( matches[i], this.convertEntity( matches[i] ) ); 
			} 
		}
		
		return text; 
	},
	
	convertEntity: function( ent ) { 
		var num = parseInt(ent.replace(/\D/g, ''), 16); 
		var esc = ((num < 16) ? '0' : '') + num.toString(16); 
		return String.fromCharCode( esc ); 
	},
	
	fixSpecialChars: function(txt) {
		text = text.replace(/\&amp\;([a-z]{2,3})\;/gi, '&$1;');
		return text;
	},
	
	trim: function(txt) {
		txt = txt.replace(/^[\s\r\n]+/g, '');
		txt = txt.replace(/[\s\r\n]+$/g, '');
		return txt;
	}
});
