/*******************************************************************************
 * 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.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.cefip.CefipManufacturerData;
import lu.tudor.santec.gecamed.prescription.ejb.session.beans.drug.lists.cefip.CefipDrugManagerBean;
import lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.drug.lists.cefip.CefipDrugManager;

import org.apache.log4j.Logger;

import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.Table;

/**
 * Imports manufacturer from the DBF file that is shipped with the CEFIP list.
 * 
 * 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: ImportMdbCefipManufacturer.java,v $
 *          Revision 1.3  2013-12-27 18:09:25  donak
 *          Cleanup of imports
 *
 *          Revision 1.2  2013-07-15 06:18:36  ferring
 *          logging changed
 *
 *          Revision 1.1  2009-05-07 15:56:26  heinemann
 *          import of new cefip file format in ms access.
 *          using lib jackccess
 *
 *          Revision 1.6  2008-09-25 09:43:06  heinemann
 *          fixed copyrights
 *
 *          Revision 1.5  2008-01-15 09:58:54  heinemann
 *          better documentation
 *
 *          Revision 1.4  2007-11-20 08:58:54  hermen
 *          moved Managerfactory to core.utils and refactured code to use ManagerFactory instead of context.lookup
 *
 *          Revision 1.3  2007/07/03 12:35:29  heinemann
 *          system.out removed
 *
 *          Revision 1.2  2007/03/02 08:28:39  hermen
 *          initial checkin after the merge of PatientModuleRebuild with the main HEAD
 *
 *          Revision 1.1.2.1  2006/12/20 13:47:04  heinemann
 *          *** empty log message ***
 * <br>
 *          Revision 1.1 2006/09/07 13:35:38 heinemann <br>
 *          many changes <br>
 */
public class ImportMdbCefipManufacturer {

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

	private Stack<CefipManufacturerData> manufacturerStack;

	private File mdbFile;


	public ImportMdbCefipManufacturer(File file) {
		/* ============================================ */
		logger.info("Create Manufacturer Importer");
		this.mdbFile = file;
		/* ============================================ */
	}

	/**
	 * Sets the manufacturer text data file name with path
	 * 
	 * @param filename
	 * @throws Exception
	 */
	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 manufacturer file
		 * ----------------------------------------------------------
		 */
		try {
			/* ------------------------------------------------------- */
			Database base   = Database.open(this.mdbFile, true);
			Table table = base.getTable("Four");
			
			table.getRowCount();
			Map<String, Object> value = table.getNextRow();
			boolean returnValue = false;
			/* ------------------------------------------------------- */
			if (value.get("NUM") != null 
					&& value.get("NOM") != null
					&& value.get("AD1") != null)
				returnValue = true;
			
			base.close();
			return returnValue;
			/* ------------------------------------------------------- */
		} catch (IOException e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		return false;
		/* ============================================ */
	}
	
	/**
	 * @return
	 */
	public int getAmount() {
		/* ================================================== */
		int rows = 0;
		try {
			/* ------------------------------------------------------- */
			Database base   = Database.open(this.mdbFile, true);
			Table table = base.getTable("Four");
			
			rows = table.getRowCount();
			
			base.close();
			
			/* ------------------------------------------------------- */
		} catch (IOException e) {
			/* --------------------------------------------- */
			e.printStackTrace();
			/* --------------------------------------------- */
		}
		return rows;
		/* ================================================== */
	}
	

