package lu.tudor.santec.gecamed.importer.converter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: XmlConverter.java,v $
 */

public abstract class GECAMedImportConverter
{
	private static DateFormat	tmpFileFormatter	= new SimpleDateFormat("HHmmssSSS");
	private static DateFormat	birthdayFormatter	= new SimpleDateFormat("yyyy-MM-dd");
	private static DateFormat	createdFormatter	= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
	
	
	protected File	outputDir;
	
	protected String	xmlTemplate;
	
	protected String	ssn;
	protected String	title;
	protected String	firstname;
	protected String	lastname;
	protected String	birthname;
	protected String	gender;
	protected Date		birthday;
	protected String	insurance;
	protected Date		created;
	
	protected String	country;
	protected String	zip;
	protected String	locality;
	protected String	street;
	protected String	streetNo;
	
	
	
	public void setOutputDir (File outputDir)
	{
		this.outputDir	= outputDir;
	}
	
	
	
	/* ======================================== */
	// ABSTRACT METHODS
	/* ======================================== */
	
	/**
	 * Read the next patient and use the methods setPatientData and setAddressData 
	 * to set the read data for the creation of the XML file.
	 * 
	 * @return <code>true</code> if a new patient was found and its data was read and set, 
	 * else if the conversion finished.
	 */
	public abstract boolean readNextPatient ();
	
	/**
	 * Do the necessary preparations before the convertion starts. 
	 */
	public abstract void perpare ();
	
	
	
	/* ======================================== */
	// CLASS BODY
	/* ======================================== */
	
	public boolean convert ()
	{
		InputStream		is;
		BufferedReader	reader	= null;
		StringBuilder	xmlTemplateBuilder;
		String			line;
		
		
		// read the template
		try
		{
			is					= GECAMedImportConverter.class.getResourceAsStream("resources/data_template.xml");
			reader				= new BufferedReader(new InputStreamReader(is, "UTF8"));
			xmlTemplateBuilder	= new StringBuilder();
			
			while ((line = reader.readLine()) != null)
				xmlTemplateBuilder
						.append(line)
						.append("\r\n");
			
			xmlTemplate	= xmlTemplateBuilder.toString();
		}
		catch (IOException e)
		{
			e.printStackTrace();
			return false;
		}
		finally
		{
			try
			{
			if (reader != null)
					reader.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
				return false;
			}
		}
		
		perpare();
		
		while (readNextPatient())
		{
			try
			{
				writeXmlFile();
			}
			catch (IOException e)
			{
				e.printStackTrace();
				return false;
			}
		}
		
		return true;
	}
	
	
	protected void setPatientData (String ssn, String title, String firstname, String lastname, String maidenname, 
			String gender, Date birthday, Date created, String insurance)
	{
		this.ssn		= ssn;
		this.title		= title;
		this.firstname	= firstname;
		this.lastname	= lastname;
		this.birthname	= maidenname;
		this.gender		= gender;
		this.birthday	= birthday;
		this.created	= created;
		this.insurance	= insurance;
	}
	
	
	protected void setAddressData (String country, String zip, String locality, String street, String streetNo)
	{
		this.country	= country;
		this.zip		= zip;
		this.locality	= locality;
		this.street		= street;
		this.streetNo	= streetNo;
	}
	
	
	
	/* ======================================== */
	// HELP METHODS
	/* ======================================== */
	
	private String createPatientFileName ()
	{
		return new StringBuilder()
				.append(isEmpty(ssn)		? "" : ssn + "_")
				.append(isEmpty(birthname)	? "" : birthname + "_")
				.append(isEmpty(lastname)	? "" : lastname + "_")
				.append(isEmpty(firstname)	? "" : firstname + "_")
				.append(tmpFileFormatter.format(new Date()))
				.append(".xml")
				.toString()
				.replaceAll("[^0-9A-Za-z_.]+", "");
	}
	
	
	private boolean isEmpty (String toTest)
	{
		return toTest == null || toTest.trim().length() == 0;
	}
	
	
	private void writeXmlFile () throws IOException
	{
		File			xmlFile;
		String			xmlOutput	= xmlTemplate;
		Calendar		calendar	= new GregorianCalendar();
		
		
		calendar.setTime(created);
		calendar.set(Calendar.HOUR_OF_DAY, 12);
		created		= calendar.getTime();
		
		// replace the template
		xmlOutput	= xmlOutput.replace("[SSN]",			ssn);
		xmlOutput	= xmlOutput.replace("[FIRSTNAME]",		firstname);
		xmlOutput	= xmlOutput.replace("[LASTNAME]",		lastname);
		xmlOutput	= xmlOutput.replace("[BITHNAME]",		birthname);
		xmlOutput	= xmlOutput.replace("[TITLE]",			title);
		xmlOutput	= xmlOutput.replace("[GENDER]",			gender);
		xmlOutput	= xmlOutput.replace("[BIRTHDAY]",		birthdayFormatter.format(birthday));
		xmlOutput	= xmlOutput.replace("[CREATED]",		createdFormatter.format(created));
		xmlOutput	= xmlOutput.replace("[INSURANCE]",		insurance);
		xmlOutput	= xmlOutput.replace("[ADDRESS_TYPE]",	"private");
		xmlOutput	= xmlOutput.replace("[STREET]",			street);
		xmlOutput	= xmlOutput.replace("[STREET_NO]",		streetNo);
		xmlOutput	= xmlOutput.replace("[ZIP]",			zip);
		xmlOutput	= xmlOutput.replace("[LOCALITY]",		locality);
		xmlOutput	= xmlOutput.replace("[COUNTRY]",		country);
		
		// write the GECAMed XML import file
		xmlFile		= new File(outputDir, createPatientFileName());
		xmlFile.createNewFile();
		writeFile(xmlOutput.getBytes("UTF8"), xmlFile);
	}
	
	
	public static boolean writeFile (byte[] data, File target)
			throws IOException
	{
		ByteBuffer			buffer		= ByteBuffer.wrap(data);
		FileOutputStream	fos			= null;
		FileChannel			channel;
		
		
		try
		{
			fos		= new FileOutputStream(target);
			channel	= fos.getChannel();
			channel.write(buffer);
		}
		finally
		{
			if (fos != null)
				fos.close();
		}
		
		return true;
		
//		BufferedOutputStream fOut = new BufferedOutputStream(
//				new FileOutputStream(toFile, false));
//		fOut.write(data);
//		fOut.close();
//		return true;
	}
}
