/*******************************************************************************
 * 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.ejb.session.beans.drug.lists.cefip;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.AtcClass;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.DrugList;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.IDrug;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.IManufacturer;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.cefip.CefipDrug;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.cefip.CefipDrugData;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.cefip.CefipManufacturer;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.cefip.CefipManufacturerData;
import lu.tudor.santec.gecamed.prescription.ejb.entity.dataclasses.DrugLight;
import lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.drug.lists.cefip.CefipDrugManager;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.LoginBean;

import org.apache.log4j.Category;
import org.jboss.annotation.security.SecurityDomain;

/**
 * 
 * See interface for description
 * 
 * @author martin.heinemann@tudor.lu
 *
 *
 * @version
 * <br>$Log: CefipDrugManagerBean.java,v $
 * <br>Revision 1.15  2013-02-22 08:46:50  kutscheid
 * <br>remove the tupel classes (please redeploy)
 * <br>
 * <br>Revision 1.14  2009-10-06 08:27:01  hermen
 * <br>fixed numberparsing if ',' is delimiter
 * <br>
 * <br>Revision 1.13  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.12  2008-09-25 09:43:10  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.11  2008-01-15 07:43:04  heinemann
 * <br>son doku
 * <br>
 * <br>Revision 1.10  2007/07/03 12:35:29  heinemann
 * <br>system.out removed
 * <br>
 * <br>Revision 1.9  2007/03/13 08:23:04  heinemann
 * <br>printlns removed
 * <br>
 * <br>Revision 1.8  2007/03/09 08:38:22  heinemann
 * <br>sysouts removed
 * <br>
 * <br>Revision 1.7  2007/03/02 08:28:42  hermen
 * <br>initial checkin after the merge of PatientModuleRebuild with the main HEAD
 * <br>
 * <br>Revision 1.6.2.4  2007/02/21 10:00:40  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.6.2.3  2007/02/08 16:45:12  heinemann
 * <br>many changes
 * <br>
 * <br>Revision 1.6.2.2  2007/01/19 10:36:34  heinemann
 * <br>cleaning
 * <br>
 * <br>Revision 1.6.2.1  2006/12/20 13:46:38  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.6  2006/09/27 13:08:28  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.5  2006/09/21 08:50:34  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.4  2006/09/20 11:59:48  heinemann
 * <br>Templates for prescriptions are working now
 * <br>
 * <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>
 */
@SuppressWarnings("unchecked")
@Stateless
@SecurityDomain ("gecamedLoginDS")
public class CefipDrugManagerBean implements CefipDrugManager{

	@PersistenceContext(unitName="gecam")
	EntityManager em;

	private static final Category logger = Category.getInstance(LoginBean.class.getName());

	private static HashMap<String, AtcClass> atcClassesStatic = new HashMap<String, AtcClass>();
	private static HashMap<String, IManufacturer> manufacturerStatic = new HashMap<String, IManufacturer>();

	@RolesAllowed("gecam")
	public void saveManufacturerData(CefipManufacturerData manufacturer) {
		/* ============================================= */
		if (manufacturer != null) {
			em.persist(manufacturer);
		}
		/* ============================================= */
	}



	@RolesAllowed("gecam")
	public void saveImportDrug(CefipDrugData drugData) {
		/* ============================================= */
		if (drugData != null)
			em.persist(drugData);
		/* ============================================= */
	}


	/* **************************************************************
	 *  Some helpfull methods
	 */

	/**
	 * Returns the id of this drug list
	 *
	 * @return
	 */
	@RolesAllowed("gecam")
	public Integer getListId() {
		/* ====================================================== */

		return this.getList().getId();
		/* ====================================================== */
	}