	/**
	 * Here it will all begin. Start the import.
	 */
	// TODO progressBar !!
	public void doImport(JProgressBar progressBar, int count) {
		/* ============================================ */
		// if we have a file
		if (this.mdbFile != null) {
			logger.info("Start atc import");
			/* ---------------------------------------- */
			
			/* ------------------------------------------------------ */
			// set the progressBar
			progressBar.setMaximum(count);
			progressBar.setValue(0);
			/* ------------------------------------------------------ */
			
			List<CefipManufacturerStoringThread> storeThreads = new ArrayList<CefipManufacturerStoringThread>();
			long start = System.currentTimeMillis();
			try {
				/* ------------------------------------------------------ */
				/*
				 * 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 a new stack
				this.manufacturerStack = new Stack<CefipManufacturerData>();
				// create the threads
				// and start them
				for (int i = 0; i < 1; i++) {
					/* ------------------------------------------------ */
					CefipManufacturerStoringThread t = new CefipManufacturerStoringThread(
							manufacturerStack);
					storeThreads.add(t);
					t.start();
					/* ------------------------------------------------ */
				}
				/* ------------------------------------------------------- */
				// start reading
				/* ------------------------------------------------------- */
				// start reading
				Database base = null;
				int a = 0;
				try {
					/* ------------------------------------------------------- */
					// open mdb file
					/* ------------------------------------------------------- */
					base = Database.open(this.mdbFile, true);
					Table table = base.getTable("Four");
					/* ------------------------------------------------------- */
					int rows = table.getRowCount();
					Map<String, Object> value = null;
					// iterate over all rows
					for (int i = 0; i <= rows; i++) {
						/* ------------------------------------------------------- */
						value = table.getNextRow();
						if (value == null)
							continue;
						progressBar.setValue(progressBar.getValue()+a++);
						/* ------------------------------------------------------ */
						// create an CefipManufacturerData object
						CefipManufacturerData md = new CefipManufacturerData();
						md.setNum((""+value.get("NUM")).trim());
						md.setNom((""+value.get("NOM")).trim());
						md.setAd1((""+value.get("AD1")).trim());
						md.setAd2((""+value.get("AD2")).trim());
						md.setSpec((""+value.get("SPEC")).trim());
						md.setDu((""+value.get("DU")).trim());
						md.setAu((""+value.get("AU")).trim());
						
						// push the object to the stack
						this.manufacturerStack.push(md);

						// if the stack has reached a size greater than 20
						// pause the creation of new objects and let the
						// storing threads to their work
						if (manufacturerStack.size() > 20)
							Thread.sleep(15);
						/* ------------------------------------------------------- */
					}
					/* ------------------------------------------------------- */
				} catch (IOException e) {
					/* --------------------------------------------- */
					e.printStackTrace();
					/* --------------------------------------------- */
				}
				
				/* ------------------------------------------------------- */
				// close the file
				/* ---------------------------------------- */
				if (base != null)
					base.close();
				
				/* ------------------------------------------------------- */
			} catch (Exception e) {
				e.printStackTrace();
			}

			// stop the threads
			for (CefipManufacturerStoringThread t : storeThreads) {
				t.setOnline(false);
				try {
					t.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			logger.info("Took " + (System.currentTimeMillis() - start)
					+ "ms to import manufacturers");
			start = System.currentTimeMillis();
			// interconnect the classes
			((CefipDrugManager) ManagerFactory
					.getRemote(CefipDrugManagerBean.class))
					.connectAtcClasses();
			logger.info("Took " + (System.currentTimeMillis() - start)
					+ "ms");
			/* ---------------------------------------- */
		} else
			logger.error("No Manufacturer data list found!");
		/* ============================================ */
	}

	/**
	 * @author martin.heinemann@tudor.lu
	 * 
	 * 
	 * @version <br>
	 *          $Log: ImportMdbCefipManufacturer.java,v $
	 *          Revision 1.3  2013-12-27 18:09:25  donak
	 *          Cleanup of imports
	 *
	 *          Revision 1.2  2013-07-15 06:18:36  ferring
	 *          logging changed
	 *
	 *          Revision 1.1  2009-05-07 15:56:26  heinemann
	 *          import of new cefip file format in ms access.
	 *          using lib jackccess
	 *
	 *          Revision 1.6  2008-09-25 09:43:06  heinemann
	 *          fixed copyrights
	 *
	 *          Revision 1.5  2008-01-15 09:58:54  heinemann
	 *          better documentation
	 *
	 *          Revision 1.4  2007-11-20 08:58:54  hermen
	 *          moved Managerfactory to core.utils and refactured code to use ManagerFactory instead of context.lookup
	 *
	 *          Revision 1.3  2007/07/03 12:35:29  heinemann
	 *          system.out removed
	 *
	 *          Revision 1.2  2007/03/02 08:28:39  hermen
	 *          initial checkin after the merge of PatientModuleRebuild with the main HEAD
	 *
	 *          Revision 1.1.2.1  2006/12/20 13:47:04  heinemann
	 *          *** empty log message ***
	 * <br>
	 *          Revision 1.1 2006/09/07 13:35:38 heinemann <br>
	 *          many changes <br>
	 */
	class CefipManufacturerStoringThread extends Thread {

		private Stack<CefipManufacturerData> stack;
		private CefipDrugManager drugManager;

		private boolean online = true;

		public CefipManufacturerStoringThread(Stack<CefipManufacturerData> storeStack) {
			/* ============================================== */
			logger.info("Start CefipManufacturerData Store Thread ");
			this.stack = storeStack;
			// obtain an instance of the session bean
			this.drugManager = (CefipDrugManager) ManagerFactory
					.getRemote(CefipDrugManagerBean.class);
			/* ============================================== */
		}

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

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

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