/**
 * 
 */
package org.commcare.data.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

import org.commcare.xml.ElementParser;
import org.commcare.xml.util.InvalidStructureException;
import org.commcare.xml.util.UnfullfilledRequirementsException;
import org.javarosa.core.log.WrappedException;
import org.javarosa.core.services.Logger;
import org.xmlpull.v1.XmlPullParserException;

/**
 * A DataModelPullParser pulls together the parsing of
 * different data models in order to be able to perform
 * a master update/restore of remote data.
 * 
 * 
 * @author ctsims
 *
 */
public class DataModelPullParser extends ElementParser<Boolean> {
	
	Vector<String> errors;
	
	TransactionParserFactory factory;
	
	boolean failfast;
	boolean deep;
	
	InputStream is;
	
	public DataModelPullParser(InputStream is, TransactionParserFactory factory) throws InvalidStructureException, IOException {
		this(is, factory, false);
	}
	
	public DataModelPullParser(InputStream is, TransactionParserFactory factory, boolean deep) throws InvalidStructureException, IOException {
		this(is,factory,false, deep);
	}
	
	public DataModelPullParser(InputStream is, TransactionParserFactory factory, boolean failfast, boolean deep) throws InvalidStructureException, IOException {
		super(is);
		this.is = is;
		this.failfast = failfast;
		this.factory = factory;
		errors = new Vector<String>();
		this.deep = deep;
	}

	public Boolean parse() throws InvalidStructureException, IOException, XmlPullParserException, UnfullfilledRequirementsException {
		try {
			String rootName = parser.getName();
			//Here we'll go through in search of CommCare data models and parse
			//them using the appropriate CommCare Model data parser.
			
			//Go through each child of the root element
			parseBlock(rootName);
		} finally {
			//kxmlparser might close the stream, but we can't be sure, especially if
			//we bail early due to schema errors
			try {
				is.close();
			} catch (IOException ioe) {
				//swallow
			}
		}
		
		if(errors.size() == 0) {
			return Boolean.TRUE;
		} else {
			return Boolean.FALSE;
		}
	}
	
	private void parseBlock(String root)  throws InvalidStructureException, IOException, XmlPullParserException, UnfullfilledRequirementsException {
		while(this.nextTagInBlock(root)) {
			
			String name = parser.getName();
			String namespace = parser.getNamespace();
			
			int depth = parser.getDepth();
			if(name == null) {
				continue;
			}
			
			TransactionParser transaction = factory.getParser(name,namespace,parser);
			if(transaction == null) {
				//nothing to be done for this element, recurse?
				if(deep) {
					parseBlock(name);
				} else {
					this.skipBlock(name);
				}
			} else {
				try{
					transaction.parse();
				} catch(Exception e) {
					e.printStackTrace();
					deal(e, depth, name);
				}
			}
		}
	}
	
	private void deal(Exception e, int depth, String parentTag) throws XmlPullParserException, IOException {
		errors.addElement(WrappedException.printException(e));
		this.skipBlock(parentTag);
		
		if(failfast) {
			throw new WrappedException(e);
		}
	}
	
	public String[] getParseErrors() {
		String[] errorBuf = new String[errors.size()];
		for(int i = 0 ; i < errorBuf.length ; ++i) {
			errorBuf[i] = errors.elementAt(i);
		}
		return errorBuf;
	}
}

@@ -2816,24 +2816,46 @@
 %09%09%7D else %7B%0D%0A
+%09%09%09%09if(!failfast) %7B%0D%0A%09
 %09%09%09%09try%7B%0D%0A%09%09
@@ -2852,16 +2852,17 @@
 %09%09try%7B%0D%0A
+%09
 %09%09%09%09%09tra
@@ -2876,24 +2876,25 @@
 n.parse();%0D%0A
+%09
 %09%09%09%09%7D catch(
@@ -2914,16 +2914,17 @@
 %7B%0D%0A%09%09%09%09%09
+%09
 e.printS
@@ -2942,16 +2942,17 @@
 ;%0D%0A%09%09%09%09%09
+%09
 deal(e, 
@@ -2958,32 +2958,81 @@
  depth, name);%0D%0A
+%09%09%09%09%09%7D%0D%0A%09%09%09%09%7D else %7B%0D%0A%09%09%09%09%09transaction.parse();%0D%0A
 %09%09%09%09%7D%0D%0A%09%09%09%7D%0D%0A%09%09%7D

improve fidelity of failfast behaviors