	public DrugList getList() {
		/* ====================================================== */
		Query q = em.createQuery("Select Object(o) FROM DrugList o " +
		"WHERE o.name = :name");

		// set the name
		q.setParameter("name", CefipDrugManager.LIST_NAME);

		DrugList list = (DrugList) q.getSingleResult();

		return list;
		/* ====================================================== */
	}


	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public void deleteAllManufacturer() {
		/* ============================================= */
		long start = System.currentTimeMillis();
		// do the delete procedure in steps of 100,
		// in order to keep an eye on the system memory usage
		Query q = em.createQuery("SELECT Object(o) FROM CefipManufacturerData o");
		q.setMaxResults(100);

		// the result list
		List<CefipManufacturerData> result;
		int count = 0;

		result = q.getResultList();
		while (result != null && result.size() > 0 ) {
			/* ------------------------------------------------------ */
			for (CefipManufacturerData m : result) {
				em.remove(m);
				count++;
			}
			em.flush();
			result = q.getResultList();
			/* ------------------------------------------------------ */
		}
		logger.info("Removed " + count + " manufacturers.");
		logger.info("Deleting Manufacturers took " + (System.currentTimeMillis()-start));
		/* ============================================= */
	}


	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public void deleteAllCefipDrugData() {
		/* ============================================= */

		long start = System.currentTimeMillis();
		// do the delete procedure in steps of 100,
		// in order to keep an eye on the system memory usage
		Query q1 = em.createQuery("SELECT Object(p) FROM CefipDrugData p");


		// the result list

		List<CefipDrugData> result;
		int count = 0;
		result = q1.getResultList();
		/* ------------------------------------------------------ */
		for (CefipDrugData m : result) {
			/* ------------------------------------------------------ */

			em.remove(m);
			count++;
			/* ------------------------------------------------------ */
		}
		
			logger.info("Removed " + count + " drugs.");
			logger.info("Deleting drugs took " + (System.currentTimeMillis()-start));
			/* ------------------------------------------------------ */

		/* ============================================= */
	}


	@RolesAllowed("gecam")
	public ArrayList<Integer> getListCounts() {
		/* ============================================= */
		// the manufacturers
		Query q = em.createQuery("SELECT COUNT(o.id) FROM "+ CefipManufacturerData.class.getName() + " o");

		Integer manufacturer = ((Long) q.getSingleResult()).intValue();

		// the cefip drugs
		Query qc = em.createQuery("SELECT COUNT(o.id) FROM "+CefipDrugData.class.getName() + " o");
		Integer cefips = ((Long) qc.getSingleResult()).intValue();

		// the atc classes
		Query qa = em.createQuery("SELECT COUNT(o.id) FROM " + AtcClass.class.getName() + " o");
		Integer atcs = ((Long) qa.getSingleResult()).intValue();

		// create the tupel
		ArrayList<Integer> arrayList = new ArrayList<Integer>(3);
		arrayList.add(manufacturer);
		arrayList.add(cefips);
		arrayList.add(atcs);
		return arrayList;
		/* ============================================= */
	}

	/**
	 * Saves the current dat for the list
	 *
	 * @param date
	 */
	@RolesAllowed("gecam")
	public void saveListDate(Date date) {
		/* ====================================================== */
		if (date != null) {
			DrugList l = this.getList();
			l.setDate(date);
			em.merge(l);
		}
		/* ====================================================== */
	}



	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.DrugManager#saveImportedAtcClass(lu.tudor.santec.gecamed.prescription.ejb.entity.beans.drug.AtcClass)
	 */
	@RolesAllowed("gecam")
	public void saveImportedCefipAtcClass(AtcClass atc) {
		/* ============================================= */
		if (atc != null) {
			em.persist(atc);
		}
		/* ============================================= */
	}



	/**
	 * creates the parent -> child connection between two atc classes
	 * Must be done after all classes have been imported, because
	 * they do not come in the alphabetical order
	 */
	@SuppressWarnings("unchecked")
		@RolesAllowed("gecam")
	public void connectAtcClasses() {
		/* ====================================================== */
		long start = System.currentTimeMillis();

		Query q = em.createQuery("SELECT Object(o) FROM " + AtcClass.class.getName() +" o");

		List<AtcClass> result = q.getResultList();

		if (result != null && result.size() > 0) {
			/* ------------------------------------------------------ */
			for (AtcClass atc : result) {
				/* ------------------------------------------------------ */
				if (atc.getCode().length() > 1) {
					/* ------------------------------------------------------ */

					/*
					 * The code is build that way
					 * CNNCCNN
					 * The numbers are always a two pair number.
					 * 01,02,11,13
					 * Therefore, if the code has a length of 7, we must delete the last two
					 * digits, the same if we have a length of 3
					 */
					int offset = 0;
					int size = atc.getCode().length();
					/* ------------------------------------------------------ */
					if (size == 7 || size == 3)
						offset = 2;
					else
						offset = 1;
					/* ------------------------------------------------------ */
					// find the parent class in the list
					for (AtcClass c : result) {
						if (c.getCode().equals(atc.getCode()
													.substring(0, atc.getCode().length()-offset))) {
							atc.setParentId(c.getId());
							break;
						}
					}

					em.merge(atc);
					/* ------------------------------------------------------ */
				} // if
				/* ------------------------------------------------------ */
			}// for

			/* ------------------------------------------------------ */
		}
		logger.info("Interconnecting ATC Classes took " + (System.currentTimeMillis()-start)+"ms");

		/* ====================================================== */
	}



	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.drug.lists.cefip.CefipDrugManager#deleteAllCefipAtcClasses()
	 */
	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public void deleteAllCefipAtcClasses() {
		/* ============================================= */
		Query q = em.createQuery("SELECT Object(o) FROM " + AtcClass.class.getName() +" o WHERE o.parent IS null");
		List<AtcClass> result = q.getResultList();

		/* ------------------------------------------------------ */
		if(result != null) {
			/* ------------------------------------------------------ */
			// delete
			for (AtcClass a : result)
				em.remove(a);
			/* ------------------------------------------------------ */
		}
		/* ============================================= */
	}



