//parse a config file and generate a Renderer
Renderer* ConfigParser::parse(std::string filename){
	
	std::cout << "ConfigParser::parse config file... " << filename <<" \n";

	struct basicxmlnode * rootNode = NULL;

	//open file
	FILE * fp = fopen(filename.c_str(), "rt");
	if (!fp) {
		std::cerr << "ConfigParser - Error: Failed opening file " << filename << "\n";
		return NULL;
	}

	rootNode = readbasicxmlnode(fp);
	fclose(fp);
	if (!rootNode) {
		std::cerr << "ConfigParser - Error: Failed reading file " << filename << ". Maybe an XML syntax error?\n";
		return NULL;
	}

	//create renderer
	Renderer* renderer = new Renderer();

	//read renderer properties
	if (!addRendererProperties(rootNode, renderer)) {
		std::cerr << "ConfigParser - Error: Failed reading renderer properties in " << filename << "\n";
		deletebasicxmlnode(rootNode);
		delete(renderer);
		return NULL;
	}

	//read sampler
	struct basicxmlnode * samplerNode = getchildnodebyname(rootNode, "Sampler");
	if (!addSampler(samplerNode, renderer)) {
		std::cerr << "ConfigParser - Error: Failed reading sampler description in " << filename << "\n";
		deletebasicxmlnode(rootNode);
		delete(renderer);
		return NULL;
	}
	
	//read shader
	struct basicxmlnode * shaderNode = getchildnodebyname(rootNode, "Shader");
	if (!addShader(shaderNode, renderer)) {
		std::cerr << "ConfigParser - Error: Failed reading shader description in " << filename << "\n";
		deletebasicxmlnode(rootNode);
		delete(renderer);
		return NULL;
	}

	//free xml memory
	deletebasicxmlnode(rootNode);

	std::cout << "[done]\n\n";

	return renderer;
}
void Population::LoadConfigFile(char* iniFile)
{
	// Loads the data file population information
	_rootConfig = NULL;
	FILE * fp = fopen(iniFile, "rt");
	if (!fp) { throw("open failed"); }
	_rootConfig = readbasicxmlnode(fp);
	fclose(fp);
	if (!_rootConfig) { throw("read failed"); }
}
//parse a scene description file and generate a Scene
Scene* SceneParser::parse(const char* filename){
	std::cout << "SceneParser::parse parses scene... " << filename <<" \n";

	struct basicxmlnode * rootNode = NULL;

	//open file
	FILE * fp = fopen(filename, "rt");
	if (!fp) {
		std::cerr << "SceneParser - Error: Failed opening file " << filename << "\n";
		return NULL;
	}

  std::string filenameString = std::string(filename);
  size_t index = filenameString.find_last_of("/");
  if (index == std::string::npos) {
    index = filenameString.find_last_of("\\");
  }

  if (index == std::string::npos) {
    directory = "";
  }
  else {
    directory = filenameString.substr(0,index+1);
  }

	//read xml tree
	rootNode = readbasicxmlnode(fp);
	fclose(fp);
	if (!rootNode) {
		std::cerr << "SceneParser - Error: Failed reading file " << filename << ". Maybe an XML syntax error?\n";
		return NULL;
	}
	
	//construct scene
	Scene* scene = new Scene();

	//read scene properties
	if (!addSceneProperties(rootNode, scene)) {
		std::cerr << "SceneParser - Error: Failed to read Scene Properties in " << filename << "\n";
		deletebasicxmlnode(rootNode);
		delete(scene);
		return NULL;
	}

	//read camera
	struct basicxmlnode * cameraNode = getchildnodebyname(rootNode, "Camera");
	if (!addCamera(cameraNode, scene)) {
		std::cerr << "SceneParser - Error: Failed reading camera description in " << filename << "\n";
		deletebasicxmlnode(rootNode);
		delete(scene);
		return NULL;
	}

	//read lights
	struct basicxmlnode * lightsNode = getchildnodebyname(rootNode, "Lights");
	if (!lightsNode) {
		std::cout << "SceneParser - Warning: No Lights specified in " << filename << "\n";
	}
	else if (!lightsNode->children[0]) {
		std::cout << "SceneParser - Warning: No Lights specified in " << filename << "\n";
	}
	else {
		for(int lightsIndex = 0; lightsNode->children[lightsIndex]; lightsIndex++) {
			if(!addLight(lightsNode->children[lightsIndex], scene)) {
				std::cerr << "SceneParser - Error: Failed reading light description in " << filename << "\n";
				deletebasicxmlnode(rootNode);
				delete(scene);
				return NULL;
			}
		}
	}


	//read materials
	struct basicxmlnode * materialsNode = getchildnodebyname(rootNode, "Materials");
	if (!materialsNode) {
		std::cout << "SceneParser - No global Materials specified in " << filename << "\n";
	}
	else if (!materialsNode->children[0]) {
		std::cout << "SceneParser - Empty Materials node in " << filename << "\n";
	} else {
		for(int materialsIndex = 0; materialsNode->children[materialsIndex]; materialsIndex++) {
			if(!addGlobalMaterial(materialsNode->children[materialsIndex], scene)) {
				std::cerr << "SceneParser - Error: Failed reading global material description in " << filename << "\n";
				deletebasicxmlnode(rootNode);
				delete(scene);
				return NULL;
			}
		}
	}

	//read textures
	struct basicxmlnode* texturesNode = getchildnodebyname(rootNode, "Textures");
	if (!texturesNode) {
		std::cout << "SceneParser - No global Textures specified in " << filename << "\n";
	}
	else if (!texturesNode->children[0]) {
		std::cout << "SceneParser - Empty Textures node in " << filename << "\n";
	}
	else {
		for(int texturesIndex = 0; texturesNode->children[texturesIndex]; texturesIndex++) {
			if(!addGlobalTexture(texturesNode->children[texturesIndex], scene)) {
				std::cerr << "SceneParser - Error: Failed reading global texture description in " << filename << "\n";
				deletebasicxmlnode(rootNode);
				delete(scene);
				return NULL;
			}
		}
	}

	//read elements
	struct basicxmlnode * elementsNode = getchildnodebyname(rootNode, "Elements");
	if (!elementsNode) {
		std::cout << "SceneParser - Warning: No Elements specified in " << filename << "\n";
	}
	else if (!elementsNode->children[0]) {
		std::cout << "SceneParser - Warning: No Elements specified in " << filename << "\n";
	}
	for(int elementsIndex = 0; elementsNode->children[elementsIndex]; elementsIndex++) {
		if(!addElement(elementsNode->children[elementsIndex], scene)) {
			std::cerr << "SceneParser - Error: Failed reading element description in " << filename << "\n";
			deletebasicxmlnode(rootNode);
			delete(scene);
			return NULL;
		}
	}

	
	//free xml memory
	deletebasicxmlnode(rootNode);

	std::cout << "[done]\n\n";

	return scene;
}
	/* readbasicxmlnode: reads simple XML file */
