var XML_TAG_UPPER = 0;
var XML_TAG_LOWER = 1;
var XML_TAG_MIXED = 2;

function XMLIterator(xmlObj) {
	this.xmlObj = xmlObj;
	this.currentSection = xmlObj;
	this.currentSectionName = 'root';
	this.traceMode = false;
	
	this.navigatorStarted = false;
	this.navigatorSection = '';
	this.navigatorField   = '';
	this.navigatorBof     = true;
	this.navigatorEof     = true;
	this.navigatorCurrent = -1;
	this.navigatorEmpty   = true;
	
	this.ErroSecaoInexistente = new Error('A seção informada não é valida.');
	this.ErroNavigatorNotStarted = new Error('O navegador nao foi inicializado.');

	if (this.traceMode)
		this.traceDiv = document.getElementById('trace');
	else 
		this.traceDiv = null;

	if(this.traceMode) this.__trace('criando objeto iterator...');
}

XMLIterator.prototype.getMetadata = function (){
	var nodo = this.xmlObj.getElementsByTagName('metadata')[0].firstChild;
	var aMetadata = new Array();

	if (nodo != null){
		do{
			aMetadata[nodo.nodeName] = this.processaNodo(nodo);
			nodo = nodo.nextSibling;
		} while (nodo != null);
	}

	return aMetadata;
}

XMLIterator.prototype.getData = function (){
	var nodo;
	var aData = new Array();

	if (this.xmlObj.getElementsByTagName('data'))
		nodo = this.xmlObj.getElementsByTagName('data')[0].firstChild;

	if (nodo != null){
		do{
			aData[nodo.nodeName] = this.processaNodo(nodo);
			nodo = nodo.nextSibling;
		} while (nodo != null);
	}

	return aData;
}

XMLIterator.prototype.processaResultset = function(rs){
	var obj = new Array();
	var fld;
	var row;

	row = rs.firstChild;
	
	var ct = 0;
	if (row != null){
		do {
			obj[ct] = new Array();
			fld = row.firstChild;
			if (fld != null){
				do{
				    var valor = "";
				    try{
				        valor = fld.firstChild.nodeValue;
				    }catch(ee){}
					obj[ct][fld.nodeName] = valor;
					fld = fld.nextSibling;
				} while (fld != null);
			}
			row = row.nextSibling;
			ct++;
		} while (row != null);
	}
	return obj;
}

XMLIterator.prototype.processaObjeto = function(rs){
	var obj = new Array();

	obj['classe'      ] = rs.getElementsByTagName('classe')[0].firstChild.nodeValue;
	obj['metodos'     ] = this.processaArray(rs.getElementsByTagName('metodos')[0]);
	obj['propriedades'] = this.processaStruct(rs.getElementsByTagName('propriedades')[0]);

	return obj;
}

XMLIterator.prototype.processaArray = function(arr){
	var obj = new Array();
	var ct = 0;
	var nodo = arr.firstChild;

	if (nodo != null){
		do {
			obj[ct] = this.processaNodo(nodo);
			nodo = nodo.nextSibling;
			ct++;
		} while (nodo != null);
	}

	return obj;
}

XMLIterator.prototype.processaStruct = function(arr){
	var obj = new Array();
	var nodo = arr.firstChild;

	if (nodo != null){
		do {
			obj[nodo.nodeName] = this.processaNodo(nodo);
			nodo = nodo.nextSibling;
		} while (nodo != null);
	}
	return obj;
}

XMLIterator.prototype.processaNodo = function(nodo){

	if (nodo.nodeType == 3 ){
		return nodo.nodeValue;
	} else {
		if (nodo.attributes.length == 0){
			if (nodo.childNodes.length == 0){
				val = null;
			} else {
				val = nodo.firstChild.nodeValue;
			}
			return val;
		} else {
			var tipo = nodo.attributes.getNamedItem('type').nodeValue;

			if (tipo == 'resultset'){
				return this.processaResultset(nodo);
			} else if (tipo == 'object'){
				return this.processaObjeto(nodo);
			} else if (tipo == 'array'){
				return this.processaArray(nodo);
			} else if (tipo == 'struct'){
				return this.processaStruct(nodo);
			}
		}
	}
}