	public List<DrugLight> getLightDrugsByNamePattern(String pattern, Integer limit) {
		/* ============================================= */
		Query q = em.createQuery(
				"SELECT o.id,o.denom,o.formeclair FROM " + CefipDrugData.class.getName() + " o " +
					"WHERE UPPER(o.denom) LIKE UPPER(:pattern)");
		q.setParameter("pattern", pattern+"%");
		q.setMaxResults(limit);
		/* ------------------------------------------------------ */
		// get the result
		Collection<Object[]> result = q.getResultList();
		// if there is no result, return an empty list
		if (result == null)
			return new ArrayList<DrugLight>();

		/* ------------------------------------------------------ */
		// else, we can assemble the list
		HashMap<String, DrugLight> drugList = new LinkedHashMap<String, DrugLight>();
		for (Object[] orr : result) {
			/* ------------------------------------------------------ */
			if (drugList.containsKey(orr[1])) {
				/* ------------------------------------------------------ */
				// check if the form is identical
				DrugLight parent = drugList.get(orr[1]);
				if (parent.getForm().equals(orr[2])) {
					continue;
				}
				/* ------------------------------------------------------ */
				// check if there is already one with that form
				boolean found = false;

				if (parent.getSubTypes() != null)
					for (DrugLight d1 : parent.getSubTypes()) {
						/* ------------------------------------------------------- */
						if (d1.getForm().equals(orr[2])) {
							found = true;
							break;
						}
						/* ------------------------------------------------------- */
					}
				// if there is a drug with that name and the form, skip to the next
				if (found)
					continue;
				/* ------------------------------------------------------- */
				DrugLight d = new DrugLight();
				d.setDrugId((Integer) orr[0]);
				d.setName((String) orr[1]);
				d.setForm((String) orr[2]);
				d.setListId(this.getListId());
				// set parent
				if (parent.getSubTypes() == null)
					parent.setSubTypes(new ArrayList<DrugLight>());
				parent.getSubTypes().add(d);
				/* ------------------------------------------------------ */

				/* ------------------------------------------------------ */
			} else {
				// create a new DrugLight object
				/* ------------------------------------------------------ */
				DrugLight d = new DrugLight();
				d.setDrugId((Integer) orr[0]);
				d.setName((String) orr[1]);
				d.setForm((String) orr[2]);
				d.setListId(this.getListId());
				drugList.put(d.getName(), d);

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


		List<DrugLight> t = new ArrayList<DrugLight>(drugList.values());
		Collections.sort(t);

		return t;
		/* ============================================= */
	}




	private void initStaticLists() {
		/* ================================================== */
		/**
		 * Preload the lists fpr atc and manucaturers
		 */
		Query q = em.createQuery("SELECT Object (o) FROM AtcClass o");
		List<AtcClass> la = q.getResultList();
		if (la != null)
			for (AtcClass a : la) {
				atcClassesStatic.put(a.getCode(), a);
			}
		/* ------------------------------------------------------- */
		/* ------------------------------------------------------- */
		// Preload manufacturers
		q = em.createQuery("SELECT Object(o) FROM CefipManufacturer o");
		List<CefipManufacturer> lm = q.getResultList();
		if (lm != null)
			for (CefipManufacturer m : lm)
				manufacturerStatic.put(m.getNumber().substring(0, 6), m);

	/* ================================================== */
	}



	/**
	 * @param code
	 * @return
	 */
	private AtcClass getAtcClass(String code) {
		/* ================================================== */

		if (atcClassesStatic.containsKey(code))
			return atcClassesStatic.get(code);
		else
			return null;
		/* ================================================== */
	}

	private IManufacturer getManufacturer(String number) {
		/* ================================================== */
		// the number in the cefip list is 2 chars shorter
		// than the one in the manufacturer list.

		if (manufacturerStatic.containsKey(number))
			return manufacturerStatic.get(number);
		/* ------------------------------------------------------- */
		else
			return null;
		/* ================================================== */
	}



	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.drug.lists.cefip.CefipDrugManager#getDrugs(java.lang.Integer, java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public List<IDrug> getDrugs(Integer start, Integer pageSize) {
		/* ====================================================== */
		// init the static lists
		if (atcClassesStatic.size() == 0)
			initStaticLists();


		Query q = em.createQuery(
				"SELECT " +
				"o.id," +			// 0
				"o.denom," +		// 1
				"o.formeclair," +	// 2
				"o.dosageq1," +		// 3
				"o.dosageu1," +		// 4
				"o.condition," +	// 5
				"o.eurprix," +		// 6
				"o.comp1," +		// 7
				"o.comp2," +		// 8
				"o.comp3," +		// 9
				"o.comp4," +		// 10
				"o.comp5," +		// 11
				"o.comp6," +		// 12
				"o.comp7," +		// 13
				"o.comp8," +		// 14
				"o.comp9," +		// 15
				"o.comp10," +		// 16
				"o.codeatc1," +		// 17
				"o.codeatc2," +		// 18
				"o.codeatc3," +		// 19
				"o.codeatc4," +		// 20
				"o.atcdef," + 		// 21
				"o.titulaire" +		// 22
				" FROM CefipDrugData o ORDER BY o.denom ASC");// +
//						"CefipManufacturerData m " +
//						"WHERE m.num = o.fabricant");
		/* ------------------------------------------------------- */
		q.setFirstResult(start);
		q.setMaxResults(pageSize);
		/* ------------------------------------------------------- */
		List<Object[]> result = q.getResultList();
		/* ------------------------------------------------------- */
		if (result == null)
			return null;
		/* ------------------------------------------------------- */
		List<IDrug> tempList = new ArrayList<IDrug>();
		// construct the objects
		int listId = this.getListId();
		for (Object[] orr : result) {
			/* ------------------------------------------------------- */
			CefipDrug d = new CefipDrug();
			d.setId((Integer) orr[0]);
			d.setName((String) orr[1]);
			d.setDrugListId(listId);
			d.setApplicationForm((String) orr[2]);
			try {
				if (!"0".equals((String) orr[3])) {
					int doseInt = Integer.parseInt((String) orr[3]);
					d.setDose((doseInt/1000) + " " + orr[4]);
				} else
					d.setDose("");
			} catch (Exception e) {
				d.setDose("");
			}
			d.setPackage((String) orr[5]);
			/* ------------------------------------------------------- */
			// price
			try {
				Long l = Long.parseLong((String) orr[6]);
				if (l != 0.0)
					d.setPrice(l / 100.0);
			} catch (Exception e) {
//				e.printStackTrace();
				// try double value
				try {
					/* --------------------------------------------- */
				    	String price = (String) orr[6];
					Double dou = Double.parseDouble(price.replaceAll(",", "."));
					d.setPrice(dou);
					/* --------------------------------------------- */
				} catch (Exception ex) {
					/* --------------------------------------------- */
					logger.error("Error parsing cefip price" , ex);
					d.setPrice(null);
					/* --------------------------------------------- */
				}
			}
			/* ------------------------------------------------------- */
			// substances
			StringBuffer buff = new StringBuffer();
			if (orr[7] != null && !"".equals((String) orr[7])) {
				buff.append(orr[7]);
				for (int i = 8; i <17;i++) {
					if (!"".equals((String) orr[i]))
						/* ------------------------------------------------------- */
						buff.append(", "+orr[i]);
						/* ------------------------------------------------------- */
				}
			}
			d.setSubstances(buff.toString());
			/* ------------------------------------------------------- */
			d.setManufacturer(getManufacturer((String) orr[22]));
//			if (orr[12] != null && !"".equals((String) orr[22])) {
//				CefipManufacturer m = new CefipManufacturer();
//				m.setName((String) orr[22]);
//				d.setManufacturer(m);
//			}
			/* ------------------------------------------------------- */
			// ATC
			// check if valid
			if (orr[21] != null && ((String) orr[21]).equals("Y")) {
				/* ------------------------------------------------------- */
				// assemble the atc codes
				List<AtcClass> atcList = new ArrayList<AtcClass>();
				for (int i = 17; i < 21; i++) {
					/* ------------------------------------------------------- */
					AtcClass c = getAtcClass((String) orr[i]);
					if (c != null)
						atcList.add(c);
					/* ------------------------------------------------------- */
				}
				d.setAtcClasses(atcList);
				/* ------------------------------------------------------- */
			}
			tempList.add(d);
		}
		return tempList;
		/* ====================================================== */
	}




	/* ************************************************************* */
}

















