/*******************************************************************************
 * 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.dicom.ejb.session.beans;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import lu.tudor.santec.gecamed.core.utils.FileUtils;
import lu.tudor.santec.gecamed.core.utils.ServerConfig;
import lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMEntry;
import lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMImage;
import lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMSeries;
import lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMStudy;
import lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;


/**
 * 
 * 
 *
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @version
 * <br>$Log: DCMManagerBean.java,v $
 * <br>Revision 1.8  2008-09-25 09:43:07  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.7  2008-09-15 10:07:23  hermen
 * <br>fixed import status dialog
 * <br>
 * <br>Revision 1.6  2008-07-10 08:59:17  hermen
 * <br>changed saving of dicom files
 * <br>
 * <br>Revision 1.5  2008-04-09 08:53:42  hermen
 * <br>fixed small possible bugs
 * <br>
 * <br>Revision 1.4  2008-03-28 14:12:20  hermen
 * <br>changed file path handling to new ServerConfiguration and FileUtils classes
 * <br>
 * <br>Revision 1.3  2008-03-05 07:27:39  hermen
 * <br>a lot of improvements and bugfixes
 * <br>
 * <br>Revision 1.2  2008-02-27 08:33:43  hermen
 * <br>new with treetablemodel
 * <br>
 * <br>Revision 1.1  2008-02-26 10:45:51  hermen
 * <br>initial checkin of the dicom module
 * <br>
 *
 */
@Remote({DCMManagerInterface.class})
@Stateless
public class DCMManagerBean implements DCMManagerInterface 
{
    //~ Static fields/initializers =============================================

    private static final long serialVersionUID = 1L;
	
    /**
	 * static logger for this class
	 */
//	private static Logger logger = Logger.getLogger(DCMManagerBean.class
//			.getName());
//    
    @PersistenceContext (unitName="gecam")
	EntityManager em;
    
    @EJB
    LoginInterface	loginBean;

	private String IMAGE_PATH = ServerConfig.getProperty(ServerConfig.DICOM_DIR);
	
