/***************************************************************************
 *   Copyright (C) 2005 by Christof Donat   *
 *   cdonat@gmx.de   *
 *                                                                         *
 *   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 2 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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "xmlparser.h"
#include "logger.h"

namespace xmlParser {

bool parser::operator()(const string& content, int &pos, responseParserHook *hook) { return false; }

bool spaceParser::operator()(const string& content, int &pos, responseParserHook *hook) { 
	if( content[pos] == ' ' || content[pos] == '\t' || content[pos] == '\n' || content[pos] == '\r' ) {
		pos++; return true;
	}
	return false;
}

bool commentParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content.substr(pos,4) == "<!--" ) {
		pos+= 4;
		while( content.substr(pos,3) != "-->" && pos < content.length() ) pos++;
		if(pos < content.length()) {
			pos += 3; return (*hook)(8,content.substr(oldpos+4,(pos-oldpos)-7));
		}
		pos = oldpos;
		return false;
	}
	return false;
}

bool nameParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( !( (content[pos] >= '0' && content[pos] <= '9' ) || 
	       (content[pos] >= 'a' && content[pos] <= 'z' ) ||
	       (content[pos] >= 'A' && content[pos] <= 'Z' ) ||
	        content[pos] == '.' || 
	        content[pos] == ':' || 
	        content[pos] == '_' ) )
		return false;
	while( (content[pos] >= '0' && content[pos] <= '9' ) || 
	       (content[pos] >= 'a' && content[pos] <= 'z' ) ||
	       (content[pos] >= 'A' && content[pos] <= 'Z' ) ||
	        content[pos] == '.' || 
	        content[pos] == ':' || 
	        content[pos] == '_' ) pos++;
	return true;
}

bool attributeValueParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content[pos] == '"' ) {
		pos++;
		while( content[pos] != '"' && pos < content.length() ) pos++;
		if( pos >= content.length() ) { pos = oldpos; return false; }
		pos++;
	}
	else if( content[pos] == '\'' ) {
		pos++;
		while( content[pos] != '\'' && pos < content.length() ) pos++;
		if( pos >= content.length() ) { pos = oldpos; return false; }
		pos++;
	} else {
		pos = oldpos;
		return false;
	}
	return (*hook)(32,content.substr(oldpos+1,(pos-oldpos)-2));
}

bool attributeParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( ! space(content,pos,hook) ) return false;
	while(space(content,pos,hook) && pos < content.length() );
	int namestartpos = pos;
	if( ! name(content,pos,hook) ) { pos = oldpos; return false; }
	int nameendpos = pos;
	if( content[pos] != '=' ) { pos = oldpos; return false; }
	pos++;
	if( ! value(content,pos,hook) ) { pos = oldpos; return false; }
	return (*hook)(2,content.substr(oldpos+1,(nameendpos-oldpos)-1));
};

bool emptyelemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content[pos] != '<' ) return false;
	pos++;
	if( !name(content,pos,hook) ) { pos = oldpos; return false; }
	int nameendpos = pos;
	
	while(attrib(content,pos,hook) && pos < content.length() );
	while(space(content,pos,hook) && pos < content.length() );
		if( content.substr(pos,2) != "/>" ) { pos = oldpos; return false; }
	pos += 2;
	return (*hook)(18,content.substr(oldpos+1,(nameendpos-oldpos)-1));
}

bool startelemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content[pos] != '<' ) return false;
	pos++;
	if( !name(content,pos,hook) ) { pos = oldpos; return false; }
	int nameendpos = pos;
	
	while(attrib(content,pos,hook) && pos < content.length() );
	while(space(content,pos,hook) && pos < content.length() );
		if( content[pos] != '>' ) { pos = oldpos; return false; }
	pos ++;

	return (*hook)(16,content.substr(oldpos+1,(nameendpos-oldpos)-1));
}

bool endelemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content.substr(pos,2) != "</" ) return false;
	pos += 2;
	if( !name(content,pos,hook) ) { pos = oldpos; return false; }
	int nameendpos = pos;
	
	while(space(content,pos,hook) && pos < content.length() );
		if( content[pos] != '>' ) { pos = oldpos; return false; }
	pos ++;

	return (*hook)(17,content.substr(oldpos+2,(nameendpos-oldpos)-2));
}

bool textParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content[pos] == '<' )
		return false;
	while( content[pos] != '<' && pos < content.length() ) pos++;
	return (*hook)(3,content.substr(oldpos,pos-oldpos));
};

bool cdataParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content.substr(pos,9) != "<![CDATA[" ) return false;
	bool foundend = false;
	while( !( foundend = (content.substr(pos,3) == "]]>") ) && pos < content.length() ) pos++;
	if( !foundend ) { pos = oldpos; return false; }
	pos += 3;
	return (*hook)(4,content.substr(oldpos+9,(pos-oldpos)-12));
};

bool elemParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( emptyelem(content,pos,hook) ) return (*hook)(1,content.substr(oldpos,pos-oldpos));
	if( ! elemstart(content,pos,hook) ) return false;
	
	bool foundend = false;
	while( !(foundend = endelem(content,pos,hook)) && pos < content.length() ) {
		if( ! ( comspace(content,pos,hook) ||
			text(content,pos,hook)     ||
			(*this)(content,pos,hook)  ||
			cdata(content,pos,hook)      ) ) {
				pos = oldpos;
				return false;
		}
	}
	if( foundend ) return (*hook)(1,content.substr(oldpos,pos-oldpos));
	return false;
}

bool xmlpcParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	if( content.substr(pos,5) != "<?xml" ) return false;
	pos += 5;

	while(attrib(content,pos,hook) && pos < content.length() );
	while(space(content,pos,hook) && pos < content.length() );
	if( content.substr(pos,2) != "?>" ) { pos = oldpos; return false; }
	pos += 2;
	return (*hook)(7,string("xml"));
}

bool XMLParser::operator()(const string& content, int &pos, responseParserHook *hook) {
	int oldpos = pos;
	while(space(content,pos,hook) && pos < content.length() );
	if( ! xmlpc(content,pos,hook) ) { pos = oldpos; return false; }
	while(comspace(content,pos,hook) && pos < content.length() );
	if( ! elem(content,pos,hook) ) { pos = oldpos; return false; }
	while(comspace(content,pos,hook) && pos < content.length() );
	return (*hook)(9,content.substr(oldpos,pos-oldpos));
}

bool ResponseParser::operator()(const string& content, responseParserHook *hook) { 
	int pos = 0; 
	bool rval = xml(content,pos,hook);
	if( pos < content.length() ) return false;
	return rval;
}

}
