package org.openforis.calc.collect;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import org.openforis.collect.model.CollectRecord;
import org.openforis.collect.model.CollectRecord.Step;
import org.openforis.collect.model.CollectSurvey;
import org.openforis.collect.persistence.xml.DataHandler;
import org.openforis.collect.persistence.xml.DataUnmarshaller;
import org.openforis.collect.persistence.xml.DataUnmarshaller.ParseRecordResult;

/**
 * 
 * @author S. Ricci
 *
 */
public class CollectBackupRecordExtractor implements Closeable {

	protected static final String IDML_FILE_NAME = "idml.xml";

	//params
	private CollectSurvey survey;
	protected File file;
	
	//transient
	private boolean initialized;
	protected ZipFile zipFile;
	protected Enumeration<? extends ZipEntry> zipEntries;
	private DataUnmarshaller dataUnmarshaller;

	public CollectBackupRecordExtractor(CollectSurvey survey, File file) throws ZipException, IOException {
		this.survey = survey;
		this.file = file;
		initialized = false;
	}

	public void init() throws ZipException, IOException {
		this.dataUnmarshaller = new DataUnmarshaller(new DataHandler(survey));
		this.zipFile = new ZipFile(file);
		this.zipEntries = zipFile.entries();
		initialized = true;
	}

	public ParseRecordResult nextRecord(Step step) throws Exception {
		checkInitialized();
		ParseRecordResult result = null;
		ZipEntry zipEntry = nextRecordEntry();
		while ( zipEntry != null ) {
			String entryName = zipEntry.getName();
			Step entryStep = extractStep(entryName);
			if ( step == null || step == entryStep ) {
				InputStream inputStream = zipFile.getInputStream(zipEntry);
				InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
				result = dataUnmarshaller.parse(reader);
				if ( result.isSuccess() ) {
					CollectRecord record = result.getRecord();
					record.updateRootEntityKeyValues();
					record.updateEntityCounts();
				}
				return result;
			} else {
				zipEntry = nextRecordEntry();
			}
		}
		return result;
	}
	
	public ZipEntry nextRecordEntry() {
		while ( zipEntries.hasMoreElements() ) {
			ZipEntry zipEntry = zipEntries.nextElement();
			String entryName = zipEntry.getName();
			if ( zipEntry.isDirectory() || IDML_FILE_NAME.equals(entryName)  ) {
				continue;
			} else {
				return zipEntry;
			}
		}
		return null;
	}
	
	@Override
	public void close() throws IOException {
		if ( zipFile != null ) {
			zipFile.close();
		}
	}
	
	protected void checkInitialized() {
		if ( ! initialized ) {
			throw new IllegalStateException("Exctractor not inited");
		}
	}
	
	private Step extractStep(String zipEntryName) throws Exception {
		String[] entryNameSplitted = getEntryNameSplitted(zipEntryName);
		String stepNumStr = entryNameSplitted[0];
		int stepNumber = Integer.parseInt(stepNumStr);
		return Step.valueOf(stepNumber);
	}
	
	private String[] getEntryNameSplitted(String zipEntryName) throws Exception {
		String entryPathSeparator = Pattern.quote(File.separator);
		String[] entryNameSplitted = zipEntryName.split(entryPathSeparator);
		if (entryNameSplitted.length != 2) {
			entryPathSeparator = Pattern.quote("/");
			entryNameSplitted = zipEntryName.split(entryPathSeparator);
		}
		if (entryNameSplitted.length != 2) {
			throw new Exception("Packaged file format exception: wrong entry name: " + zipEntryName);
		}
		return entryNameSplitted;
	}

	public long countRecords() {
		checkInitialized();
		int count = 0;
		ZipEntry entry = nextRecordEntry();
		while ( entry != null ) {
			count++;
			entry = nextRecordEntry();
		}
		return count;
	}
	
}

@@ -2863,32 +2863,60 @@
 tryName) throws 
+CollectBackupRecordExtractor
 Exception %7B%0A%09%09St
@@ -3170,32 +3170,60 @@
 tryName) throws 
+CollectBackupRecordExtractor
 Exception %7B%0A%09%09St
@@ -3552,16 +3552,44 @@
 row new 
+CollectBackupRecordExtractor
 Exceptio
@@ -3722,17 +3722,71 @@
 Records(
-)
+Step step) throws CollectBackupRecordExtractorException
  %7B%0A%09%09che
@@ -3885,16 +3885,146 @@
 ull ) %7B%0A
+%09%09%09String entryName = entry.getName();%0A%09%09%09Step entryStep = extractStep(entryName);%0A%09%09%09if ( step == null %7C%7C step == entryStep ) %7B%0A%09
 %09%09%09count
@@ -4027,16 +4027,21 @@
 ount++;%0A
+%09%09%09%7D%0A
 %09%09%09entry
@@ -4087,10 +4087,280 @@
 t;%0A%09%7D%0A%09%0A
+%09class CollectBackupRecordExtractorException extends Exception %7B%0A%09%09%0A%09%09private static final long serialVersionUID = 1L;%0A%0A%09%09public CollectBackupRecordExtractorException() %7B%0A%09%09%7D%0A%0A%09%09public CollectBackupRecordExtractorException(String message) %7B%0A%09%09%09super(message);%0A%09%09%7D%0A%09%09%0A%09%7D%0A
 %7D%0A

Fix total records count