    //~ Methods ================================================================

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getStudies(java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public Collection<DCMStudy> getStudies(Integer patientID) throws Exception {
		try {
			Query q = em.createNamedQuery(DCMStudy.findDCMStudiesByPatientID).setParameter("patientID", patientID);
			Collection<DCMStudy> studies = q.getResultList();	
			return  studies;			
		} catch (NoResultException e) {
			return null;
		}	
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getImages(java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public Collection<DCMImage> getImages(Integer seriesID) throws Exception {
		try {
			Query q = em.createNamedQuery(DCMImage.findAllDCMImageBySeriesID).setParameter("seriesID", seriesID);
			Collection<DCMImage> images = q.getResultList();	
			return  images;
		} catch (NoResultException e) {
			return null;
		}	
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getSeries(java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public Collection<DCMSeries> getSeries(Integer studyID) throws Exception {
		try {	
			Query q = em.createNamedQuery(DCMSeries.findAllDCMSeriesByStudyID).setParameter("studyID", studyID);
			Collection<DCMSeries> series = q.getResultList();	
			return  series;
		} catch (NoResultException e) {
			return null;
		}	
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#saveImage(lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMImage)
	 */
	public DCMImage saveImage(DCMImage image, byte[] file) throws Exception {
		saveImageFile(image, file);
		return em.merge(image);
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#saveSeries(lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMSeries)
	 */
	public DCMSeries saveSeries(DCMSeries series) throws Exception {
		return em.merge(series);
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#saveStudy(lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMStudy)
	 */
	public DCMStudy saveStudy(DCMStudy study) throws Exception {
		return em.merge(study);
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getImage(java.lang.String)
	 */
	public DCMImage getImage(String instanceUID) throws Exception {
		try {
			Query q = em.createNamedQuery(DCMImage.findDCMImageByInstanceUID).setParameter("instanceUID", instanceUID);
			return (DCMImage) q.getSingleResult();	
		} catch (NoResultException e) {
			return null;
		}	
	}
	

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getSeries(java.lang.String)
	 */
	public DCMSeries getSeries(String instanceUID) throws Exception {
		try {
			Query q = em.createNamedQuery(DCMSeries.findDCMSeriesByInstanceUID).setParameter("instanceUID", instanceUID);
			return (DCMSeries) q.getSingleResult();	
		} catch (NoResultException e) {
			return null;
		}	
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getStudy(java.lang.String)
	 */
	public DCMStudy getStudy(String instanceUID) throws Exception {
		try {
			Query q = em.createNamedQuery(DCMStudy.findDCMStudyByInstanceUID).setParameter("instanceUID", instanceUID);
			return (DCMStudy) q.getSingleResult();	
		} catch (NoResultException e) {
			return null;
		}	
	}

	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getDCMHistoryTree(java.lang.Integer)
	 */
	@SuppressWarnings({ "unchecked" })
	public Vector<DCMEntry> getDCMHistoryTree(Integer patientID) throws Exception {
		Collection studies = getStudies(patientID);
		for (Iterator iter = studies.iterator(); iter.hasNext();) {
			DCMStudy study = (DCMStudy) iter.next();
			Collection<DCMSeries> series = getSeries(study.getId());
			for (Iterator iter2 = series.iterator(); iter2.hasNext();) {
				DCMSeries serie = (DCMSeries) iter2.next();				
				// get images
				Collection<DCMImage> images = getImages(serie.getId());
				double size = 0;
				DCMImage image = null;
				for (Iterator iter3 = images.iterator(); iter3.hasNext();) {
					image = (DCMImage) iter3.next();
					size += image.getSize();
				}
				try {
					serie.setImageInfos(images.size() + " img, " + image.getCols()+"x"+image.getRows()+"px, " + ((int)(size/1024/1024)) + "Mb.");
					serie.setPreview(images.iterator().next().getPreview());
				} catch (Exception e) {
				}
			}
			study.setChilds(new Vector<DCMEntry>(series));
		}
		return new Vector<DCMEntry>(studies);
	}

	/**
	 * @param dcmImage
	 * @param data
	 * @return
	 * @throws IOException
	 */
	private boolean saveImageFile(DCMImage dcmImage, byte[] data) throws Exception {
		File dir = new File(IMAGE_PATH);
		File f = new File(dir, createFileName(dcmImage));
		if (! f.getParentFile().exists())
		 	f.getParentFile().mkdirs();
		FileUtils.writeFile(data, f);
//		System.out.println(f.getAbsolutePath());
		return true;
	}


	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#getImageFile(lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMImage)
	 */
	public byte[] getImageFile(DCMImage image) throws Exception {
		
		File file = new File(IMAGE_PATH, createFileName(image));
		return FileUtils.readFile(file);
	}


	/**
	 * creates the filename for the image to save.
	 * @param dcmImage
	 * @return the created filename
	 */
	private String createFileName(DCMImage dcmImage) {
		return FileUtils.getPatientDir(dcmImage.getPatientID()) + File.separator  + dcmImage.getSeriesID() + File.separator + dcmImage.getInstanceUID();
	}
	

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#deleteSeries(lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMSeries)
	 */
	public void deleteSeries(DCMSeries series) throws Exception {
		DCMSeries dbSeries = em.find(DCMSeries.class, series.getId());
		Collection<DCMImage> images = getImages(dbSeries.getId());
		for (Iterator<DCMImage> iter = images.iterator(); iter.hasNext();) {
			DCMImage image = (DCMImage) iter.next();
			deleteImage(image);
		}
		em.remove(dbSeries);
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.dicom.ejb.session.interfaces.DCMManagerInterface#deleteStudy(lu.tudor.santec.gecamed.dicom.ejb.entity.beans.DCMStudy)
	 */
	public void deleteStudy(DCMStudy study) throws Exception {
		DCMStudy dbStudy = em.find(DCMStudy.class, study.getId());
		Collection<DCMSeries> series = getSeries(dbStudy.getId());
		for (Iterator<DCMSeries> iter = series.iterator(); iter.hasNext();) {
			DCMSeries serie = (DCMSeries) iter.next();
			deleteSeries(serie);
		}
		em.remove(dbStudy);
	}
	
	/**
	 * delete the dcmimage
	 * @param image
	 * @throws Exception
	 */
	private void deleteImage(DCMImage image) throws Exception {
		DCMImage dbImage = em.find(DCMImage.class, image.getId());
		deleteFile(dbImage);
		em.remove(dbImage);
	}
	
	/**
	 * delete the dicom file for the DCMImage
	 * @param image
	 * @throws Exception
	 */
	private void deleteFile(DCMImage image) throws Exception {
		File file = new File(IMAGE_PATH, createFileName(image));
		if (!FileUtils.deleteFile(file))
			throw new Exception("unable to delete file: "  + file);
		File parent = file.getParentFile();
		    try {
			if (parent.list().length == 0) {
			    parent.delete();
			    if (parent.getParentFile().list().length == 0) {
				    parent.getParentFile().delete();
				}
			}			
		    } catch (Exception e) {
			throw new Exception("unable to delete dir: "  + file.getParent());
		    }
	}
	
}