struct basicxmlnode *readbasicxmlnode( FILE * fpi )
	{
	int bufinc=500, textinc=50, childinc=50; /* tuning */
	char * buf=0; int nbuf=0;
	char * ibuf=0, * buftmp, * wspos, * ps, * pe, * pe2;
	int phase=0, ch=0, err=0, ii=0, ia, natts, * nodeitmp;
	int itex=0, ntex=textinc, ichi=0, nchi=childinc, nest=0;
	typedef /*struct*/ basicxmlnode nodetype;
	nodetype * node, * child, * * nodetmp;

	if (!err && !fpi) err=1; /* bad arg */
	/* get chars between < and >; strip most whitespace */
	while (1) {
		int isws=0, issl=0, islt=0, isgt=0, iseq=0, isqu=0;
		int isqs=0, isex=0, isda=0, issi=0, isls=0, isrs=0;
		int isn1=0, isn2=0;
		if ((ibuf-buf+5) > nbuf) { /* realloc buf */
		nbuf += bufinc;
		buftmp = new char[nbuf]; /*(char*)malloc(so_c*nbuf);*/
		if (!buftmp) {
			err=2; break; /* out of memory */
		}
		if (buf) {
			ii = ibuf-buf;
			strncpy(buftmp, buf, ii);
			delete [] buf; /*free(buf);*/
		}
		buf = buftmp;
		ibuf = buf + ii;
		}
		if (phase != 100) ch = fgetc(fpi);
		if (err || feof(fpi) || (phase == 100)) break;
		/* analyze char */ /* /<>="?!-'12*/
		if ((ch == ' ') || ((ch > 8) && (ch < 14))) isws = 1;
		if (ch == '/') issl = 1; if (ch == '<') islt = 1;
		if (ch == '>') isgt = 1; if (ch == '=') iseq = 1;
		if (ch == '"') isqu = 1; if (ch == '?') isqs = 1;
		if (ch == '!') isex = 1; if (ch == '-') isda = 1;
		if (ch == '[') isls = 1; if (ch == ']') isrs = 1;
		if (ch == '\'') issi = 1;
		if ((ch >= 'a') && (ch <= 'z')) isn1 = 1;
		if ((ch >= 'A') && (ch <= 'Z')) isn1 = 1;
		if (ch == '_') isn1 = 1;
		if (isn1 || isda || (ch == '.')) isn2 = 1;
		if ((ch >= '0') && (ch <= '9')) isn2 = 1;
		/* err=3, bad xml file (parsing error) */
		switch (phase) {
		case 0: /* eat whitespace before < */
			if (isws) { } /* */
			else if (islt) { ++phase; *ibuf=ch; ++ibuf; } /*<*/
			else { err=3; } /**/ /*/>="?!-'t1*/
			break;
		case 1: /* handle the first char after < */
			if (issl) { phase=10; *ibuf=ch; ++ibuf; } /*</*/
			else if (isqs) { phase=14; --ibuf; } /*<?*/
			else if (isex) { phase=15; --ibuf; } /*<!*/
			else if (isn1) { ++phase; *ibuf=ch; ++ibuf; } /*<t*/
			else { err=3; } /*<*/ /* <>="-'1*/
			break;
		case 2: /* store tag name and a single space after it */
			if (isws) { ++phase; *ibuf = ' '; ++ibuf; } /*<t */
			else if (issl) { phase=13; strncpy(ibuf," /",2); ibuf+=2; } /*<t/*/
			else if (isgt) { phase=100; strncpy(ibuf," >",2); ibuf+=2; } /*<t>*/
			else if (isn2) { *ibuf=ch; ++ibuf; } /*<t*/ /*-1*/
			else { err=3; } /*<t*/ /*<="?!'*/
			break;
		case 3: /* eat whitespace after tag name */
			if (isws) { } /*<tag  */
			else if (issl) { phase=13; *ibuf=ch; ++ibuf; } /*<tag /*/
			else if (isgt) { phase=100; *ibuf=ch; ++ibuf; } /*<tag >*/
			else if (isn1) { ++phase; *ibuf=ch; ++ibuf; } /*<tag t*/
			else { err=3; } /*<tag */ /*<="?!-'1*/
			break;
		case 4: /* store attribute name */
			if (isws) { ++phase; } /*<tag a */
			else if (iseq) { phase=6; *ibuf=ch; ++ibuf; } /*<tag a=*/
			else if (isn2) { *ibuf=ch; ++ibuf; } /*<tag a*/ /*-t1*/
			else { err=3; } /*<tag a*/ /*/<>"?!'t*/
			break;
		case 5: /* eat whitespace after attribute name */
			if (isws) { } /*<tag attr */
			else if (iseq) { ++phase; *ibuf=ch; ++ibuf; } /*<tag attr =*/
			else { err=3; } /*<tag attr */ /*/<>"?!-'t1*/
			break;
		case 6: /* eat whitespace after = */
			if (isws) { } /*<tag attr= */
			else if (isqu) { ++phase; *ibuf=ch; ++ibuf; } /*<tag attr="*/
			else if (issi) { phase=8; *ibuf=ch; ++ibuf; } /*<tag attr='*/
			else { err=3; } /*<tag attr=*/ /*/<>=?!-t1*/
			break;
		case 7: /* store the attribute value ("value") */
			if (isws) { *ibuf=' '; ++ibuf; } /*tag attr=" */
			else if (islt) { err=3; } /*<tag attr="<*/
			else if (isqu) { phase=9; *ibuf=ch; ++ibuf; } /*<tag attr=""*/
			else { *ibuf=ch; ++ibuf; } /*tag attr="*/ /*/>=?!-'t1*/
			break;
		case 8: /* store the attribute value ('value') */
			if (isws) { *ibuf=' '; ++ibuf; } /*<tag attr=' */
			else if (islt) { err=3; } /*<tag attr='<*/
			else if (issi) { ++phase; *ibuf=ch; ++ibuf; } /*<tag attr=''*/
			else { *ibuf=ch; ++ibuf; } /*tag attr='*/ /*/>="?!-t1*/
			break;
		case 9: /* eat whitespace after attribute value */
			if (isws) { phase=3; *ibuf=' '; ++ibuf; } /*<tag attr="value" */
			else if (issl) { phase=13; strncpy(ibuf," /",2); ibuf+=2; } /*..."/*/
			else if (isgt) { phase=100; strncpy(ibuf," >",2); ibuf+=2; } /*...">*/
			else { err=3; } /*tag attr="value"*/ /*<="?!-'t1*/
			break;
		case 10: /* handle the first char after </ */
			if (isn1) { ++phase; *ibuf=ch; ++ibuf; } /*</t*/
			else { err=3; } /*</*/ /* /<>="?!-'1*/
			break;
		case 11: /* store tag name and a single space after it */
			if (isws) { ++phase; *ibuf=' '; ++ibuf; } /*</t */
			else if (isgt) { phase=100; strncpy(ibuf," >",2); ibuf+=2; } /*</t>*/
			else if (isn2) { *ibuf=ch; ++ibuf; } /*</t*/ /*-t*/
			else { err=3; } /*</t*/ /*/<="?!'*/
			break;
		case 12: /* eat whitespace before > */
			if (isws) { } /*</tag */
			else if (isgt) { phase=100; *ibuf=ch; ++ibuf; } /*</tag >*/
			else { err=3; } /*</tag */ /*/<="?!-'t1*/
			break;
		case 13: /* ensure final > */
			if (isgt) { phase=100; *ibuf=ch; ++ibuf; } /*<tag />*/
			else { err=3; } /*<tag /*/ /* /<="?!-'t1*/
			break;
		case 14: /* skip tag (probably <? tag) */
			if (isgt) { if (nest < 1) nest=phase=0; } /*<?>*/
			else if (isls) { ++nest; } /*<?[*/
			else if (isrs) { --nest; } /*<?[*/
			else { } /*<?*/ /* /<="?!-'t1*/
			break;
		case 15: /* find first - (<! tag) */
			if (isgt) { phase=0; } /*<!>*/
			else if (isda) { ++phase; } /*<!-*/
			else if (isls) { ++nest; phase=14; } /*<![*/
			else { phase=14; } /*<!*/ /* /<="?!'t1*/
			break;
		case 16: /* find second - (<!- tag) */
			if (isgt) { phase=0; } /*<!->*/
			else if (isda) { ++phase; } /*<!--*/
			else { phase=14; } /*<!-*/ /* /<="?!'t1*/
			break;
		case 17: /* skip comment */
			if (isda) { ++phase; } /*-*/
			else { } /**/ /* /<>="?!'t1*/
			break;
		case 18: /* find second - in --> */
			if (isda) { ++phase; } /*--*/
			else { phase=17; } /*-*/ /* /<>="?!'t1*/
			break;
		case 19: /* find > in --> */
			if (isgt) { phase=0; } /*-->*/
			else { err=3; } /*--*/ /* /<="?!-'t1*/
			break;
		};
		if (err) break;
	}
	if (!err && (phase != 100)) {
		err=4; /* incomplete xml file */
	}
	if (!err) *ibuf = 0;
	/* buf is now in one of these formats: */
	/* <tag > or </tag > or <tag /> or */
	/* <tag attr="value" ... attr="value" > or */
	/* <tag attr="value" ... attr="value" /> */
	/* allocate memory for a node */
	node = new nodetype; /*(nodetype*)malloc(so_n);*/
	if (node) {
		node->tag = node->text = 0;
		node->attrs = node->values = 0;
		node->children = 0;
		node->childreni = 0;
	}
	if (!err) {
		if (!node) {
		err=5; /* out of memory */
		} else {
		memset(node, 0, sizeof(node));
	} }
	/* put tag name into node */
	if (!err) {
		wspos = strchr(buf, ' ');
		node->tag = new char[wspos-buf]; /*(char*)malloc(so_c*(wspos-buf));*/
		if (!node->tag) err=6; /* out of memory */
	}
	if (!err) {
		strncpy(node->tag, buf+1, wspos-buf-1);
		node->tag[wspos-buf-1] = 0;
		if (buf[1] == '/') { /* end tag (not err) */
		delete [] buf; /*free(buf);*/
		return node;
		}
		/* estimate # of attrs and values (maybe too much) */
		pe = strstr(wspos, "\" ");
		pe2 = strstr(wspos, "' ");
		for (natts=0; pe || pe2; ++natts) {
		if (!pe || (pe2 && (pe2 < pe))) pe = pe2;
		pe2 = strstr(pe+1, "' "); pe = strstr(pe+1, "\" ");
		}
		node->attrs = new char *[natts+1]; /*(char**)malloc(so_cp*(natts+1));*/
		node->values = new char *[natts+1]; /*(char**)malloc(so_cp*(natts+1));*/
		if (!node->attrs||!node->values) {
		if (node->attrs) delete [] node->attrs; /*free(node->attrs);*/
		if (node->values) delete [] node->values; /*free(node->values);*/
		node->attrs=node->values=0; err=7; /* out of memory */
	} }
	/* put attrs and values into node (and recount #) */
	if (!err) { ps = wspos+1;
		pe = strstr(wspos, "=\""); pe2 = strstr(wspos, "='");
	}
	for (natts=0, ia=0; !err && (pe||pe2); ++ia, ++natts) {
		if (!pe || (pe2 && (pe2 < pe))) pe = pe2;
		node->attrs[ia] = new char[pe-ps+1]; /*(char*)malloc(so_c*(pe-ps+1));*/
		if (!node->attrs[ia]) {
		node->values[ia]=0; err=8; break; /* out of memory */
		}
		strncpy(node->attrs[ia], ps, pe-ps);
		node->attrs[ia][pe-ps] = 0;
		node->attrs[ia+1] = 0;
		ps = pe + 2;
		if (pe == pe2) pe = strstr(ps, "' ");
		else pe = strstr(ps, "\" ");
		node->values[ia] = new char[pe-ps+1]; /*(char*)malloc(so_c*(pe-ps+1));*/
		if (!node->values[ia]) { err=9; break; } /* out of memory */
		strncpy(node->values[ia], ps, pe-ps);
		node->values[ia][pe-ps] = 0;
		node->values[ia+1] = 0;
		ps = pe + 2;
		pe2 = strstr(ps, "='"); pe = strstr(ps, "=\"");
	}
	if (!err) {
		node->attrs[natts] = node->values[natts] = 0;
		/* no children for self-contained tag, save memory */
		if (buf[strlen(buf)-2] == '/') {
		ntex = 1; nchi = 1;
		}
		/* no body or children yet */
		node->text = new char[ntex]; /*(char*)malloc(so_c*ntex);*/
		node->children = new nodetype *[nchi]; /*(nodetype**)malloc(so_np*nchi);*/
		node->childreni = new int [nchi]; /*(int*)malloc(so_i*nchi);*/
		if (!node->text || !node->children || !node->childreni) {
		err=10; /* out of memory */
		} else {
		node->text[0] = 0; node->children[0] = 0; node->childreni[0] = 0;
	} }
	if (!err) {
		if (ntex == 1) { /* end tag, no children (not err) */
		delete [] buf; /*free(buf);*/
		return node;
	} }
	/* read child tags */
	for (ichi=0; !err; ++ichi) {
		/* add more text to node (between child tags) */
		for (ch=fgetc(fpi); ch != '<'; ch=fgetc(fpi)) {
		if (feof(fpi)) {
			err=11; /* incomplete xml file */
			break;
		}
		if ((itex+2) == ntex) { /* realloc text */
			ntex += textinc;
			buftmp = new char[ntex]; /*(char*)malloc(so_c*ntex);*/
			if (!buftmp) { err=12; break; } /* out of memory */
			strncpy(buftmp, node->text, itex);
			delete [] node->text; /*free(node->text);*/
			node->text = buftmp;
		}
		node->text[itex++] = ch;
		}
		if (err) continue;
		node->text[itex] = 0;
		ungetc(ch, fpi); /* oops, put back next tag's "<" */
		child = readbasicxmlnode(fpi);
		if (child) {
		if (child->tag[0] == '/') {
			if (strcmp(child->tag+1, node->tag)) {
			err=13; /* end tag mismatch */
			}
			delete [] child->tag; /*free(child->tag);*/
			delete child; /*free(child);*/
			child=0;
		} } else if (!err) {
		err=14; /* bad child */
		}
		if (err || !child) break;
		node->children[ichi] = child;
		node->childreni[ichi] = itex;
		if ((ichi+2) == nchi) { /* realloc child tags array */
		nchi += childinc;
		nodetmp = new nodetype *[nchi]; /*(nodetype**)malloc(so_np*nchi);*/
		if (!nodetmp) { err=15; continue; } /* out of memory */
		nodeitmp = new int [nchi]; /*(int*)malloc(so_i*nchi);*/
		if (!nodeitmp) {
			delete [] nodetmp; /*free(nodetmp);*/
			nodetmp=0; err=16; continue; /* out of memory */
		}
		for (ii=0; ii <= ichi; ++ii) { /* copy */
			nodetmp[ii] = node->children[ii];
			nodeitmp[ii] = node->childreni[ii];
		}
		delete [] node->children; /*free(node->children);*/
		delete [] node->childreni; /*free(node->childreni);*/
		node->children = nodetmp;
		node->childreni = nodeitmp;
	} }
	if (node) {
		if (node->children) {
		node->children[ichi] = 0;
		node->childreni[ichi] = 0;
		if (err) { /* delete complete node */
			deletebasicxmlnode(node); node = 0;
		} } else { /* delete partial node */
		if (node->tag) delete [] node->tag; /*free(node->tag);*/
		if (node->text) delete [] node->text; /*free(node->text);*/
		if (node->attrs) {
			for (ii=0; node->attrs[ii]; ++ii) {
			delete [] node->attrs[ii]; /*free(node->attrs[ii]);*/
		} }
		if (node->values) {
			for (ii=0; node->values[ii]; ++ii) {
			delete [] node->values[ii]; /*free(node->values[ii]);*/
		} }
		if (node->attrs) delete node->attrs; /*free(node->attrs);*/
		if (node->values) delete node->values; /*free(node->values);*/
		delete node; /*free(node);*/
		node = 0;
	} }
	if (buf) delete [] buf; /*free(buf);*/
	return node; /* whew! return complete node */
}