/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
/**
 * 
 */
package lu.tudor.santec.gecamed.prescription.gui.drug.lists.cefip.importer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.swing.JProgressBar;

import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.cefip.CefipDrugData;
import lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.drug.lists.cefip.CefipDrugManager;
import lu.tudor.santec.gecamed.prescription.gui.drug.lists.cefip.CefipDrugListModule;

import org.apache.log4j.Logger;

import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.Table;
import com.svcon.jdbf.JDBFException;

/**
 * Imports a CEFIP dbf database file into the GECAMed database
 * 
 * While importing, several storing threads are started that send the generated
 * objects to the application server. The generated objects are pushed into a
 * stack and the store threads pull them out again. If the stack size is getting
 * to high, the generation-process is paused to let the store threads reduce the
 * stack size.
 * 
 * 
 * @author martin.heinemann@tudor.lu
 * 
 * 
 * @version <br>
 *          $Log: ImportMdbCefipDrug.java,v $
 *          Revision 1.4  2013-12-27 18:09:25  donak
 *          Cleanup of imports
 *
 *          Revision 1.3  2013-07-15 06:18:36  ferring
 *          logging changed
 *
 *          Revision 1.2  2011-02-28 15:41:45  troth
 *          To provide smaller resolutions for the user interface add the navigation bar icons and function bar icons to the user setting "use small icons"
 * <br>
 *          Revision 1.1 2009-05-07 15:56:26 heinemann <br>
 *          import of new cefip file format in ms access. <br>
 *          using lib jackccess <br>
 * <br>
 *          Revision 1.8 2008-09-25 09:43:06 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.7 2008-01-15 09:58:54 heinemann <br>
 *          better documentation <br>
 * <br>
 *          Revision 1.6 2007/07/19 14:09:59 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.5 2007/07/03 12:35:29 heinemann <br>
 *          system.out removed <br>
 * <br>
 *          Revision 1.4 2007/03/02 08:28:39 hermen <br>
 *          initial checkin after the merge of PatientModuleRebuild with the
 *          main HEAD <br>
 * <br>
 *          Revision 1.3.2.1 2006/12/20 13:47:04 heinemann <br>
 *          *** empty log message *** <br>
 */
public class ImportMdbCefipDrug {

	/* *******************************************************************
	 * Class Members
	 */
	Logger logger = Logger
			.getLogger("lu.tudor.santec.gecamed.prescription.gui.drug.lists.cefip");

	private Stack<CefipDrugData> cefipStack;

	private JProgressBar progressBar;

	private File mdbFile;

	/* End of Class Members */
	/* ****************************************************************** */

	/* ******************************************************************
	 * Class methods
	 */

	/**
	 * 
	 * 
	 * @param dbfReader
	 *            the DBFReader with the dbf file to read from
	 */
	public ImportMdbCefipDrug(File file) {
		/* ====================================================== */
		logger.info("Cefip MdbDrug importer created");

		this.mdbFile = file;

		// create a new stack
		this.cefipStack = new Stack<CefipDrugData>();
		/* ====================================================== */
	}