XMLIterator.prototype.selectSection = function (sName){
	section = this.xmlObj.getElementsByTagName(sName);

	if (section.length > 0){
		this.currentSection = section;
		this.currentSectionName = sName;
		if(this.traceMode) this.__trace('selecionando secao: '+sName);
	} else {
		throw this.ErroSecaoInexistente;
		if(this.traceMode) this.__trace('secao invalida: '+sName);
	}
}

XMLIterator.prototype.getSectionLength = function (sName){
	if (sName != null){
		this.selectSection(sName);
	}
	szSection = this.currentSection[0].childNodes.length;

	if(this.traceMode) this.__trace('buscando o tamanho da secao '+(sName==undefined?this.currentSectionName:sName)+', o tamanho é '+szSection);
	return szSection;
}

XMLIterator.prototype.getSectionAttribute = function (sName, aName){
	section = this.xmlObj.getElementsByTagName(sName);

	if (section.length > 0){
		val = section[0].attributes.getNamedItem(aName);
		if (val == null){
			if(this.traceMode) this.__trace('pegando o atributo '+aName+' da secao '+sName+' nao encontrado.');
		} else {
			if(this.traceMode) this.__trace('pegando o atributo '+aName+' da secao '+sName+', o valor eh '+val.nodeValue);
		}
		return val;
	} else {
		throw this.ErroSecaoInexistente;
		if(this.traceMode) this.__trace('secao invalida: '+sName);
	}
}

XMLIterator.prototype.getSectionAttributes = function (sName){
	section = this.xmlObj.getElementsByTagName(sName);

	if (section.length > 0){
		oAtribs = new Object();
		for (var i=0; i<section[0].attributes.length; i++){
			oAtribs[section[0].attributes[i].nodeName] = section[0].attributes[i].nodeValue;
		}
		if(this.traceMode) this.__trace('pegando os atributos da secao '+sName);

		return oAtribs;

	} else {
		throw this.ErroSecaoInexistente;
		if(this.traceMode) this.__trace('secao invalida: '+sName);
	}
}

XMLIterator.prototype.getSectionFieldValue = function (fName, sName){
	if (sName == null){
		section = this.currentSection;
	} else {
		section = this.xmlObj.getElementsByTagName(sName);
	}
	fld = section[0].getElementsByTagName(fName);
	
	try {
		val = fld[0].childNodes[0].nodeValue;
	} catch (e){
		val = '';
	}

	if(this.traceMode) this.__trace('buscando valor do campo '+fName+', valor encontrado: '+val);

	return val;
}

XMLIterator.prototype.getSectionFieldAttribute = function (fName, aName, sName){
	if (sName == null){
		section = this.currentSection;
	} else {
		section = this.xmlObj.getElementsByTagName(sName);
	}
	fld = section[0].getElementsByTagName(fName);
	val = fld[0].attributes.getNamedItem(aName).nodeValue;

	if(this.traceMode) this.__trace('buscando atributo '+aName+' do campo '+fName+', valor encontrado: '+val);

	return val;
}

XMLIterator.prototype.getErrorCode = function (){
	section = this.xmlObj.getElementsByTagName('metadata');
	
	try {
		errorcode = section[0].getElementsByTagName('errorcode')[0].childNodes[0].nodeValue;
	} catch (e) {
		errorcode = 0;
	}

	return errorcode;
}

XMLIterator.prototype.getErrorMsg = function (){
	section = this.xmlObj.getElementsByTagName('metadata');

	try {
		errormsg = section[0].getElementsByTagName('errormsg')[0].childNodes[0].nodeValue;
	} catch (e) {
		errormsg = '';
	}

	return errormsg;
}