	/**
	 * @return
	 */
	public int getAmount() {
		/* ================================================== */
		int rows = 0;
		try {
			/* ------------------------------------------------------- */
			Database base = Database.open(this.mdbFile, true);
			Table table = base.getTable("CEFIP2000");

			rows = table.getRowCount();

			base.close();

			/* ------------------------------------------------------- */
		} catch (IOException e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		return rows;
		/* ================================================== */
	}

	/**
	 * @return
	 */
	public boolean testIntegrity() {
		/* ====================================================== */
		if (this.mdbFile == null) {
			logger.error("No Mdb file avalable!");
			return false;
		}
		/*
		 * ---------------------------------------------------------- We will
		 * now test, if this is a valid mdb drug file
		 * ----------------------------------------------------------
		 */
		try {
			/* ------------------------------------------------------- */
			Database base = Database.open(this.mdbFile, true);
			Table table = base.getTable("CEFIP2000");

			table.getRowCount();
			Map<String, Object> value = table.getNextRow();
			boolean returnValue = false;
			/* ------------------------------------------------------- */
			if (value.get("NUMNAT") != null && value.get("DATEHIST") != null
					&& value.get("DENOM") != null
					&& value.get("FORMECLAIR") != null)
				returnValue = true;

			base.close();
			return returnValue;
			/* ------------------------------------------------------- */
		} catch (IOException e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		return false;
		/* ====================================================== */
	}

	/**
	 * Here it will all begin. Start the import.
	 * 
	 * @param max
	 *            progressbar max size
	 * @throws JDBFException
	 */
	public void doImport(JProgressBar progressBar, int count) {
		/* ============================================ */
		logger.info("Starting import of CEFIP DrugDatabase");
		/* ---------------------------------------- */
		this.progressBar = progressBar;

		List<DrugStoringThread> storeThreads = new ArrayList<DrugStoringThread>();
		long startTime = System.currentTimeMillis();

		/* ------------------------------------------------------ */

		// set the text
		this.progressBar.setMaximum(count);
		progressBar.setValue(0);
		/* ------------------------------------------------------ */
		/*
		 * At first a few Threads are started to write the entities to the
		 * session bean. When the list is finished, a thread is started to stop
		 * the threads.
		 */

		// create the threads
		// and start them
		for (int i = 0; i < 1; i++) {
			/* ------------------------------------------------ */
			DrugStoringThread t = new DrugStoringThread(cefipStack);
			storeThreads.add(t);
			t.start();
			/* ------------------------------------------------ */
		}

		/* ------------------------------------------------------ */
		// start reading
		Database base = null;
		int a = 0;
		try {
			/* ------------------------------------------------------- */
			// open mdb file
			/* ------------------------------------------------------- */
			base = Database.open(this.mdbFile, true);
			Table table = base.getTable("CEFIP2000");
			/* ------------------------------------------------------- */
			int rows = table.getRowCount();
			Map<String, Object> value = null;
			// iterate over all rows
			logger.info("Starting import of mdb drugs");
			for (int i = 0; i <= rows; i++) {
				/* ------------------------------------------------------- */
				value = table.getNextRow();
				if (value == null)
					continue;
				// progress
				progressBar.setValue(progressBar.getValue() + a++);
				/* ------------------------------------------------------ */
				// Create a CefipDrugData object
				CefipDrugData data = new CefipDrugData();
				/* ------------------------------------------------------ */
				// fill the object
				setObjectData(value, data);
				data.setId(null);

				// push the object to the stack
				this.cefipStack.push(data);

				/* ------------------------------------------------------ */
				// if the stack has reached a size greater than 20
				// pause the creation of new objects and let the
				// storing threads do their work
				try {
					if (cefipStack.size() > 20)
						Thread.sleep(15);
				} catch (InterruptedException e) {
					logger.warn(e.getLocalizedMessage());
				}
				/* ------------------------------------------------------ */
				/* ------------------------------------------------------- */
			}
			logger.info("Finished importing mdb drugs");
			/* ------------------------------------------------------- */
		} catch (IOException e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}

		/* ------------------------------------------------------- */
		// close the file
		/* ---------------------------------------- */
		if (base != null)
			try {
				base.close();
			} catch (IOException e1) {
				/* --------------------------------------------- */
				e1.printStackTrace();
				/* --------------------------------------------- */
			}

		// stop the threads
		for (DrugStoringThread t : storeThreads) {
			t.setOnline(false);
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("Took " + (System.currentTimeMillis() - startTime)
				+ "ms");

		/* ---------------------------------------- */
	}

	/* ============================================ */

	private void setObjectData(Map<String, Object> value, CefipDrugData data) {
		/* ================================================== */
		data.setNumnat(("" + value.get("NUMNAT")).trim());
		data.setDatehist(("" + value.get("DATEHIST")).trim());
		data.setDenom(("" + value.get("DENOM")).trim());
		data.setFormeclair(("" + value.get("FORMECLAIR")).trim());
		data.setDosageq1(("" + value.get("DOSAGEQ1")).trim());
		data.setDosageu1(("" + value.get("DOSAGEU1")).trim());
		data.setDosageqp1(("" + value.get("DOSAGEQP1")).trim());
		data.setDosageup1(("" + value.get("DOSAGEUP1")).trim());
		data.setDosageq2(("" + value.get("DOSAGEQ2")).trim());
		data.setDosageu2(("" + value.get("DOSAGEU2")).trim());
		data.setDosageqp2(("" + value.get("DOSAGEQP2")).trim());
		data.setDosageup2(("" + value.get("DOSAGEUP2")).trim());
		data.setPiece(("" + value.get("PIECE")).trim());
		data.setLarg(("" + value.get("LARG")).trim());
		data.setLongu(("" + value.get("LONGU")).trim());
		data.setPoids(("" + value.get("POIDS")).trim());
		data.setVolume(("" + value.get("VOLUME")).trim());
		data.setCondition(("" + value.get("CONDITION")).trim());
		data.setPresent(("" + value.get("PRESENT")).trim());
		data.setPresenta(("" + value.get("PRESENTA")).trim());
		data.setEmballage(("" + value.get("EMBALLAGE")).trim());
		data.setVoieadmis1(("" + value.get("VOIEADMIS1")).trim());
		data.setVoieadmis2(("" + value.get("VOIEADMIS2")).trim());
		data.setVoieadmis3(("" + value.get("VOIEADMIS3")).trim());
		data.setVoieadmis4(("" + value.get("VOIEADMIS4")).trim());
		data.setCodeatc1(("" + value.get("CODEATC1")).trim());
		data.setCodeatc2(("" + value.get("CODEATC2")).trim());
		data.setCodeatc3(("" + value.get("CODEATC3")).trim());
		data.setCodeatc4(("" + value.get("CODEATC4")).trim());
		data.setClassme(("" + value.get("CLASSME")).trim());
		data.setAtcdef(("" + value.get("ATCDEF")).trim());
		data.setLimitenbr(("" + value.get("LIMITENBR")).trim());
		data.setLimitemj(("" + value.get("LIMITEMJ")).trim());
		data.setTdc(("" + value.get("TDC")).trim());
		data.setTdcrecons(("" + value.get("TDCRECONS")).trim());
		data.setDdstma(("" + value.get("DDSTMA")).trim());
		data.setDsunites(("" + value.get("DSUNITES")).trim());
		data.setReconsnbr(("" + value.get("RECONSNBR")).trim());
		data.setReconsmjh(("" + value.get("RECONSMJH")).trim());
		data.setRenouv(("" + value.get("RENOUV")).trim());
		data.setRenouvmois(("" + value.get("RENOUVMOIS")).trim());
		data.setPresunique(("" + value.get("PRESUNIQUE")).trim());
		data.setCondspec(("" + value.get("CONDSPEC")).trim());
		data.setNmol(("" + value.get("NMOL")).trim());
		data.setConddeliv(("" + value.get("CONDDELIV")).trim());
		data.setTitulaire(("" + value.get("TITULAIRE")).trim());
		data.setFabricant(("" + value.get("FABRICANT")).trim());
		data.setDistribpha(("" + value.get("DISTRIBPHA")).trim());
		data.setDistribgro(("" + value.get("DISTRIBGRO")).trim());
		data.setCodepamm(("" + value.get("CODEPAMM")).trim());
		data.setImporte(("" + value.get("IMPORTE")).trim());
		data.setPays1(("" + value.get("PAYS1")).trim());
		data.setPays2(("" + value.get("PAYS2")).trim());
		data.setPays3(("" + value.get("PAYS3")).trim());
		data.setPays4(("" + value.get("PAYS4")).trim());
		data.setVigilan1(("" + value.get("VIGILAN1")).trim());
		data.setVigilan2(("" + value.get("VIGILAN2")).trim());
		data.setVigilan3(("" + value.get("VIGILAN3")).trim());
		data.setVigilan4(("" + value.get("VIGILAN4")).trim());
		data.setProcedure(("" + value.get("PROCEDURE")).trim());
		data.setProceddate(("" + value.get("PROCEDDATE")).trim());
		data.setCleancenr(("" + value.get("CLEANCENR")).trim());
		data.setClenouvenr(("" + value.get("CLENOUVENR")).trim());
		data.setDatedeb(("" + value.get("DATEDEB")).trim());
		data.setCetat(("" + value.get("CETAT")).trim());
		data.setDatefin(("" + value.get("DATEFIN")).trim());
		data.setDatemem(("" + value.get("DATEMEM")).trim());
		data.setEtatmem1(("" + value.get("ETATMEM1")).trim());
		data.setCetatmem1(("" + value.get("CETATMEM1")).trim());
		data.setEtatmem2(("" + value.get("ETATMEM2")).trim());
		data.setCetatmem2(("" + value.get("CETATMEM2")).trim());
		data.setLufexus(("" + value.get("LUFEXUS")).trim());
		data.setLufprix(("" + value.get("LUFPRIX")).trim());
		data.setLufinterv(("" + value.get("LUFINTERV")).trim());
		data.setLufrefer(("" + value.get("LUFREFER")).trim());
		data.setLufb1recom(("" + value.get("LUFB1RECOM")).trim());
		data.setEurexusin(("" + value.get("EUREXUSIN")).trim());
		data.setEurprix(("" + value.get("EURPRIX")).trim());
		data.setEurinterv(("" + value.get("EURINTERV")).trim());
		data.setEurrefer(("" + value.get("EURREFER")).trim());
		data.setEurb1recom(("" + value.get("EURB1RECOM")).trim());
		data.setPaysref(("" + value.get("PAYSREF")).trim());
		data.setPaysorig(("" + value.get("PAYSORIG")).trim());
		data.setTaux(("" + value.get("TAUX")).trim());
		data.setAbatt(("" + value.get("ABATT")).trim());
		data.setCategorie(("" + value.get("CATEGORIE")).trim());
		data.setDateprix(("" + value.get("DATEPRIX")).trim());
		data.setEtatprix(("" + value.get("ETATPRIX")).trim());
		data.setApcm(("" + value.get("APCM")).trim());
		data.setApcmcond(("" + value.get("APCMCOND")).trim());
		data.setApcmdetail(("" + value.get("APCMDETAIL")).trim());
		data.setCefipnum(("" + value.get("CEFIPNUM")).trim());
		data.setCefipcbarr(("" + value.get("CEFIPCBARR")).trim());
		data.setCefipdenom(("" + value.get("CEFIPDENOM")).trim());
		data.setCefiprespo(("" + value.get("CEFIPRESPO")).trim());
		data.setCefprixluf(("" + value.get("CEFPRIXLUF")).trim());
		data.setCefprixeur(("" + value.get("CEFPRIXEUR")).trim());
		data.setCefpharluf(("" + value.get("CEFPHARLUF")).trim());
		data.setCefphareur(("" + value.get("CEFPHAREUR")).trim());
		data.setTva(("" + value.get("TVA")).trim());
		data.setNbcomp(("" + value.get("NBCOMP")).trim());
		data.setComp1(("" + value.get("COMP1")).trim());
		data.setCp11(("" + value.get("CP11")).trim());
		data.setCp12(("" + value.get("CP12")).trim());
		data.setCp13(("" + value.get("CP13")).trim());
		data.setCp14(("" + value.get("CP14")).trim());
		data.setCp15(("" + value.get("CP15")).trim());
		data.setComp2(("" + value.get("COMP2")).trim());
		data.setCp21(("" + value.get("CP21")).trim());
		data.setCp22(("" + value.get("CP22")).trim());
		data.setCp23(("" + value.get("CP23")).trim());
		data.setCp24(("" + value.get("CP24")).trim());
		data.setCp25(("" + value.get("CP25")).trim());
		data.setComp3(("" + value.get("COMP3")).trim());
		data.setCp31(("" + value.get("CP31")).trim());
		data.setCp32(("" + value.get("CP32")).trim());
		data.setCp33(("" + value.get("CP33")).trim());
		data.setCp34(("" + value.get("CP34")).trim());
		data.setCp35(("" + value.get("CP35")).trim());
		data.setComp4(("" + value.get("COMP4")).trim());
		data.setCp41(("" + value.get("CP41")).trim());
		data.setCp42(("" + value.get("CP42")).trim());
		data.setCp43(("" + value.get("CP43")).trim());
		data.setCp44(("" + value.get("CP44")).trim());
		data.setCp45(("" + value.get("CP45")).trim());
		data.setComp5(("" + value.get("COMP5")).trim());
		data.setCp51(("" + value.get("CP51")).trim());
		data.setCp52(("" + value.get("CP52")).trim());
		data.setCp53(("" + value.get("CP53")).trim());
		data.setCp54(("" + value.get("CP54")).trim());
		data.setCp55(("" + value.get("CP55")).trim());
		data.setComp6(("" + value.get("COMP6")).trim());
		data.setCp61(("" + value.get("CP61")).trim());
		data.setCp62(("" + value.get("CP62")).trim());
		data.setCp63(("" + value.get("CP63")).trim());
		data.setCp64(("" + value.get("CP64")).trim());
		data.setCp65(("" + value.get("CP65")).trim());
		data.setComp7(("" + value.get("COMP7")).trim());
		data.setCp71(("" + value.get("CP71")).trim());
		data.setCp72(("" + value.get("CP72")).trim());
		data.setCp73(("" + value.get("CP73")).trim());
		data.setCp74(("" + value.get("CP74")).trim());
		data.setCp75(("" + value.get("CP75")).trim());
		data.setComp8(("" + value.get("COMP8")).trim());
		data.setCp81(("" + value.get("CP81")).trim());
		data.setCp82(("" + value.get("CP82")).trim());
		data.setCp83(("" + value.get("CP83")).trim());
		data.setCp84(("" + value.get("CP84")).trim());
		data.setCp85(("" + value.get("CP85")).trim());
		data.setComp9(("" + value.get("COMP9")).trim());
		data.setCp91(("" + value.get("CP91")).trim());
		data.setCp92(("" + value.get("CP92")).trim());
		data.setCp93(("" + value.get("CP93")).trim());
		data.setCp94(("" + value.get("CP94")).trim());
		data.setCp95(("" + value.get("CP95")).trim());
		data.setComp10(("" + value.get("COMP10")).trim());
		data.setCp101(("" + value.get("CP101")).trim());
		data.setCp102(("" + value.get("CP102")).trim());
		data.setCp103(("" + value.get("CP103")).trim());
		data.setCp104(("" + value.get("CP104")).trim());
		data.setCp105(("" + value.get("CP105")).trim());
		data.setDenominati(("" + value.get("DENOMINATIONCOMPLETE")).trim());
		/* ================================================== */
	}

	/* ********************************************************************************
	 * 
	 * Additional Classes
	 */

	/**
	 * @author martin.heinemann@tudor.lu
	 * 
	 * 
	 * @version <br>
	 *          $Log: ImportMdbCefipDrug.java,v $
	 *          Revision 1.4  2013-12-27 18:09:25  donak
	 *          Cleanup of imports
	 *
	 *          Revision 1.3  2013-07-15 06:18:36  ferring
	 *          logging changed
	 *
	 *          Revision 1.2  2011-02-28 15:41:45  troth
	 *          To provide smaller resolutions for the user interface add the navigation bar icons and function bar icons to the user setting "use small icons"
	 * Revision 1.1 2009-05-07
	 *          15:56:26 heinemann import of new cefip file format in ms access.
	 *          using lib jackccess
	 * 
	 *          Revision 1.8 2008-09-25 09:43:06 heinemann fixed copyrights
	 * 
	 *          Revision 1.7 2008-01-15 09:58:54 heinemann better documentation
	 * 
	 *          Revision 1.6 2007/07/19 14:09:59 heinemann *** empty log message
	 *          ***
	 * 
	 *          Revision 1.5 2007/07/03 12:35:29 heinemann system.out removed
	 * 
	 *          Revision 1.4 2007/03/02 08:28:39 hermen initial checkin after
	 *          the merge of PatientModuleRebuild with the main HEAD
	 * 
	 *          Revision 1.3.2.1 2006/12/20 13:47:04 heinemann *** empty log
	 *          message *** <br>
	 *          Revision 1.3 2006/09/13 12:01:00 heinemann <br>
	 *          *** empty log message *** <br>
	 * <br>
	 *          Revision 1.2 2006/09/11 14:40:25 heinemann <br>
	 *          *** empty log message *** <br>
	 * <br>
	 *          Revision 1.1 2006/09/07 13:35:38 heinemann <br>
	 *          many changes <br>
	 */
	class DrugStoringThread extends Thread {

		private Stack<CefipDrugData> stack;
		private CefipDrugManager drugManager;

		private boolean online = true;

		public DrugStoringThread(Stack<CefipDrugData> storeStack) {
			/* ============================================== */
			logger.info("Start Drug Save Thread ");
			this.stack = storeStack;
			// obtain an instance of the session bean
			this.drugManager = CefipDrugListModule.getManager();
			/* ============================================== */
		}

		public void run() {
			/* ========================================== */
			while (true) {
				// if offline and stack is empty
				if (!online && stack.empty())
					break;
				// save the entity
				try {
					CefipDrugData d = stack.pop();
					drugManager.saveImportDrug(d);

				} catch (EmptyStackException e) {
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			logger.info("Thread stopped properly");
			/* ========================================== */
		}

		public void setOnline(boolean b) {
			online = b;
		}

	}
}