/* Navegacao */
XMLIterator.prototype.startNavigator = function (sName, rName){
	this.navigatorSection = this.xmlObj.getElementsByTagName(sName);
	this.navigatorField   = rName;

	if (this.navigatorSection[0].childNodes.length == 0) {
		this.navigatorBof     = true;
		this.navigatorEof     = true;
		this.navigatorCurrent = -1;
		this.navigatorEmpty   = true;
	} else {
		this.navigatorBof     = false;
		this.navigatorEof     = false;
		this.navigatorCurrent = 0;
		this.navigatorEmpty   = false;
	}

	this.navigatorStarted = true;
}

XMLIterator.prototype.isNavigatorEmpty = function (){
	return this.navigatorEmpty;
}

XMLIterator.prototype.fieldValue = function (fName){
	if (this.navigatorStarted && !this.navigatorEof && !this.navigatorBof){
		curFld = this.__getCurFld(fName);

		try {
			val = curFld[0].childNodes[0].nodeValue;
		} catch (e) {
			val = ' ';
		}

		return val;

	} else {
		if (!this.navigatorStarted){
			throw this.ErroNavigatorNotStarted;
		}
	}
}

XMLIterator.prototype.fieldAttribute = function (fName, aName){
	if (this.navigatorStarted && !(this.navigatorEof && this.navigatorBof)){
		curFld = this.__getCurFld(fName);
		val    = curFld[0].attributes.getNamedItem(aName).nodeValue;

		return val;

	} else {
		if (!this.navigatorStarted){
			throw this.ErroNavigatorNotStarted;
		}
	}
}

XMLIterator.prototype.rowAttribute = function (aName){

	if (this.navigatorStarted && !(this.navigatorEof && this.navigatorBof)){
		curRow = this.__getCurRow();
		val    = curRow.attributes.getNamedItem(aName).nodeValue;

		return val;

	} else {
		if (!this.navigatorStarted){
			throw this.ErroNavigatorNotStarted;
		}
	}
}

XMLIterator.prototype.next = function (){
	if (this.navigatorStarted){
		if(!this.navigatorEof){
			this.navigatorCurrent++;
			this.navigatorEof = (this.navigatorCurrent >= this.navigatorSection[0].childNodes.length);
			this.navigatorBof = !(this.navigatorCurrent >= 0);
		}
	} else {
		throw this.ErroNavigatorNotStarted;
	}
}

XMLIterator.prototype.prev = function (){
	if (this.navigatorStarted){
		if(!this.navigatorBof){
			this.navigatorCurrent--;
			this.navigatorBof = (this.navigatorCurrent < 0);
		}
	} else {
		throw this.ErroNavigatorNotStarted;
	}
}

XMLIterator.prototype.reset = function (){
	if (this.navigatorStarted){
		this.navigatorCurrent = 0;
		this.navigatorBof     = false;
		this.navigatorEof     = false;
	} else {
		throw this.ErroNavigatorNotStarted;
	}
}

XMLIterator.prototype.eof = function (){
	if (this.navigatorStarted){
		return this.navigatorEof;
	} else {
		throw this.ErroNavigatorNotStarted;
	}
}

XMLIterator.prototype.bof = function (){
	if (this.navigatorStarted){
		return this.navigatorBof;
	} else {
		throw this.ErroNavigatorNotStarted;
	}
}

XMLIterator.prototype.__getCurRow = function (){
	return this.navigatorSection[0].childNodes[this.navigatorCurrent];
}

XMLIterator.prototype.__getCurFld = function (fName){
	row = this.__getCurRow();
	if (row != null){
		return row.getElementsByTagName(fName);
	} else {
		return null;
	}
}

XMLIterator.prototype.__trace = function (msg){
	if(this.traceDiv != null){
		this.traceDiv.innerHTML += msg+'<br />';
	}
}