edu.stanford.epad.epadws.queries.DefaultEpadOperations.java Source code

Java tutorial

Introduction

Here is the source code for edu.stanford.epad.epadws.queries.DefaultEpadOperations.java

Source

/*******************************************************************************
 * Copyright (c) 2015 The Board of Trustees of the Leland Stanford Junior University
 * BY CLICKING ON "ACCEPT," DOWNLOADING, OR OTHERWISE USING EPAD, YOU AGREE TO THE FOLLOWING TERMS AND CONDITIONS:
 * STANFORD ACADEMIC SOFTWARE SOURCE CODE LICENSE FOR
 * "ePAD Annotation Platform for Radiology Images"
 *
 * This Agreement covers contributions to and downloads from the ePAD project ("ePAD") maintained by The Board of Trustees 
 * of the Leland Stanford Junior University ("Stanford"). 
 *
 * *   Part A applies to downloads of ePAD source code and/or data from ePAD. 
 *
 * *   Part B applies to contributions of software and/or data to ePAD (including making revisions of or additions to code 
 * and/or data already in ePAD), which may include source or object code. 
 *
 * Your download, copying, modifying, displaying, distributing or use of any ePAD software and/or data from ePAD 
 * (collectively, the "Software") is subject to Part A. Your contribution of software and/or data to ePAD (including any 
 * that occurred prior to the first publication of this Agreement) is a "Contribution" subject to Part B. Both Parts A and 
 * B shall be governed by and construed in accordance with the laws of the State of California without regard to principles 
 * of conflicts of law. Any legal action involving this Agreement or the Research Program will be adjudicated in the State 
 * of California. This Agreement shall supersede and replace any license terms that you may have agreed to previously with 
 * respect to ePAD.
 *
 * PART A. DOWNLOADING AGREEMENT - LICENSE FROM STANFORD WITH RIGHT TO SUBLICENSE ("SOFTWARE LICENSE").
 * 1. As used in this Software License, "you" means the individual downloading and/or using, reproducing, modifying, 
 * displaying and/or distributing Software and the institution or entity which employs or is otherwise affiliated with you. 
 * Stanford  hereby grants you, with right to sublicense, with respect to Stanford's rights in the Software, a 
 * royalty-free, non-exclusive license to use, reproduce, make derivative works of, display and distribute the Software, 
 * provided that: (a) you adhere to all of the terms and conditions of this Software License; (b) in connection with any 
 * copy, distribution of, or sublicense of all or any portion of the Software, the terms and conditions in this Software 
 * License shall appear in and shall apply to such copy and such sublicense, including without limitation all source and 
 * executable forms and on any user documentation, prefaced with the following words: "All or portions of this licensed 
 * product  have been obtained under license from The Board of Trustees of the Leland Stanford Junior University. and are 
 * subject to the following terms and conditions" AND any user interface to the Software or the "About" information display 
 * in the Software will display the following: "Powered by ePAD http://epad.stanford.edu;" (c) you preserve and maintain 
 * all applicable attributions, copyright notices and licenses included in or applicable to the Software; (d) modified 
 * versions of the Software must be clearly identified and marked as such, and must not be misrepresented as being the 
 * original Software; and (e) you consider making, but are under no obligation to make, the source code of any of your 
 * modifications to the Software freely available to others on an open source basis.
 *
 * 2. The license granted in this Software License includes without limitation the right to (i) incorporate the Software 
 * into your proprietary programs (subject to any restrictions applicable to such programs), (ii) add your own copyright 
 * statement to your modifications of the Software, and (iii) provide additional or different license terms and conditions 
 * in your sublicenses of modifications of the Software; provided that in each case your use, reproduction or distribution 
 * of such modifications otherwise complies with the conditions stated in this Software License.
 * 3. This Software License does not grant any rights with respect to third party software, except those rights that 
 * Stanford has been authorized by a third party to grant to you, and accordingly you are solely responsible for (i) 
 * obtaining any permissions from third parties that you need to use, reproduce, make derivative works of, display and 
 * distribute the Software, and (ii) informing your sublicensees, including without limitation your end-users, of their 
 * obligations to secure any such required permissions.
 * 4. You agree that you will use the Software in compliance with all applicable laws, policies and regulations including, 
 * but not limited to, those applicable to Personal Health Information ("PHI") and subject to the Institutional Review 
 * Board requirements of the your institution, if applicable. Licensee acknowledges and agrees that the Software is not 
 * FDA-approved, is intended only for research, and may not be used for clinical treatment purposes. Any commercialization 
 * of the Software is at the sole risk of you and the party or parties engaged in such commercialization. You further agree 
 * to use, reproduce, make derivative works of, display and distribute the Software in compliance with all applicable 
 * governmental laws, regulations and orders, including without limitation those relating to export and import control.
 * 5. You or your institution, as applicable, will indemnify, hold harmless, and defend Stanford against any third party 
 * claim of any kind made against Stanford arising out of or related to the exercise of any rights granted under this 
 * Agreement, the provision of Software, or the breach of this Agreement. Stanford provides the Software AS IS and WITH ALL 
 * FAULTS.  Stanford makes no representations and extends no warranties of any kind, either express or implied.  Among 
 * other things, Stanford disclaims any express or implied warranty in the Software:
 * (a)  of merchantability, of fitness for a particular purpose,
 * (b)  of non-infringement or 
 * (c)  arising out of any course of dealing.
 *
 * Title and copyright to the Program and any associated documentation shall at all times remain with Stanford, and 
 * Licensee agrees to preserve same. Stanford reserves the right to license the Program at any time for a fee.
 * 6. None of the names, logos or trademarks of Stanford or any of Stanford's affiliates or any of the Contributors, or any 
 * funding agency, may be used to endorse or promote products produced in whole or in part by operation of the Software or 
 * derived from or based on the Software without specific prior written permission from the applicable party.
 * 7. Any use, reproduction or distribution of the Software which is not in accordance with this Software License shall 
 * automatically revoke all rights granted to you under this Software License and render Paragraphs 1 and 2 of this 
 * Software License null and void.
 * 8. This Software License does not grant any rights in or to any intellectual property owned by Stanford or any 
 * Contributor except those rights expressly granted hereunder.
 *
 * PART B. CONTRIBUTION AGREEMENT - LICENSE TO STANFORD WITH RIGHT TO SUBLICENSE ("CONTRIBUTION AGREEMENT").
 * 1. As used in this Contribution Agreement, "you" means an individual providing a Contribution to ePAD and the 
 * institution or entity which employs or is otherwise affiliated with you.
 * 2. This Contribution Agreement applies to all Contributions made to ePAD at any time. By making a Contribution you 
 * represent that: (i) you are legally authorized and entitled by ownership or license to make such Contribution and to 
 * grant all licenses granted in this Contribution Agreement with respect to such Contribution; (ii) if your Contribution 
 * includes any patient data, all such data is de-identified in accordance with U.S. confidentiality and security laws and 
 * requirements, including but not limited to the Health Insurance Portability and Accountability Act (HIPAA) and its 
 * regulations, and your disclosure of such data for the purposes contemplated by this Agreement is properly authorized and 
 * in compliance with all applicable laws and regulations; and (iii) you have preserved in the Contribution all applicable 
 * attributions, copyright notices and licenses for any third party software or data included in the Contribution.
 * 3. Except for the licenses you grant in this Agreement, you reserve all right, title and interest in your Contribution.
 * 4. You hereby grant to Stanford, with the right to sublicense, a perpetual, worldwide, non-exclusive, no charge, 
 * royalty-free, irrevocable license to use, reproduce, make derivative works of, display and distribute the Contribution. 
 * If your Contribution is protected by patent, you hereby grant to Stanford, with the right to sublicense, a perpetual, 
 * worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under your interest in patent rights embodied in 
 * the Contribution, to make, have made, use, sell and otherwise transfer your Contribution, alone or in combination with 
 * ePAD or otherwise.
 * 5. You acknowledge and agree that Stanford ham may incorporate your Contribution into ePAD and may make your 
 * Contribution as incorporated available to members of the public on an open source basis under terms substantially in 
 * accordance with the Software License set forth in Part A of this Agreement. You further acknowledge and agree that 
 * Stanford shall have no liability arising in connection with claims resulting from your breach of any of the terms of 
 * this Agreement.
 * 6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION DOES NOT CONTAIN ANY CODE OBTAINED BY YOU UNDER AN 
 * OPEN SOURCE LICENSE THAT REQUIRES OR PRESCRIBES DISTRBUTION OF DERIVATIVE WORKS UNDER SUCH OPEN SOURCE LICENSE. (By way 
 * of non-limiting example, you will not contribute any code obtained by you under the GNU General Public License or other 
 * so-called "reciprocal" license.)
 *******************************************************************************/
package edu.stanford.epad.epadws.queries;

import ij.ImagePlus;
import ij.io.Opener;
import ij.measure.Calibration;
import ij.process.ImageProcessor;
import ij.process.ImageStatistics;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.XML;

import com.pixelmed.dicom.ImageToDicom;
import com.pixelmed.dicom.SOPClass;
import com.pixelmed.dicom.UIDGenerator;

import edu.stanford.epad.common.dicom.DCM4CHEEImageDescription;
import edu.stanford.epad.common.dicom.DCM4CHEEUtil;
import edu.stanford.epad.common.dicom.DICOMFileDescription;
import edu.stanford.epad.common.pixelmed.PixelMedUtils;
import edu.stanford.epad.common.pixelmed.SegmentedProperty;
import edu.stanford.epad.common.pixelmed.SegmentedPropertyHelper;
import edu.stanford.epad.common.util.EPADConfig;
import edu.stanford.epad.common.util.EPADFileUtils;
import edu.stanford.epad.common.util.EPADLogger;
import edu.stanford.epad.dtos.AnnotationStatus;
import edu.stanford.epad.dtos.EPADAIM;
import edu.stanford.epad.dtos.EPADAIMList;
import edu.stanford.epad.dtos.EPADDSOFrame;
import edu.stanford.epad.dtos.EPADEventLog;
import edu.stanford.epad.dtos.EPADEventLogList;
import edu.stanford.epad.dtos.EPADFile;
import edu.stanford.epad.dtos.EPADFileList;
import edu.stanford.epad.dtos.EPADFrame;
import edu.stanford.epad.dtos.EPADFrameList;
import edu.stanford.epad.dtos.EPADImage;
import edu.stanford.epad.dtos.EPADImageList;
import edu.stanford.epad.dtos.EPADObjectList;
import edu.stanford.epad.dtos.EPADProject;
import edu.stanford.epad.dtos.EPADProjectList;
import edu.stanford.epad.dtos.EPADProjectTemplate;
import edu.stanford.epad.dtos.EPADSeries;
import edu.stanford.epad.dtos.EPADSeriesList;
import edu.stanford.epad.dtos.EPADStudy;
import edu.stanford.epad.dtos.EPADStudyList;
import edu.stanford.epad.dtos.EPADSubject;
import edu.stanford.epad.dtos.EPADSubjectList;
import edu.stanford.epad.dtos.EPADTemplate;
import edu.stanford.epad.dtos.EPADTemplateContainer;
import edu.stanford.epad.dtos.EPADTemplateContainerList;
import edu.stanford.epad.dtos.EPADTemplateUsage;
import edu.stanford.epad.dtos.EPADTemplateUsageList;
import edu.stanford.epad.dtos.EPADUsage;
import edu.stanford.epad.dtos.EPADUsageList;
import edu.stanford.epad.dtos.EPADUser;
import edu.stanford.epad.dtos.EPADUserList;
import edu.stanford.epad.dtos.EPADWorklist;
import edu.stanford.epad.dtos.EPADWorklistList;
import edu.stanford.epad.dtos.EPADWorklistStudy;
import edu.stanford.epad.dtos.EPADWorklistStudyList;
import edu.stanford.epad.dtos.EPADWorklistSubject;
import edu.stanford.epad.dtos.EPADWorklistSubjectList;
import edu.stanford.epad.dtos.SeriesProcessingStatus;
import edu.stanford.epad.dtos.StudyProcessingStatus;
import edu.stanford.epad.dtos.TaskStatus;
import edu.stanford.epad.dtos.internal.DCM4CHEESeries;
import edu.stanford.epad.dtos.internal.DCM4CHEESeriesList;
import edu.stanford.epad.dtos.internal.DCM4CHEEStudy;
import edu.stanford.epad.dtos.internal.DCM4CHEEStudyList;
import edu.stanford.epad.dtos.internal.DICOMElement;
import edu.stanford.epad.dtos.internal.DICOMElementList;
import edu.stanford.epad.dtos.internal.XNATProject;
import edu.stanford.epad.dtos.internal.XNATSubject;
import edu.stanford.epad.dtos.internal.XNATUserList;
import edu.stanford.epad.epadws.aim.AIMQueries;
import edu.stanford.epad.epadws.aim.AIMSearchType;
import edu.stanford.epad.epadws.aim.AIMUtil;
import edu.stanford.epad.epadws.aim.dicomsr.Aim2DicomSRConverter;
import edu.stanford.epad.epadws.dcm4chee.Dcm4CheeDatabase;
import edu.stanford.epad.epadws.dcm4chee.Dcm4CheeDatabaseOperations;
import edu.stanford.epad.epadws.dcm4chee.Dcm4CheeOperations;
import edu.stanford.epad.epadws.epaddb.EpadDatabase;
import edu.stanford.epad.epadws.epaddb.EpadDatabaseOperations;
import edu.stanford.epad.epadws.epaddb.PNGFilesOperations;
import edu.stanford.epad.epadws.handlers.core.EPADSearchFilter;
import edu.stanford.epad.epadws.handlers.core.FrameReference;
import edu.stanford.epad.epadws.handlers.core.ImageReference;
import edu.stanford.epad.epadws.handlers.core.ProjectReference;
import edu.stanford.epad.epadws.handlers.core.SeriesReference;
import edu.stanford.epad.epadws.handlers.core.StudyReference;
import edu.stanford.epad.epadws.handlers.core.SubjectReference;
import edu.stanford.epad.epadws.handlers.dicom.DSOUtil;
import edu.stanford.epad.epadws.models.DisabledTemplate;
import edu.stanford.epad.epadws.models.EpadFile;
import edu.stanford.epad.epadws.models.EpadStatistics;
import edu.stanford.epad.epadws.models.EpadStatisticsMonthly;
import edu.stanford.epad.epadws.models.EpadStatisticsTemplate;
import edu.stanford.epad.epadws.models.Template;
import edu.stanford.epad.epadws.models.EventLog;
import edu.stanford.epad.epadws.models.FileType;
import edu.stanford.epad.epadws.models.NonDicomSeries;
import edu.stanford.epad.epadws.models.Project;
import edu.stanford.epad.epadws.models.ProjectToFile;
import edu.stanford.epad.epadws.models.ProjectToSubjectToStudy;
import edu.stanford.epad.epadws.models.ProjectToSubjectToStudyToSeriesToUserStatus;
import edu.stanford.epad.epadws.models.ProjectToTemplate;
import edu.stanford.epad.epadws.models.ProjectType;
import edu.stanford.epad.epadws.models.Study;
import edu.stanford.epad.epadws.models.Subject;
import edu.stanford.epad.epadws.models.User;
import edu.stanford.epad.epadws.models.UserRole;
import edu.stanford.epad.epadws.models.WorkList;
import edu.stanford.epad.epadws.models.WorkListToStudy;
import edu.stanford.epad.epadws.models.WorkListToSubject;
import edu.stanford.epad.epadws.processing.pipeline.task.DSOEvaluationTask;
import edu.stanford.epad.epadws.processing.pipeline.task.StudyDataDeleteTask;
import edu.stanford.epad.epadws.processing.pipeline.task.SubjectDataDeleteTask;
import edu.stanford.epad.epadws.processing.pipeline.watcher.Dcm4CheeDatabaseWatcher;
import edu.stanford.epad.epadws.security.EPADSession;
import edu.stanford.epad.epadws.security.EPADSessionOperations;
import edu.stanford.epad.epadws.security.IdGenerator;
import edu.stanford.epad.epadws.service.DefaultEpadProjectOperations;
import edu.stanford.epad.epadws.service.DefaultWorkListOperations;
import edu.stanford.epad.epadws.service.EpadProjectOperations;
import edu.stanford.epad.epadws.service.EpadWorkListOperations;
import edu.stanford.epad.epadws.service.UserProjectService;
import edu.stanford.epad.epadws.xnat.XNATDeletionOperations;
import edu.stanford.epad.epadws.xnat.XNATUtil;
import edu.stanford.hakan.aim4api.base.AimException;
import edu.stanford.hakan.aim4api.compability.aimv3.ImageAnnotation;
import edu.stanford.hakan.aim4api.usage.AnnotationValidator;

// TODO Too long - separate in to multiple classes

public class DefaultEpadOperations implements EpadOperations {
    private static final EPADLogger log = EPADLogger.getInstance();

    private static final DefaultEpadOperations ourInstance = new DefaultEpadOperations();

    private final EpadDatabaseOperations epadDatabaseOperations = EpadDatabase.getInstance()
            .getEPADDatabaseOperations();
    private final Dcm4CheeDatabaseOperations dcm4CheeDatabaseOperations = Dcm4CheeDatabase.getInstance()
            .getDcm4CheeDatabaseOperations();
    private final EpadProjectOperations projectOperations = DefaultEpadProjectOperations.getInstance();
    private final EpadWorkListOperations workListOperations = DefaultWorkListOperations.getInstance();

    private DefaultEpadOperations() {
    }

    public static DefaultEpadOperations getInstance() {
        return ourInstance;
    }

    /**
     * Get operations
     */

    @Override
    public EPADProjectList getProjectDescriptions(String username, String sessionID, EPADSearchFilter searchFilter,
            boolean annotationCount, boolean ignoreSystem) throws Exception {
        return getProjectDescriptions(username, sessionID, searchFilter, annotationCount, ignoreSystem, false);
    }

    @Override
    public EPADProjectList getProjectDescriptions(String username, String sessionID, EPADSearchFilter searchFilter,
            boolean annotationCount, boolean ignoreSystem, boolean includeAnnotationStatus) throws Exception {
        if (searchFilter.hasAnnotationMatch())
            annotationCount = true;
        EPADProjectList epadProjectList = new EPADProjectList();
        long starttime = System.currentTimeMillis();
        List<Project> projects = new ArrayList<Project>();
        List projectList = projectOperations.getProjectsForUser(username);
        projectList = projectOperations.sort(projectList, "name", true);
        projects.addAll(projectList);
        long gettime = System.currentTimeMillis();
        for (Project project : projects) {
            if (ignoreSystem && (project.getProjectId().equals(EPADConfig.xnatUploadProjectID) || project
                    .getProjectId().equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))))
                continue;
            EPADProject epadProject = project2EPADProject(sessionID, username, project, searchFilter,
                    annotationCount, includeAnnotationStatus);

            if (epadProject != null) {
                //log.info("project " + epadProject.id + " aim count:" + epadProject.numberOfAnnotations);
                epadProjectList.addEPADProject(epadProject);
            }
        }
        long convtime = System.currentTimeMillis();
        log.info("Time to get " + epadProjectList.ResultSet.totalRecords + " projects:" + (gettime - starttime)
                + " msecs, to convert:" + (convtime - gettime) + " msecs");
        return epadProjectList;
    }

    @Override
    public EPADProject getProjectDescription(ProjectReference projectReference, String username, String sessionID,
            boolean annotationCount) throws Exception {
        return getProjectDescription(projectReference, username, sessionID, annotationCount, false);
    }

    @Override
    public EPADProject getProjectDescription(ProjectReference projectReference, String username, String sessionID,
            boolean annotationCount, boolean includeAnnotationStatus) throws Exception {
        Project project = projectOperations.getProjectForUser(username, projectReference.projectID);
        if (project != null)
            return project2EPADProject(sessionID, username, project, new EPADSearchFilter(), annotationCount,
                    includeAnnotationStatus);
        return null;
    }

    @Override
    public EPADSubjectList getSubjectDescriptions(String projectID, String username, String sessionID,
            EPADSearchFilter searchFilter, int start, int count, String sortField, boolean annotationCount)
            throws Exception {
        return getSubjectDescriptions(projectID, username, sessionID, searchFilter, start, count, sortField,
                annotationCount, false);
    }

    @Override
    public EPADSubjectList getSubjectDescriptions(String projectID, String username, String sessionID,
            EPADSearchFilter searchFilter, int start, int count, String sortField, boolean annotationCount,
            boolean includeAnnotationStatus) throws Exception {
        EPADSubjectList epadSubjectList = new EPADSubjectList();
        List<Subject> subjects = projectOperations.getSubjectsForProject(projectID);
        if (count > 0 && !searchFilter.hasSomeMatchCriteria() && subjects.size() > (start + count)) {
            subjects = subjects.subList(start, start + count);
        }
        if (EPADConfig.xnatUploadProjectID.equals(projectID)) {
            annotationCount = false;
        }
        if (subjects.size() > 300 && !searchFilter.hasAnnotationMatch())
            annotationCount = false;
        for (Subject subject : subjects) {
            EPADSubject epadSubject = subject2EPADSubject(sessionID, username, subject, projectID, searchFilter,
                    annotationCount, includeAnnotationStatus);
            if (epadSubject != null) {
                boolean matchAccessionNumber = true;
                if (searchFilter.hasAccessionNumberMatch()) {
                    matchAccessionNumber = false;
                    Set<String> studyUIDsInXNAT = UserProjectService.getStudyUIDsForSubject(projectID,
                            epadSubject.subjectID);
                    for (String studyUID : studyUIDsInXNAT) {
                        SubjectReference subjectReference = new SubjectReference(projectID, epadSubject.subjectID);
                        EPADStudyList studyList = getStudyDescriptions(subjectReference, username, sessionID,
                                searchFilter);
                        if (studyList.ResultSet.totalRecords > 0) {
                            matchAccessionNumber = true;
                            break;
                        }
                    }
                }
                if (matchAccessionNumber) {
                    //log.info("subject " + epadSubject.subjectID + " aim count:" + epadSubject.numberOfAnnotations);
                    epadSubjectList.addEPADSubject(epadSubject);
                }
            }
        }
        //      if (count > 0 && searchFilter.hasSomeMatchCriteria() && epadSubjectList.ResultSet.Result.size() > (start+count))
        //      {
        //         epadSubjectList.ResultSet.Result = epadSubjectList.ResultSet.Result.subList(start, start+count);
        //      }
        return epadSubjectList;
    }

    @Override
    public EPADSubjectList getWorklistSubjectDescriptions(String projectID, String username, String workListID,
            EPADSearchFilter searchFilter, String sessionID, String sortField) throws Exception {
        EPADSubjectList epadSubjectList = new EPADSubjectList();
        List<Subject> subjects = workListOperations.getSubjectsForWorkList(workListID);
        for (Subject subject : subjects) {
            if (!subject.getProjectID().equals(projectID))
                continue;
            EPADSubject epadSubject = subject2EPADSubject(sessionID, username, subject, projectID, searchFilter,
                    true);
            if (epadSubject != null) {
                boolean matchAccessionNumber = true;
                if (searchFilter.hasAccessionNumberMatch()) {
                    matchAccessionNumber = false;
                    Set<String> studyUIDsInXNAT = UserProjectService.getStudyUIDsForSubject(projectID,
                            epadSubject.subjectID);
                    for (String studyUID : studyUIDsInXNAT) {
                        SubjectReference subjectReference = new SubjectReference(projectID, epadSubject.subjectID);
                        EPADStudyList studyList = getStudyDescriptions(subjectReference, username, sessionID,
                                searchFilter);
                        if (studyList.ResultSet.totalRecords > 0) {
                            matchAccessionNumber = true;
                            break;
                        }
                    }
                }
                if (matchAccessionNumber) {
                    //log.info("subject " + epadSubject.subjectID + " aim count:" + epadSubject.numberOfAnnotations);
                    epadSubjectList.addEPADSubject(epadSubject);
                }
            }
        }
        return epadSubjectList;
    }

    @Override
    public EPADSubjectList getUnassignedSubjectDescriptions(String username, String sessionID,
            EPADSearchFilter searchFilter) throws Exception {
        EPADSubjectList epadSubjectList = new EPADSubjectList();
        List<Subject> subjects = projectOperations.getUnassignSubjects();
        for (Subject subject : subjects) {
            EPADSubject epadSubject = subject2EPADSubject(sessionID, username, subject,
                    EPADConfig.xnatUploadProjectID, searchFilter, false);
            if (epadSubject != null)
                epadSubjectList.addEPADSubject(epadSubject);
        }

        return epadSubjectList;
    }

    public EPADSubject getSubjectDescription(SubjectReference subjectReference, String username, String sessionID)
            throws Exception {
        return getSubjectDescription(subjectReference, username, sessionID, false);
    }

    @Override
    public EPADSubject getSubjectDescription(SubjectReference subjectReference, String username, String sessionID,
            boolean includeAnnotationStatus) throws Exception {

        Subject subject = null;
        if (subjectReference.projectID == null) {
            subject = projectOperations.getSubject(subjectReference.subjectID);
            if (subject != null) {
                //ml for download. no project id. cannot take status
                EPADSubject esubject = subject2EPADSubject(sessionID, username, subject, subjectReference.projectID,
                        new EPADSearchFilter(), true, includeAnnotationStatus);
                return esubject;
            }
        } else {
            subject = projectOperations.getSubjectForProject(subjectReference.projectID,
                    subjectReference.subjectID);

        }
        if (subject != null) {
            EPADSubject esubject = subject2EPADSubject(sessionID, username, subject, subjectReference.projectID,
                    new EPADSearchFilter(), true, includeAnnotationStatus);
            String status = projectOperations.getUserStatusForProjectAndSubject(username,
                    subjectReference.projectID, subjectReference.subjectID);
            esubject.setUserProjectStatus(status);
            return esubject;
        }
        return null;
    }

    @Override
    public EPADStudyList getStudyDescriptions(SubjectReference subjectReference, String username, String sessionID,
            EPADSearchFilter searchFilter) throws Exception {
        return getStudyDescriptions(subjectReference, username, sessionID, searchFilter, false);

    }

    @Override
    public EPADStudyList getStudyDescriptions(String username, String sessionID, Integer days) throws Exception {
        EPADStudyList epadStudyList = new EPADStudyList();
        List<Study> studies = new ArrayList<Study>();
        Subject subject = null;
        Set<String> studyUIDsInEpad = new HashSet<String>();

        studies = projectOperations.getStudiesOlderThanDays(days);
        for (Study study : studies) {
            studyUIDsInEpad.add(study.getStudyUID());
        }
        DCM4CHEEStudyList dcm4CheeStudyList = Dcm4CheeQueries.getStudies(studyUIDsInEpad);

        for (DCM4CHEEStudy dcm4CheeStudy : dcm4CheeStudyList.ResultSet.Result) {
            subject = projectOperations.getSubjectForStudy(dcm4CheeStudy.studyUID);

            List<NonDicomSeries> series = projectOperations.getNonDicomSeriesForStudy(dcm4CheeStudy.studyUID);
            dcm4CheeStudy.seriesCount = dcm4CheeStudy.seriesCount + series.size();
            EPADStudy epadStudy = dcm4cheeStudy2EpadStudy(sessionID, subject.getProjectID(),
                    subject.getSubjectUID(), dcm4CheeStudy, username, false);

            studyUIDsInEpad.remove(epadStudy.studyUID);
            epadStudyList.addEPADStudy(epadStudy);

        }
        for (Study study : studies) {
            if (studyUIDsInEpad.contains(study.getStudyUID())) {
                List<NonDicomSeries> series = projectOperations.getNonDicomSeriesForStudy(study.getStudyUID());
                String firstSeries = "";
                if (series.size() > 0)
                    firstSeries = series.get(0).getSeriesUID();
                String firstSeriesDate = "";
                if (series.size() > 0)
                    firstSeriesDate = dateformat.format(series.get(0).getCreatedTime());
                String desc = "";
                subject = projectOperations.getSubjectForStudy(study.getStudyUID());

                DCM4CHEEStudy dcm4CheeStudy = new DCM4CHEEStudy(study.getStudyUID(), subject.getName(),
                        subject.getSubjectUID(), "", formatDateTime(study.getStudyDate()), 0, series.size(),
                        firstSeries, firstSeriesDate, "", 0, study.getStudyUID(), study.getDescription(), "", "",
                        "");
                EPADStudy epadStudy = dcm4cheeStudy2EpadStudy(sessionID, study.getProjectID(),
                        subject.getSubjectUID(), dcm4CheeStudy, username);
                epadStudyList.addEPADStudy(epadStudy);
            }
        }
        //      for (Study study: studies)
        //      {
        //         
        //            List<NonDicomSeries> series = projectOperations.getNonDicomSeriesForStudy(study.getStudyUID());
        //            String firstSeries = "";
        //            if (series.size() > 0) firstSeries = series.get(0).getSeriesUID();
        //            String firstSeriesDate = "";
        //            if (series.size() > 0) firstSeriesDate = dateformat.format(series.get(0).getCreatedTime());
        //            
        //            subject =projectOperations.getSubjectForStudy(study.getStudyUID());
        //            
        //            DCM4CHEEStudy dcm4CheeStudy = new DCM4CHEEStudy(study.getStudyUID(), subject.getName(),subject.getSubjectUID(), 
        //                  "", formatDateTime(study.getStudyDate()), 
        //                  0, series.size(), firstSeries, firstSeriesDate,
        //                  "", 0, study.getStudyUID(), study.getDescription(), "",
        //                  "", "");
        //            EPADStudy epadStudy = dcm4cheeStudy2EpadStudy(sessionID, study.getProjectID(), subject.getSubjectUID(),
        //                  dcm4CheeStudy, username);
        //            epadStudyList.addEPADStudy(epadStudy);
        //         
        //      }
        return epadStudyList;
    }

    @Override
    public EPADStudyList getStudyDescriptions(SubjectReference subjectReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean includeAnnotationStatus) throws Exception {
        EPADStudyList epadStudyList = new EPADStudyList();
        List<Study> studies = new ArrayList<Study>();
        Subject subject = null;
        Set<String> studyUIDsInEpad = new HashSet<String>();
        subject = projectOperations.getSubject(subjectReference.subjectID);
        boolean unassignedProject = false;
        boolean noProject = false;
        //ml fix for subjects download (null check)
        if (subjectReference.projectID == null) {
            noProject = true;
        } else {
            unassignedProject = subjectReference.projectID
                    .equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"));
        }
        if (unassignedProject || noProject) {
            studies = projectOperations.getStudiesForSubject(subjectReference.subjectID);
        } else {
            studies = projectOperations.getStudiesForProjectAndSubject(subjectReference.projectID,
                    subjectReference.subjectID);

        }
        for (Study study : studies) {
            if (noProject || !unassignedProject
                    || new ProjectToSubjectToStudy().getCount("study_id = " + study.getId()) <= 1)
                studyUIDsInEpad.add(study.getStudyUID());
        }
        DCM4CHEEStudyList dcm4CheeStudyList = Dcm4CheeQueries.getStudies(studyUIDsInEpad);

        for (DCM4CHEEStudy dcm4CheeStudy : dcm4CheeStudyList.ResultSet.Result) {
            //ml+Dev for debugging patient mismatch with dcm4chee
            if (!dcm4CheeStudy.patientID.equals(subjectReference.subjectID)) {
                log.warning("Patient mismatch, Study:" + dcm4CheeStudy.studyUID + " epad patientID:"
                        + subjectReference.subjectID + " dcm4chee patientID:" + dcm4CheeStudy.patientID);
            }
            List<NonDicomSeries> series = projectOperations.getNonDicomSeriesForStudy(dcm4CheeStudy.studyUID);
            dcm4CheeStudy.seriesCount = dcm4CheeStudy.seriesCount + series.size();
            EPADStudy epadStudy = dcm4cheeStudy2EpadStudy(sessionID, subjectReference.projectID,
                    subjectReference.subjectID, dcm4CheeStudy, username, includeAnnotationStatus);
            if (epadStudy.studyDescription != null) {//fill study's description in our db if it exists in dcm4che
                Study dbStudy = projectOperations.getStudy(epadStudy.studyUID);
                if (dbStudy.getDescription() == null || dbStudy.getDescription().equals("")) {
                    dbStudy.setDescription(epadStudy.studyDescription);
                    dbStudy.save();
                }

            }
            studyUIDsInEpad.remove(epadStudy.studyUID);
            boolean filter = searchFilter.shouldFilterStudy(subjectReference.subjectID,
                    epadStudy.studyAccessionNumber, epadStudy.examTypes, epadStudy.numberOfAnnotations);
            if (!filter)
                epadStudyList.addEPADStudy(epadStudy);

        }
        for (Study study : studies) {
            if (studyUIDsInEpad.contains(study.getStudyUID())) {
                List<NonDicomSeries> series = projectOperations.getNonDicomSeriesForStudy(study.getStudyUID());
                String firstSeries = "";
                if (series.size() > 0)
                    firstSeries = series.get(0).getSeriesUID();
                String firstSeriesDate = "";
                if (series.size() > 0)
                    firstSeriesDate = dateformat.format(series.get(0).getCreatedTime());
                String desc = "";
                DCM4CHEEStudy dcm4CheeStudy = new DCM4CHEEStudy(study.getStudyUID(), subject.getName(),
                        subjectReference.subjectID, "", formatDateTime(study.getStudyDate()), 0, series.size(),
                        firstSeries, firstSeriesDate, "", 0, study.getStudyUID(), study.getDescription(), "", "",
                        "");
                EPADStudy epadStudy = dcm4cheeStudy2EpadStudy(sessionID, subjectReference.projectID,
                        subjectReference.subjectID, dcm4CheeStudy, username, includeAnnotationStatus);
                boolean filter = searchFilter.shouldFilterStudy(subjectReference.subjectID,
                        epadStudy.studyAccessionNumber, epadStudy.examTypes, epadStudy.numberOfAnnotations);
                if (!filter)
                    epadStudyList.addEPADStudy(epadStudy);
            }
        }
        return epadStudyList;
    }

    @Override
    public EPADStudy getStudyDescription(StudyReference studyReference, String username, String sessionID)
            throws Exception {
        return getStudyDescription(studyReference, username, sessionID, false);
    }

    @Override
    public EPADStudy getStudyDescription(StudyReference studyReference, String username, String sessionID,
            boolean includeAnnotationStatus) throws Exception {
        boolean found = true;
        String patientID = studyReference.subjectID;
        if (studyReference.projectID != null && patientID != null) {
            found = projectOperations.isStudyInProjectAndSubject(studyReference.projectID, studyReference.subjectID,
                    studyReference.studyUID);
        }

        if (!found) {
            log.warning("Count not find study " + studyReference.studyUID + " for subject "
                    + studyReference.subjectID + " in project " + studyReference.projectID);
            return null;
        } else {
            DCM4CHEEStudy dcm4CheeStudy = Dcm4CheeQueries.getStudy(studyReference.studyUID);
            if (dcm4CheeStudy != null) {
                if (patientID == null)
                    patientID = dcm4CheeStudy.patientID;
                return dcm4cheeStudy2EpadStudy(sessionID, studyReference.projectID, patientID, dcm4CheeStudy,
                        username, includeAnnotationStatus);
            } else {
                log.warning("Count not find dcm4chee study " + studyReference.studyUID + " for subject "
                        + studyReference.subjectID + " in project " + studyReference.projectID);
                return null;
            }
        }
    }

    @Override
    public EPADSeries getSeriesDescription(SeriesReference seriesReference, String username, String sessionID) {
        return getSeriesDescription(seriesReference, username, sessionID, false);

    }

    @Override
    public EPADSeries getSeriesDescription(SeriesReference seriesReference, String username, String sessionID,
            boolean includeAnnotationStatus) {
        String patientID = seriesReference.subjectID;
        DCM4CHEESeries dcm4cheeSeries = Dcm4CheeQueries.getSeries(seriesReference.seriesUID);

        if (dcm4cheeSeries != null) {
            if (patientID == null)
                patientID = dcm4cheeSeries.patientID;
            return dcm4cheeSeries2EpadSeries(sessionID, seriesReference.projectID, patientID, dcm4cheeSeries,
                    username, includeAnnotationStatus);
        } else {
            try {
                NonDicomSeries ndSeries = projectOperations.getNonDicomSeries(seriesReference.seriesUID);
                if (ndSeries != null) {
                    EPADSeries series = new EPADSeries(seriesReference.projectID, seriesReference.subjectID, "",
                            seriesReference.studyUID, ndSeries.getSeriesUID(),
                            dateformat.format(ndSeries.getSeriesDate()), ndSeries.getDescription(), "", "", "", 0,
                            0, 0, "", "", "", null, "", "", "SEG".equalsIgnoreCase(ndSeries.getModality()));
                    series.isNonDicomSeries = true;
                    return series;
                }
            } catch (Exception e) {
                log.warning("Error getting non-dicom series", e);
            }
            log.warning("Could not find series description for series " + seriesReference.seriesUID);
            return null;
        }
    }

    @Override
    public EPADSeriesList getSeriesDescriptions(StudyReference studyReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean filterDSOs) {
        return getSeriesDescriptions(studyReference, username, sessionID, searchFilter, filterDSOs, false);
    }

    @Override
    public EPADSeriesList getSeriesDescriptions(StudyReference studyReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean filterDSOs, boolean includeAnnotationStatus) {
        EPADSeriesList epadSeriesList = new EPADSeriesList();

        DCM4CHEESeriesList dcm4CheeSeriesList = Dcm4CheeQueries.getSeriesInStudy(studyReference.studyUID);
        for (DCM4CHEESeries dcm4CheeSeries : dcm4CheeSeriesList.ResultSet.Result) {
            EPADSeries epadSeries = dcm4cheeSeries2EpadSeries(sessionID, studyReference.projectID,
                    studyReference.subjectID, dcm4CheeSeries, username, includeAnnotationStatus);
            boolean filter = searchFilter.shouldFilterSeries(epadSeries.patientID, epadSeries.patientName,
                    epadSeries.examType, epadSeries.numberOfAnnotations);
            //         log.info("Series:" + epadSeries.seriesDescription + " filterDSO:" + filterDSOs + " isDSO:"+ epadSeries.isDSO + " annotation:"+ epadSeries.annotationStatus.toString());
            if (!filter && !(filterDSOs && epadSeries.isDSO)) {
                if (epadSeries.isDSO) { //bad solution!!
                    //ml filter dsos with no permission
                    log.info("filter");
                    List<EPADAIM> aims = null;
                    if (studyReference.projectID != null && !studyReference.projectID.equals(""))
                        aims = this.epadDatabaseOperations.getAIMsByDSOSeries(studyReference.projectID,
                                epadSeries.seriesUID);
                    else {
                        aims = this.epadDatabaseOperations.getAIMsByDSOSeries(epadSeries.seriesUID);
                        log.info(
                                "No project id. Returning all series for this project. may download dso series that are in other projects");
                    }
                    try {
                        EPADAIMList aimList = AIMUtil.filterPermittedImageAnnotations(new EPADAIMList(aims),
                                username, sessionID, studyReference.projectID);
                        if (aimList != null && aimList.ResultSet.totalRecords != 0) {
                            log.info("putting dso series:" + epadSeries.seriesUID);
                            epadSeriesList.addEPADSeries(epadSeries);
                        }
                    } catch (ParserConfigurationException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (AimException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
                //log.info("Series:" + epadSeries.seriesDescription + " createdtime:" + epadSeries.createdTime);
                else
                    epadSeriesList.addEPADSeries(epadSeries);
            } else if (epadSeries.isDSO) {
                // Check if AIM exists
                List<EPADAIM> aims = this.epadDatabaseOperations.getAIMsByDSOSeries(epadSeries.seriesUID);
                if (aims == null || aims.size() == 0) {
                    log.info("No aim found for DSO:" + epadSeries.seriesUID);
                    Set<DICOMFileDescription> dicomFileDescriptions = dcm4CheeDatabaseOperations
                            .getDICOMFilesForSeries(epadSeries.seriesUID);
                    if (dicomFileDescriptions.size() > 0) {
                        File dsoDICOMFile = null;
                        DICOMFileDescription lastDSO = dicomFileDescriptions.iterator().next();
                        String createdTime = lastDSO.createdTime;
                        for (DICOMFileDescription dicomFileDescription : dicomFileDescriptions) {
                            if (createdTime.compareTo(dicomFileDescription.createdTime) < 0) {
                                createdTime = dicomFileDescription.createdTime;
                                lastDSO = dicomFileDescription;
                            }
                        }
                        String dicomFilePath = EPADConfig.dcm4cheeDirRoot + "/" + lastDSO.filePath;
                        dsoDICOMFile = new File(dicomFilePath);
                        try {
                            List<ImageAnnotation> ias = AIMQueries.getAIMImageAnnotations(AIMSearchType.SERIES_UID,
                                    epadSeries.seriesUID, username, 1, 50);
                            if (ias == null || ias.size() == 0) {
                                AIMUtil.generateAIMFileForDSO(dsoDICOMFile, "shared", studyReference.projectID);
                            }
                            //                     else
                            //                     {
                            //                        log.info("Adding entries to annotations table");
                            //                        Aim aim = new Aim(ias.get(0));
                            //                        ImageReference reference = new ImageReference(epadSeries.projectID, epadSeries.patientID, epadSeries.studyUID, aim.getFirstSeriesID(), aim.getFirstImageID());
                            //                        this.epadDatabaseOperations.addDSOAIM(username, reference, epadSeries.seriesUID, ias.get(0).getUniqueIdentifier());
                            //                     }
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }

            }

        }
        try {
            List<NonDicomSeries> ndSerieses = projectOperations.getNonDicomSeriesForStudy(studyReference.studyUID);
            for (NonDicomSeries ndSeries : ndSerieses) {
                EPADSeries series = new EPADSeries(studyReference.projectID, studyReference.subjectID, "",
                        studyReference.studyUID, ndSeries.getSeriesUID(),
                        dateformat.format(ndSeries.getSeriesDate()), ndSeries.getDescription(), "", "", "", 0, 0, 0,
                        "", "", "", null, "", "", "SEG".equalsIgnoreCase(ndSeries.getModality()));
                series.isNonDicomSeries = true;
                epadSeriesList.addEPADSeries(series);
            }
        } catch (Exception e) {
            log.warning("Error getting non-dicom series", e);
        }
        return epadSeriesList;
    }

    Set<String> seriesInProcess = new HashSet<String>();

    @Override
    public EPADImageList getImageDescriptions(SeriesReference seriesReference, String sessionID,
            EPADSearchFilter searchFilter) {
        List<DCM4CHEEImageDescription> imageDescriptions = dcm4CheeDatabaseOperations
                .getImageDescriptions(seriesReference.studyUID, seriesReference.seriesUID);

        int numImages = imageDescriptions.size();
        if (numImages == 0)
            throw new RuntimeException("This series " + seriesReference.seriesUID + " has no images");
        if (numImages == 1) {
            List<String> pngs = epadDatabaseOperations.getAllPNGLocations(imageDescriptions.get(0).imageUID);
            if (pngs.size() > 1)
                imageDescriptions.get(0).multiFrameImage = true;
        }
        DICOMElementList suppliedDICOMElementsFirst = getDICOMElements(imageDescriptions.get(0).studyUID,
                imageDescriptions.get(0).seriesUID, imageDescriptions.get(0).imageUID);
        String pixelSpacing1 = getDICOMElement(suppliedDICOMElementsFirst, PixelMedUtils.PixelSpacingCode);
        String rows1 = getDICOMElement(suppliedDICOMElementsFirst, PixelMedUtils.RowsCode);
        String columns1 = getDICOMElement(suppliedDICOMElementsFirst, PixelMedUtils.ColumnsCode);

        String modality = getDICOMElement(suppliedDICOMElementsFirst, PixelMedUtils.ModalityCode);
        String sopClassUID = getDICOMElement(suppliedDICOMElementsFirst, PixelMedUtils.SOPClassUIDCode);

        DICOMElementList suppliedDICOMElementsLast = getDICOMElements(imageDescriptions.get(numImages - 1).studyUID,
                imageDescriptions.get(numImages - 1).seriesUID, imageDescriptions.get(numImages - 1).imageUID);
        String pixelSpacing2 = getDICOMElement(suppliedDICOMElementsLast, PixelMedUtils.PixelSpacingCode);
        String rows2 = getDICOMElement(suppliedDICOMElementsLast, PixelMedUtils.RowsCode);
        String columns2 = getDICOMElement(suppliedDICOMElementsLast, PixelMedUtils.ColumnsCode);
        boolean getMetaDataForAllImages = false;
        log.debug("pixelSpacing1:" + pixelSpacing1 + " pixelSpacing2:" + pixelSpacing2);
        //if ultrasound send all the images no need to check the others
        if (modality.equalsIgnoreCase("US") || sopClassUID.equals("1.2.840.10008.5.1.4.1.1.6.1")
                || ((pixelSpacing1 != null && !pixelSpacing1.equals(pixelSpacing2))
                        || (rows1 != null && !rows1.equals(rows2))
                        || (columns1 != null && !columns1.equals(columns2)))) {
            log.info("Series: " + seriesReference.seriesUID + " returning metadata for all images");
            getMetaDataForAllImages = true;
            epadDatabaseOperations.insertEpadEvent(EPADSessionOperations.getSessionUser(sessionID),
                    "This Image may take some time to load. Please do not retry", seriesReference.seriesUID,
                    imageDescriptions.get(0).imageUID, seriesReference.subjectID, seriesReference.subjectID,
                    seriesReference.studyUID, seriesReference.projectID,
                    "Getting Variable Metadata Slices " + imageDescriptions.size());
            seriesInProcess.add(seriesReference.seriesUID);
        }
        DICOMElementList defaultDICOMElements = null;
        EPADImageList epadImageList = new EPADImageList();
        int i = 0;
        boolean isFirst = true;
        for (DCM4CHEEImageDescription dcm4cheeImageDescription : imageDescriptions) {
            i++;
            EPADImage epadImage = null;
            if (isFirst) {
                DICOMElementList suppliedDICOMElements = suppliedDICOMElementsFirst;
                defaultDICOMElements = getDefaultDICOMElements(dcm4cheeImageDescription.studyUID,
                        dcm4cheeImageDescription.seriesUID, dcm4cheeImageDescription.imageUID,
                        suppliedDICOMElements, dcm4cheeImageDescription.instanceNumber,
                        dcm4cheeImageDescription.multiFrameImage);

                epadImage = createEPADImage(seriesReference, dcm4cheeImageDescription, suppliedDICOMElements,
                        defaultDICOMElements);
                log.info(
                        "Returning DICOM metadata, supplied Elements:" + suppliedDICOMElements.getNumberOfElements()
                                + " default Elements:" + defaultDICOMElements.getNumberOfElements());
                epadImage.multiFrameImage = dcm4cheeImageDescription.multiFrameImage;
                epadImageList.addImage(epadImage);
                isFirst = false;
            } else {
                DICOMElementList suppliedDICOMElements = suppliedDICOMElementsFirst;
                // We do not always add DICOM headers to remaining image descriptions because it would be too expensive
                if (getMetaDataForAllImages) {
                    if (i % 300 == 0) {
                        epadDatabaseOperations.insertEpadEvent(EPADSessionOperations.getSessionUser(sessionID),
                                "This Image still being loaded. Please do not retry", seriesReference.seriesUID,
                                imageDescriptions.get(0).imageUID, seriesReference.subjectID,
                                seriesReference.subjectID, seriesReference.studyUID, seriesReference.projectID,
                                "Getting Variable Metadata Slice " + i);
                    }
                    suppliedDICOMElements = replaceSliceSpecificElements(dcm4cheeImageDescription.studyUID,
                            dcm4cheeImageDescription.seriesUID, dcm4cheeImageDescription.imageUID,
                            suppliedDICOMElements);
                    //suppliedDICOMElements = getDICOMElements(dcm4cheeImageDescription.studyUID,
                    //      dcm4cheeImageDescription.seriesUID, dcm4cheeImageDescription.imageUID);            
                    defaultDICOMElements = getDefaultDICOMElements(dcm4cheeImageDescription.studyUID,
                            dcm4cheeImageDescription.seriesUID, dcm4cheeImageDescription.imageUID,
                            suppliedDICOMElements, dcm4cheeImageDescription.instanceNumber);
                    log.info("Getting metadata for image " + i);
                    epadImage = createEPADImage(seriesReference, dcm4cheeImageDescription, suppliedDICOMElements,
                            defaultDICOMElements);
                } else
                    epadImage = createEPADImage(seriesReference, dcm4cheeImageDescription, new DICOMElementList(),
                            new DICOMElementList());
                epadImageList.addImage(epadImage);
            }
            //log.info("Image UID:" + epadImage.imageUID + " LossLess:" + epadImage.losslessImage);
        }
        log.info("Returning image list:" + imageDescriptions.size());
        //return after sorting for correct slice order (using image position and orientation)
        //      epadImageList.sort(); //doesnt work after (first slice should hold dicom info), sort before
        return epadImageList;
    }

    @Override
    public EPADImage getImageDescription(ImageReference imageReference, String sessionID) {
        DCM4CHEEImageDescription dcm4cheeImageDescription = dcm4CheeDatabaseOperations
                .getImageDescription(imageReference);
        List<String> pngs = epadDatabaseOperations.getAllPNGLocations(imageReference.imageUID);
        if (pngs.size() > 1)
            dcm4cheeImageDescription.multiFrameImage = true;
        DICOMElementList suppliedDICOMElements = getDICOMElements(imageReference);
        DICOMElementList defaultDICOMElements = getDefaultDICOMElements(imageReference, suppliedDICOMElements);

        EPADImage eImage = createEPADImage(imageReference, dcm4cheeImageDescription, suppliedDICOMElements,
                defaultDICOMElements);
        eImage.multiFrameImage = dcm4cheeImageDescription.multiFrameImage;
        log.info("Returning DICOM metadata, supplied Elements:" + suppliedDICOMElements.getNumberOfElements()
                + " default Elements:" + defaultDICOMElements.getNumberOfElements());
        return eImage;
    }

    @Override
    public EPADFrameList getFrameDescriptions(ImageReference imageReference) {
        return getFrameDescriptions(imageReference, false, false);

    }

    @Override
    public EPADFrameList getFrameDescriptions(ImageReference imageReference, boolean all, boolean pixelData) {
        if (imageReference.seriesUID.equals("*")) { //ml no series uid. probably dso. fill it!
            imageReference.seriesUID = dcm4CheeDatabaseOperations.getSeriesUIDForImage(imageReference.imageUID);
            log.info("image reference of image " + imageReference.imageUID + " series uid filled with "
                    + imageReference.seriesUID);
        }
        if (imageReference.studyUID.equals("*")) { //ml no study uid. probably dso. fill it!
            imageReference.studyUID = dcm4CheeDatabaseOperations.getStudyUIDForSeries(imageReference.seriesUID);
            log.info("image reference of image " + imageReference.imageUID + " studyUID uid filled with "
                    + imageReference.studyUID);
        }
        DCM4CHEEImageDescription dcm4cheeImageDescription = dcm4CheeDatabaseOperations
                .getImageDescription(imageReference);
        List<EPADFrame> frames = new ArrayList<>();

        if (dcm4cheeImageDescription != null && isDSO(dcm4cheeImageDescription)) {
            log.info("Getting referenced series for DSO, subjectID:" + imageReference.subjectID + " seriesID:"
                    + imageReference.seriesUID + " imageUID:" + imageReference.imageUID);
            SegmentedProperty catTypeProp = new SegmentedProperty();
            DICOMElementList suppliedDICOMElements = getDICOMElements(imageReference, catTypeProp);
            List<DICOMElement> referencedSOPInstanceUIDDICOMElements = getDICOMElementsByCode(suppliedDICOMElements,
                    PixelMedUtils.ReferencedSOPInstanceUIDCode);
            int numberOfFrames = getNumberOfFrames(imageReference.imageUID, suppliedDICOMElements);
            int numberOfSegments = getNumberOfSegments(suppliedDICOMElements);
            log.info("numberOfFrames for " + imageReference.imageUID + ":" + numberOfFrames + " numberOfSegments:"
                    + numberOfSegments);

            if (numberOfFrames > 0 && numberOfSegments < 2) {
                DICOMElement firstDICOMElement = referencedSOPInstanceUIDDICOMElements.get(0);
                String studyUID = imageReference.studyUID; // DSO will be in same study as original images
                String referencedFirstImageUID = firstDICOMElement.value;
                String referencedSeriesUID = dcm4CheeDatabaseOperations
                        .getSeriesUIDForImage(referencedFirstImageUID);
                int i = 1;
                while (referencedSeriesUID == null
                        || referencedSeriesUID.equals("") && i < referencedSOPInstanceUIDDICOMElements.size()) {
                    firstDICOMElement = referencedSOPInstanceUIDDICOMElements.get(i);
                    referencedFirstImageUID = firstDICOMElement.value;
                    referencedSeriesUID = dcm4CheeDatabaseOperations.getSeriesUIDForImage(referencedFirstImageUID);
                    i++;
                }

                if (!referencedSeriesUID.equals("")) {

                    DICOMElementList referencedDICOMElements = getDICOMElements(studyUID, referencedSeriesUID,
                            referencedFirstImageUID);
                    DICOMElementList defaultDICOMElements = getDefaultDICOMElements(imageReference,
                            referencedDICOMElements);
                    boolean isFirst = true;
                    List<DCM4CHEEImageDescription> imageDescriptions = dcm4CheeDatabaseOperations
                            .getImageDescriptions(studyUID, referencedSeriesUID);
                    int instanceOffset = imageDescriptions.size();
                    Map<String, DCM4CHEEImageDescription> descMap = new HashMap<String, DCM4CHEEImageDescription>();
                    for (DCM4CHEEImageDescription imageDescription : imageDescriptions) {
                        descMap.put(imageDescription.imageUID, imageDescription);
                        if (imageDescription.instanceNumber < instanceOffset)
                            instanceOffset = imageDescription.instanceNumber;
                    }
                    List<DCM4CHEEImageDescription> referencedImages = new ArrayList<DCM4CHEEImageDescription>();
                    for (DICOMElement dicomElement : referencedSOPInstanceUIDDICOMElements) {
                        String referencedImageUID = dicomElement.value;
                        DCM4CHEEImageDescription dcm4cheeReferencedImageDescription = descMap
                                .get(referencedImageUID);
                        referencedImages.add(dcm4cheeReferencedImageDescription);
                    }
                    if (instanceOffset == 0)
                        instanceOffset = 1;
                    if (referencedSOPInstanceUIDDICOMElements.size() < imageDescriptions.size())
                        instanceOffset = 1;
                    int index = 0;
                    boolean instanceOneFound = false;
                    int instanceCount = 0;
                    for (DICOMElement dicomElement : referencedSOPInstanceUIDDICOMElements) {
                        String referencedImageUID = dicomElement.value;
                        DCM4CHEEImageDescription dcm4cheeReferencedImageDescription = referencedImages.get(index);
                        index++;
                        if (dcm4cheeReferencedImageDescription == null) {
                            // Note: These referenced images that are not found probably are extra images referenced in the DICOM. 
                            //       There seems to be no way to tell them apart using this PixelMed api - need to use something else
                            log.info("Did not find referenced image, seriesuid:" + referencedSeriesUID
                                    + " imageuid:" + referencedImageUID + " for DSO seriesUID:"
                                    + imageReference.seriesUID + " DSO imageUID:" + imageReference.imageUID);
                            continue;
                        }
                        String insertDate = dcm4cheeReferencedImageDescription.createdTime;
                        String imageDate = dcm4cheeReferencedImageDescription.contentTime;
                        String sliceLocation = dcm4cheeReferencedImageDescription.sliceLocation;
                        int instanceNumber = dcm4cheeReferencedImageDescription.instanceNumber;
                        // In case all instanceNumbers are 1
                        if (instanceNumber == 1 && !instanceOneFound) {
                            instanceOneFound = true;
                            instanceCount = 1;
                        } else if (instanceNumber == 1 && instanceOneFound) {
                            instanceCount++;
                            instanceNumber = instanceCount;
                        }
                        int frameNumber = instanceNumber - instanceOffset; // Frames 0-based, instances 1 or more
                        String losslessImage = getPNGMaskPath(studyUID, imageReference.seriesUID,
                                imageReference.imageUID, frameNumber);
                        String contourImage = "";
                        contourImage = getPNGContourPath(studyUID, imageReference.seriesUID,
                                imageReference.imageUID, frameNumber);
                        String lossyImage = ""; // We do not have a lossy image for the DSO frame
                        String sourceLosslessImage = getPNGPath(studyUID, referencedSeriesUID, referencedImageUID);
                        String sourceLossyImage = getWADOPath(studyUID, referencedSeriesUID, referencedImageUID);
                        //log.info("Frame:" + frameNumber + " losslessImage:" + losslessImage);

                        if (isFirst || all) {
                            EPADDSOFrame frame = new EPADDSOFrame(imageReference.projectID,
                                    imageReference.subjectID, imageReference.studyUID, imageReference.seriesUID,
                                    imageReference.imageUID, insertDate, imageDate, sliceLocation, frameNumber,
                                    losslessImage, lossyImage, suppliedDICOMElements, defaultDICOMElements,
                                    referencedSeriesUID, referencedImageUID, sourceLosslessImage, sourceLossyImage,
                                    catTypeProp.getId(), catTypeProp.getName(), catTypeProp.getDefColor());
                            frames.add(frame);
                            isFirst = false;
                        } else { // We do not add DICOM headers to remaining frame descriptions because it would be too expensive
                            EPADDSOFrame frame = new EPADDSOFrame(imageReference.projectID,
                                    imageReference.subjectID, imageReference.studyUID, imageReference.seriesUID,
                                    imageReference.imageUID, insertDate, imageDate, sliceLocation, frameNumber,
                                    losslessImage, lossyImage, new DICOMElementList(), new DICOMElementList(),
                                    referencedSeriesUID, referencedImageUID, sourceLosslessImage, sourceLossyImage,
                                    catTypeProp.getId(), catTypeProp.getName(), catTypeProp.getDefColor());
                            frames.add(frame);
                        }
                    }
                    log.info("Returning :" + frames.size() + " frames for DSO");
                    return new EPADFrameList(frames);
                } else {
                    log.warning("Could not find original series for DSO image " + imageReference.imageUID
                            + " in series " + imageReference.seriesUID);
                }
            } else if (numberOfFrames > 0 && numberOfSegments > 0) {
                log.debug("Multi-segment DSO frames, numberOfSegment:" + numberOfSegments);
                referencedSOPInstanceUIDDICOMElements = getDICOMElementsByCodeWithParent(suppliedDICOMElements,
                        PixelMedUtils.ReferencedSOPInstanceUIDCode, "Source Image Sequence");
                List<DICOMElement> segmentNumberDICOMElements = getDICOMElementsByCodeWithParent(
                        suppliedDICOMElements, PixelMedUtils.ReferencedSegmentNumberCode,
                        "Segment Identification Sequence");
                log.debug("Number frames:" + numberOfFrames + " referencedUIDs:"
                        + referencedSOPInstanceUIDDICOMElements.size() + " segmenNumbers:"
                        + segmentNumberDICOMElements.size());
                String studyUID = imageReference.studyUID; // DSO will be in same study as original images
                String referencedFirstImageUID = referencedSOPInstanceUIDDICOMElements.get(0).value;
                String referencedSeriesUID = dcm4CheeDatabaseOperations
                        .getSeriesUIDForImage(referencedFirstImageUID);
                if (!referencedSeriesUID.equals("")) {
                    DICOMElementList referencedDICOMElements = getDICOMElements(studyUID, referencedSeriesUID,
                            referencedFirstImageUID);
                    DICOMElementList defaultDICOMElements = getDefaultDICOMElements(imageReference,
                            referencedDICOMElements);
                    boolean isFirst = true;
                    List<DCM4CHEEImageDescription> imageDescriptions = dcm4CheeDatabaseOperations
                            .getImageDescriptions(studyUID, referencedSeriesUID);
                    Map<String, DCM4CHEEImageDescription> descMap = new HashMap<String, DCM4CHEEImageDescription>();
                    for (DCM4CHEEImageDescription imageDescription : imageDescriptions) {
                        descMap.put(imageDescription.imageUID, imageDescription);
                    }
                    List<DCM4CHEEImageDescription> referencedImages = new ArrayList<DCM4CHEEImageDescription>();
                    for (DICOMElement dicomElement : referencedSOPInstanceUIDDICOMElements) {
                        String referencedImageUID = dicomElement.value;
                        DCM4CHEEImageDescription dcm4cheeReferencedImageDescription = descMap
                                .get(referencedImageUID);
                        referencedImages.add(dcm4cheeReferencedImageDescription);
                    }
                    int index = 0;
                    for (DICOMElement dicomElement : referencedSOPInstanceUIDDICOMElements) {
                        String referencedImageUID = dicomElement.value;
                        DCM4CHEEImageDescription dcm4cheeReferencedImageDescription = descMap
                                .get(referencedImageUID);
                        if (dcm4cheeReferencedImageDescription == null) {
                            // Note: These referenced images that are not found probably are extra images referenced in the DICOM. 
                            //       There seems to be no way to tell them apart using this PixelMed api - need to use something else
                            log.info("Did not find referenced image, seriesuid:" + referencedSeriesUID
                                    + " imageuid:" + referencedImageUID + " for DSO seriesUID:"
                                    + imageReference.seriesUID + " DSO imageUID:" + imageReference.imageUID);
                            continue;
                        }
                        String insertDate = dcm4cheeReferencedImageDescription.createdTime;
                        String imageDate = dcm4cheeReferencedImageDescription.contentTime;
                        String sliceLocation = dcm4cheeReferencedImageDescription.sliceLocation;
                        int instanceNumber = dcm4cheeReferencedImageDescription.instanceNumber;
                        int frameNumber = instanceNumber - 1; // Frames 0-based, instances 1 or more
                        String losslessImage = getPNGMaskPath(studyUID, imageReference.seriesUID,
                                imageReference.imageUID, frameNumber, segmentNumberDICOMElements.get(index).value);
                        String contourImage = "";
                        contourImage = getPNGContourPath(studyUID, imageReference.seriesUID,
                                imageReference.imageUID, frameNumber);
                        String lossyImage = ""; // We do not have a lossy image for the DSO frame
                        String sourceLosslessImage = getPNGPath(studyUID, referencedSeriesUID, referencedImageUID);
                        String sourceLossyImage = getWADOPath(studyUID, referencedSeriesUID, referencedImageUID);
                        //log.info("Frame:" + frameNumber + " losslessImage:" + losslessImage);
                        if (isFirst || all) {
                            EPADDSOFrame frame = new EPADDSOFrame(imageReference.projectID,
                                    imageReference.subjectID, imageReference.studyUID, imageReference.seriesUID,
                                    imageReference.imageUID, insertDate, imageDate, sliceLocation, frameNumber,
                                    losslessImage, lossyImage, suppliedDICOMElements, defaultDICOMElements,
                                    referencedSeriesUID, referencedImageUID, sourceLosslessImage, sourceLossyImage,
                                    catTypeProp.getId(), catTypeProp.getName(), catTypeProp.getDefColor());
                            frame.segmentNumber = getInt(segmentNumberDICOMElements.get(index).value);
                            frame.multiSegment = true;
                            frames.add(frame);
                            isFirst = false;
                        } else { // We do not add DICOM headers to remaining frame descriptions because it would be too expensive
                            EPADDSOFrame frame = new EPADDSOFrame(imageReference.projectID,
                                    imageReference.subjectID, imageReference.studyUID, imageReference.seriesUID,
                                    imageReference.imageUID, insertDate, imageDate, sliceLocation, frameNumber,
                                    losslessImage, lossyImage, new DICOMElementList(), new DICOMElementList(),
                                    referencedSeriesUID, referencedImageUID, sourceLosslessImage, sourceLossyImage,
                                    catTypeProp.getId(), catTypeProp.getName(), catTypeProp.getDefColor());
                            frame.segmentNumber = getInt(segmentNumberDICOMElements.get(index).value);
                            frame.multiSegment = true;
                            frames.add(frame);
                        }
                        index++;
                    }
                }
                log.info("Returning :" + frames.size() + " frames for multisegment DSO");
                return new EPADFrameList(frames);
            } else {
                log.warning("Could not find frames for DSO image " + imageReference.imageUID + " in series "
                        + imageReference.seriesUID);
            }
        } else if (dcm4cheeImageDescription == null) {
            try {
                EpadFile file = projectOperations.getEpadFile(null, imageReference.subjectID,
                        imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID);
                // TODO: Return frames for NIFTI??
            } catch (Exception e) {
                log.warning("Error getting file for non-dicom image " + imageReference.imageUID + " in series "
                        + imageReference.seriesUID, e);
            }

        } else { // Multiframe DICOMS (non-DSO)
            List<String> pngs = epadDatabaseOperations.getAllPNGLocations(imageReference.imageUID);
            if (pngs.size() > 1) {
                // Sort by frame number
                for (int i = 0; i < pngs.size(); i++) {
                    for (int j = i; j < pngs.size(); j++) {
                        String pngNamei = pngs.get(i).substring(pngs.get(i).lastIndexOf("/") + 1);
                        int framei = getInt(pngNamei.substring(0, pngNamei.indexOf(".")));
                        String pngNamej = pngs.get(j).substring(pngs.get(j).lastIndexOf("/") + 1);
                        int framej = getInt(pngNamej.substring(0, pngNamej.indexOf(".")));
                        if (framei > framej) {
                            String temp = pngs.get(i);
                            pngs.set(i, pngs.get(j));
                            pngs.set(j, temp);
                        }
                    }
                    //log.debug("png " + i + ":" + pngs.get(i).substring(pngs.get(i).lastIndexOf("/")+1));
                }
                Map<String, String> pixelValues = null;
                if (pixelData) {
                    pixelValues = epadDatabaseOperations.getPixelValues(imageReference.imageUID);
                }
                DICOMElementList suppliedDICOMElements = getDICOMElements(imageReference);
                DICOMElementList defaultDICOMElements = getDefaultDICOMElements(imageReference,
                        suppliedDICOMElements);
                String insertDate = dcm4cheeImageDescription.createdTime;
                String imageDate = dcm4cheeImageDescription.contentTime;
                String sliceLocation = dcm4cheeImageDescription.sliceLocation;
                String lossyImage = getWADOPath(imageReference.studyUID, imageReference.seriesUID,
                        imageReference.imageUID);

                for (int i = 0; i < pngs.size(); i++) {

                    String pixelValue = null;
                    if (pixelData) {
                        pixelValue = pixelValues.get(pngs.get(i));
                    }
                    if (i == 0 || all) {
                        EPADFrame frame = new EPADFrame(imageReference.projectID, imageReference.subjectID,
                                imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID,
                                insertDate, imageDate, sliceLocation, i, pngs.get(i), lossyImage,
                                suppliedDICOMElements, defaultDICOMElements, pixelValue);
                        frames.add(frame);
                    } else { // We do not add DICOM headers to remaining frame descriptions because it would be too expensive
                        EPADFrame frame = new EPADFrame(imageReference.projectID, imageReference.subjectID,
                                imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID,
                                insertDate, imageDate, sliceLocation, i, pngs.get(i), lossyImage,
                                new DICOMElementList(), new DICOMElementList(), pixelValue);
                        frames.add(frame);
                    }
                }
                log.info("Returning :" + frames.size() + " frames for multiframe image");
                return new EPADFrameList(frames);
            } else
                log.warning("Attempt to get frames of non multi-frame image " + imageReference.imageUID
                        + " in series " + imageReference.seriesUID);
        }
        log.info("Returning : 0 frames for DSO");
        return new EPADFrameList();
    }

    private int getInt(String value) {
        try {
            return new Integer(value.trim()).intValue();
        } catch (Exception x) {
            return 0;
        }
    }

    public static List<DICOMElement> getDICOMElementsByCode(DICOMElementList dicomElementList, String tagCode) {
        Set<DICOMElement> matchingDICOMElements = new LinkedHashSet<>(); // Maintain insertion order

        for (DICOMElement dicomElement : dicomElementList.ResultSet.Result) {
            // Do not allow duplicates.
            if (dicomElement.tagCode.equalsIgnoreCase(tagCode) && !matchingDICOMElements.contains(dicomElement))
                matchingDICOMElements.add(dicomElement);
        }

        return new ArrayList<>(matchingDICOMElements);
    }

    public static List<DICOMElement> getDICOMElementsByCodeWithParent(DICOMElementList dicomElementList,
            String tagCode, String parentSequenceName) {
        log.debug("Searching for, tagCode:" + tagCode + " parent:" + parentSequenceName);
        List<DICOMElement> matchingDICOMElements = new ArrayList<DICOMElement>();

        for (DICOMElement dicomElement : dicomElementList.ResultSet.Result) {
            if (dicomElement.tagCode.equalsIgnoreCase(tagCode)
                    && dicomElement.parentSequenceName.equals(parentSequenceName))
                matchingDICOMElements.add(dicomElement);
        }

        return matchingDICOMElements;
    }

    private boolean isDSO(DCM4CHEEImageDescription dcm4cheeImageDescription) {
        return dcm4cheeImageDescription.classUID.equals(SOPClass.SegmentationStorage);
    }

    @Override
    public EPADFrame getFrameDescription(FrameReference frameReference, String sessionID) {
        return getFrameDescription(frameReference, sessionID, false);
    }

    @Override
    public EPADFrame getFrameDescription(FrameReference frameReference, String sessionID, boolean pixelData) {
        ImageReference imageReference = new ImageReference(frameReference.projectID, frameReference.subjectID,
                frameReference.studyUID, frameReference.seriesUID, frameReference.imageUID);
        //basic version use getFrameDescriptions, but getFrameDescriptions handles frame numbers, makes 0 based (pixelmed created 1 based).
        //so using this for now. TODO create specific frame getter for better performance
        EPADFrameList frames = getFrameDescriptions(imageReference, true, pixelData);
        for (EPADFrame frame : frames.ResultSet.Result) {
            if (frame.frameNumber == frameReference.frameNumber)
                return frame;
        }
        return null;

    }

    /**
     * Creation operations
     */

    @Override
    public void createSubjectAndStudy(String username, String projectID, String subjectID, String subjectName,
            String studyUID, String sessionID) throws Exception {
        if (projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned")))
            throw new Exception("Patient can not be added to project:" + projectID);
        projectOperations.createEventLog(username, projectID, subjectID, studyUID, null, null, null,
                "CREATE SUBJECT", subjectName);
        Subject subject = projectOperations.getSubject(subjectID);
        if (subject == null)
            subject = projectOperations.createSubject(username, subjectID, subjectName, null, "");
        projectOperations.createStudy(username, studyUID, subjectID, "", new Date());
    }

    SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMdd");

    @Override
    public EPADSeries createSeries(String username, SeriesReference seriesReference, String description,
            Date seriesDate, String modality, String referencedSeries, String sessionID) throws Exception {
        log.info("Creating new series:" + seriesReference.seriesUID + " description:" + description + " modality:"
                + modality);
        DCM4CHEESeries dcm4CheeSeries = Dcm4CheeQueries.getSeries(seriesReference.seriesUID);
        if (dcm4CheeSeries != null)
            throw new Exception("Series " + seriesReference.seriesUID + " already exists in DCM4CHE");
        String seriesUID = seriesReference.seriesUID;
        if (seriesUID.equalsIgnoreCase("new")) {
            UIDGenerator u = new UIDGenerator();
            seriesUID = u.getNewUID();
            if ("SEG".equals(modality) && (referencedSeries == null || referencedSeries.trim().length() == 0))
                throw new Exception("Segmentation series should specify a referenced Series UID");
        }
        projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID, seriesReference.seriesUID, null, null, "CREATE SERIES",
                description + ":" + seriesDate + ":" + modality);
        if (seriesDate == null)
            seriesDate = new Date();
        NonDicomSeries series = projectOperations.createNonDicomSeries(username, seriesUID,
                seriesReference.studyUID, description, seriesDate, modality, referencedSeries);
        projectOperations.addStudyToProject(username, seriesReference.studyUID, seriesReference.subjectID,
                seriesReference.projectID);
        return new EPADSeries(seriesReference.projectID, seriesReference.subjectID, "", seriesReference.studyUID,
                seriesUID, dateformat.format(seriesDate), description, "", "", "", 0, 0, 0, "", "", "", null, "",
                "", "seg".equalsIgnoreCase(modality));
    }

    @Override
    public void updateSeriesTags(String username, SeriesReference seriesReference, String defaultTags,
            String sessionID) throws Exception {
        epadDatabaseOperations.updateSeriesDefaultTags(seriesReference.seriesUID, defaultTags);
    }

    @Override
    public String seriesDelete(SeriesReference seriesReference, String sessionID, boolean deleteAims,
            String username) throws Exception {
        return this.seriesDelete(seriesReference, sessionID, deleteAims, username, false);
    }

    @Override
    public String seriesDelete(SeriesReference seriesReference, String sessionID, boolean deleteAims,
            String username, boolean all) throws Exception {
        User user = projectOperations.getUser(username);
        if (!user.isAdmin() && !projectOperations.isOwner(username, seriesReference.projectID))
            throw new Exception("No permissions to delete series:" + seriesReference.seriesUID + " in project "
                    + seriesReference.projectID);
        if (!user.isAdmin() && all)
            throw new Exception("No permissions to delete series:" + seriesReference.seriesUID
                    + " from system. You are not admin. Please select delete from project. ");

        try {
            projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                    seriesReference.studyUID, seriesReference.seriesUID, null, null, "DELETE SERIES",
                    "deleteAims:" + deleteAims);
            Set<String> projectIds = UserProjectService.getAllProjectIDs();
            //ml if the user is admin and all is not true check whether the series is in use
            if (!user.isAdmin() || !all) {
                for (String projectId : projectIds) {
                    if (projectId.equals(seriesReference.projectID))
                        continue;
                    if (projectId.equals(EPADConfig.xnatUploadProjectID))
                        continue;
                    if (projectOperations.isOwner(username, projectId))
                        continue;
                    Set<String> allStudyUIDs = UserProjectService.getAllStudyUIDsForProject(projectId);
                    if (allStudyUIDs.contains(seriesReference.studyUID.replace('.', '_'))
                            || allStudyUIDs.contains(seriesReference.studyUID)) {
                        //the user chose to select from project we do not need that anymore. 
                        //should we tell user when we are also deleting from system?
                        return "";
                        //                  log.info("Series " + seriesReference.studyUID + " in use by other projects:" + projectId + ", so series will not be deleted from DCM4CHEE");
                        //                  return "Series " + seriesReference.seriesUID + " in use by other projects:" + projectId + ", so series will not be deleted from DCM4CHEE";
                    }
                }
            }
            return deleteSeries(seriesReference, deleteAims);
        } catch (Exception e) {
            String msg = "Error deleting Series " + seriesReference.seriesUID + " for patient "
                    + seriesReference.subjectID + " in project " + seriesReference.projectID + ", "
                    + e.getMessage();
            log.warning(msg, e);
            return msg;
        }
    }

    public String deleteSeries(SeriesReference seriesReference, boolean deleteAims) {
        String seriesPk = null;
        List<Map<String, String>> seriesList = dcm4CheeDatabaseOperations
                .getAllSeriesInStudy(seriesReference.studyUID);
        for (Map<String, String> seriesData : seriesList) {
            String uid = seriesData.get("series_iuid");
            if (uid.equals(seriesReference.seriesUID)) {
                seriesPk = seriesData.get("pk");
            }
        }
        if (seriesPk == null) {
            log.warning("Series not found in DCM4CHE database, uid:" + seriesReference.seriesUID);
            NonDicomSeries nds;
            try {
                nds = projectOperations.getNonDicomSeries(seriesReference.seriesUID);
                if (nds != null) {
                    projectOperations.deleteNonDicomSeries(seriesReference.seriesUID);
                }
            } catch (Exception e) {
                throw new RuntimeException("Error deleting series:" + e.getMessage());
            }
            epadDatabaseOperations.deleteSeries(seriesReference.seriesUID);
            if (deleteAims)
                deleteAllSeriesAims(seriesReference.seriesUID, false);
            if (nds == null)
                log.warning("Series not found in DCM4CHE database, uid:" + seriesReference.seriesUID);
            return "";
        }
        if (Dcm4CheeOperations.deleteSeries(seriesReference.seriesUID, seriesPk)) {
            epadDatabaseOperations.deleteSeries(seriesReference.seriesUID);
            deleteSeriesPNGs(seriesReference);
            if (deleteAims)
                deleteAllSeriesAims(seriesReference.seriesUID, false);
            return "";
        } else {
            return "Error deleting Series in DCM4CHE database";
        }

    }

    @Override
    public void deleteSeriesPNGs(SeriesReference seriesReference) {
        String pngPath = EPADConfig.getEPADWebServerPNGDir() + "studies/" + seriesReference.studyUID + "/series/"
                + seriesReference.seriesUID + "/images/";
        log.debug("Deleting all files in:" + pngPath);
        File pngDir = new File(pngPath);
        if (pngDir.exists())
            EPADFileUtils.deleteDirectoryAndContents(pngDir);
    }

    @Override
    public void deleteAllSeriesAims(String seriesUID, boolean deleteDSOs) {
        // Delete all Series AIMs
        SeriesReference sref = new SeriesReference(null, null, null, seriesUID);
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(sref);
        for (EPADAIM aim : aims) {
            epadDatabaseOperations.deleteAIM("", aim.aimID);
            AIMUtil.deleteAIM(aim.aimID, aim.projectID);
        }
    }

    @Override
    public void deleteAllAims(String projectID, String subjectID, String studyUID, String seriesUID,
            boolean deleteDSOs) {
        if (projectID == null || projectID.trim().length() == 0)
            return;
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(projectID, subjectID, studyUID, seriesUID);
        for (EPADAIM aim : aims) {
            epadDatabaseOperations.deleteAIM("", aim.aimID);
            AIMUtil.deleteAIM(aim.aimID, aim.projectID);
            if (deleteDSOs && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                this.deleteSeries(new SeriesReference(aim.projectID, aim.subjectID, aim.studyUID, aim.dsoSeriesUID),
                        false);
            }
        }
    }

    @Override
    public Set<String> getExamTypesForSubject(String projectID, String patientID, String sessionID,
            EPADSearchFilter searchFilter) throws Exception {
        Set<String> studyUIDs = UserProjectService.getStudyUIDsForSubject(projectID, patientID);

        Set<String> examTypes = new HashSet<String>();

        for (String studyUID : studyUIDs)
            examTypes.addAll(getExamTypesForStudy(studyUID));

        return examTypes;
    }

    @Override
    public Set<String> getExamTypesForSubject(String patientID) { // Probably could make this a single query to dcm4chee database.
        Set<String> studyUIDs = Dcm4CheeQueries.getStudyUIDsForPatient(patientID);

        Set<String> examTypes = new HashSet<String>();

        for (String studyUID : studyUIDs)
            examTypes.addAll(getExamTypesForStudy(studyUID));

        return examTypes;
    }

    @Override
    public Set<String> getExamTypesForStudy(String studyUID) { // Probably could make this a single query to dcm4chee database.
        DCM4CHEESeriesList dcm4CheeSeriesList = Dcm4CheeQueries.getSeriesInStudy(studyUID);
        Set<String> examTypes = new HashSet<String>();

        for (DCM4CHEESeries dcm4CheeSeries : dcm4CheeSeriesList.ResultSet.Result) {
            examTypes.add(dcm4CheeSeries.examType);
        }
        return examTypes;
    }

    @Override
    public Set<String> getSeriesUIDsForSubject(String projectID, String patientID, String sessionID,
            EPADSearchFilter searchFilter) {
        // Set<String> studyUIDs = XNATQueries.dicomStudyUIDsForSubject(sessionID, projectID, patientID);
        Set<String> studyUIDs = dcm4CheeDatabaseOperations.getStudyUIDsForPatient(patientID);
        Set<String> seriesIDs = new HashSet<String>();

        for (String studyUID : studyUIDs) {
            Set<String> seriesIDsForStudy = dcm4CheeDatabaseOperations.getAllSeriesUIDsInStudy(studyUID);
            seriesIDs.addAll(seriesIDsForStudy);
        }
        return seriesIDs;
    }

    /**
     * Called by {@link Dcm4CheeDatabaseWatcher} to see if new series have been uploaded to DCM4CHEE that ePAD does not
     * know about.
     * <p>
     * We might want to consider getting series from dcm4chee where their upload time (DCM4CHEESeries.createdTime) is
     * after ePAD's processing time (EPADSeries.createdTime), indicating a repeat upload.
     */
    @Override
    public List<DCM4CHEESeries> getNewDcm4CheeSeries() {
        List<DCM4CHEESeries> newDcm4CheeSeries = new ArrayList<DCM4CHEESeries>();

        Set<String> allReadyDcm4CheeSeriesUIDs = dcm4CheeDatabaseOperations.getAllReadyDcm4CheeSeriesUIDs();
        Set<String> allEPADSeriesUIDs = epadDatabaseOperations.getAllSeriesUIDsFromEPadDatabase();
        //log.info("Series in dcm4chee:" + allReadyDcm4CheeSeriesUIDs.size()+ " Series in epad:" + allEPADSeriesUIDs.size());
        allReadyDcm4CheeSeriesUIDs.removeAll(allEPADSeriesUIDs);

        List<String> newSeriesUIDs = new ArrayList<String>(allReadyDcm4CheeSeriesUIDs);
        //if (newSeriesUIDs.size() > 0) log.info("newSeriesUIDs:" + newSeriesUIDs.size());

        for (String seriesUID : newSeriesUIDs) {
            DCM4CHEESeries dcm4CheeSeries = Dcm4CheeQueries.getSeries(seriesUID);
            if (dcm4CheeSeries != null) {
                newDcm4CheeSeries.add(dcm4CheeSeries);
            } else
                log.warning("Could not find new series " + seriesUID + " in dcm4chee");
        }
        return newDcm4CheeSeries;
    }

    @Override
    public Set<String> getDeletedDcm4CheeSeries() {
        Set<String> allReadyDcm4CheeSeriesUIDs = dcm4CheeDatabaseOperations.getAllDcm4CheeSeriesUIDs();
        Set<String> allEPADSeriesUIDs = epadDatabaseOperations.getAllSeriesUIDsFromEPadDatabase();
        //log.info("Series in dcm4chee:" + allReadyDcm4CheeSeriesUIDs.size()+ " Series in epad:" + allEPADSeriesUIDs.size());
        allEPADSeriesUIDs.removeAll(allReadyDcm4CheeSeriesUIDs);

        return allEPADSeriesUIDs;
    }

    @Override
    public Set<DICOMFileDescription> getUnprocessedDICOMFilesInSeries(String seriesUID) {
        Set<DICOMFileDescription> dicomFilesWithoutPNGs = new HashSet<DICOMFileDescription>();

        try {
            // Get list of DICOM file descriptions from DCM4CHEE.
            Set<DICOMFileDescription> dicomFileDescriptions = dcm4CheeDatabaseOperations
                    .getDICOMFilesForSeries(seriesUID);

            // Get list of image UIDs in series for images recorded in ePAD database table epaddb.epad_files.
            Set<String> imageUIDs = epadDatabaseOperations.getImageUIDsInSeries(seriesUID);

            // Make a list of image UIDs that have no entry in ePAD files_table.
            for (DICOMFileDescription dicomFileDescription : dicomFileDescriptions) {
                String modality = dicomFileDescription.modality;
                if ("RTPLAN".equals(modality) || "PR".equals(modality) || "SR".equals(modality))
                    continue; // no images to generate
                if (!imageUIDs.contains(dicomFileDescription.imageUID)) {
                    log.info("ImageUID without png: " + dicomFileDescription.imageUID);
                    dicomFilesWithoutPNGs.add(dicomFileDescription);
                } else if ("SEG".equalsIgnoreCase(dicomFileDescription.modality)) {
                    File dsoFile = new File(EPADConfig.dcm4cheeDirRoot + "/" + dicomFileDescription.filePath);
                    if (!dsoFile.exists()) {
                        try {
                            log.info("Downloading remote DICOM file with image " + dicomFileDescription.imageUID
                                    + " for series UID " + seriesUID);
                            dsoFile = File.createTempFile(dicomFileDescription.imageUID, ".tmp");
                            DCM4CHEEUtil.downloadDICOMFileFromWADO(dicomFileDescription, dsoFile);
                        } catch (Exception e) {
                            log.warning("Exception when downloading DICOM file with series UID " + seriesUID
                                    + " and image UID " + dicomFileDescription.imageUID, e);
                        }

                    }
                    if (PixelMedUtils.isDicomSegmentationObject(dsoFile.getAbsolutePath())) { //check if pixelmed thinks it is a segmentation object (does not support surface segmentation yet)
                        if (!DSOUtil.checkDSOMaskPNGs(dsoFile))
                            dicomFilesWithoutPNGs.add(dicomFileDescription);
                    }
                }
            }
        } catch (Exception e) {
            log.warning("Error finding unprocessed file descriptions: " + e.getMessage(), e);
        }
        return dicomFilesWithoutPNGs;
    }

    @Override
    public Set<DICOMFileDescription> getDICOMFilesInSeries(String seriesUID, String imageUID) {
        Set<DICOMFileDescription> dicomFilesWithoutPNGs = new HashSet<DICOMFileDescription>();

        try {
            // Get list of DICOM file descriptions from DCM4CHEE.
            Set<DICOMFileDescription> dicomFileDescriptions = dcm4CheeDatabaseOperations
                    .getDICOMFilesForSeries(seriesUID);

            // Make a list of image UIDs that have no entry in ePAD files_table.
            for (DICOMFileDescription dicomFileDescription : dicomFileDescriptions) {
                if (imageUID == null || imageUID.equals(dicomFileDescription.imageUID))
                    dicomFilesWithoutPNGs.add(dicomFileDescription);
            }
        } catch (Exception e) {
            log.warning("Error finding DICOM file descriptions: " + e.getMessage(), e);
        }
        return dicomFilesWithoutPNGs;
    }

    @Override
    public int createProject(String username, ProjectReference projectReference, String projectName,
            String projectDescription, String defaultTemplate, String sessionID, ProjectType type)
            throws Exception {
        if (projectReference.projectID == null || projectReference.projectID.trim().length() == 0)
            throw new Exception("Invalid Project ID");
        projectOperations.createEventLog(username, projectReference.projectID, null, null, null, null, null,
                "CREATE PROJECT", projectName + ":" + projectDescription);
        projectOperations.createProject(username, projectReference.projectID, projectName, projectDescription,
                defaultTemplate, type);
        projectOperations.addUserToProject(username, projectReference.projectID, username, UserRole.OWNER,
                defaultTemplate);
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createProject(String username, ProjectReference projectReference, String projectName,
            String projectDescription, String defaultTemplate, String sessionID) throws Exception {
        return createProject(username, projectReference, projectName, projectDescription, defaultTemplate,
                sessionID, ProjectType.PRIVATE);

    }

    @Override
    public int updateProject(String username, ProjectReference projectReference, String projectName,
            String projectDescription, String defaultTemplate, String sessionID, ProjectType type)
            throws Exception {
        projectOperations.createEventLog(username, projectReference.projectID, null, null, null, null, null,
                "UPDATE PROJECT", projectName + ":" + projectDescription);
        if (projectOperations.isOwner(username, projectReference.projectID))
            projectOperations.updateProject(username, projectReference.projectID, projectName, projectDescription,
                    defaultTemplate, type);
        else
            throw new Exception("No privilege to modify project:" + projectReference.projectID);
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int updateProject(String username, ProjectReference projectReference, String projectName,
            String projectDescription, String defaultTemplate, String sessionID) throws Exception {
        //type was null. left the same but why??
        return updateProject(username, projectReference, projectName, projectDescription, defaultTemplate,
                sessionID, null);

    }

    @Override
    public int createSubject(String username, SubjectReference subjectReference, String subjectName, Date dob,
            String gender, String sessionID) throws Exception {
        if (subjectReference.projectID != null && subjectReference.projectID
                .equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned")))
            throw new Exception("Patient can not be added to project:" + subjectReference.projectID);
        if (subjectReference.subjectID == null || subjectReference.subjectID.trim().length() == 0)
            throw new Exception("Invalid Subject ID");
        projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                null, null, null, "CREATE SUBJECT", subjectName + ":" + dob + ":" + gender);
        String subjectID = subjectReference.subjectID;
        if (subjectID.equalsIgnoreCase("new")) {
            IdGenerator idGenerator = new IdGenerator();
            subjectID = idGenerator.generateId(8);
            Subject subject = projectOperations.getSubject(subjectID);
            while (subject != null) {
                subjectID = idGenerator.generateId(8);
                subject = projectOperations.getSubject(subjectID);
            }
        }
        Subject subject = projectOperations.getSubject(subjectID);
        if (subject == null)
            subject = projectOperations.createSubject(username, subjectID, subjectName, null, "");
        if (subjectReference.projectID != null && subjectReference.projectID.length() != 0)
            projectOperations.addSubjectToProject(username, subjectID, subjectReference.projectID);
        if (!EPADConfig.xnatUploadProjectID.equals(subjectReference.projectID))
            projectOperations.addSubjectToProject(username, subjectID, EPADConfig.xnatUploadProjectID);
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int updateSubject(String username, SubjectReference subjectReference, String subjectName, Date dob,
            String gender, String sessionID) throws Exception {
        Subject subject = projectOperations.getSubject(subjectReference.subjectID);
        if (subject == null)
            throw new Exception("Subject " + subjectReference.subjectID + " not found");
        projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                null, null, null, "UPDATE SUBJECT", subjectName + ":" + dob + ":" + gender);
        projectOperations.createSubject(username, subjectReference.subjectID, subjectName, dob, gender);
        projectOperations.addSubjectToProject(username, subjectReference.subjectID, subjectReference.projectID);
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createStudy(String username, StudyReference studyReference, String description, Date studyDate,
            String sessionID) throws Exception {
        if (studyReference.projectID != null
                && studyReference.projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned")))
            throw new Exception("Study can not be added to project:" + studyReference.projectID);
        if (studyReference.studyUID != null && studyReference.studyUID.trim().length() == 0)
            throw new Exception("Invalid Study UID");
        String studyUID = studyReference.studyUID;
        if (studyUID.equalsIgnoreCase("new")) {
            UIDGenerator u = new UIDGenerator();
            studyUID = u.getNewUID();
        }
        Study study = projectOperations.getStudy(studyUID);
        if (study == null) {
            projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                    studyReference.studyUID, null, null, null, "CREATE STUDY", description + ":" + studyDate);
            study = projectOperations.createStudy(username, studyUID, studyReference.subjectID, description,
                    studyDate);
        }
        if (studyReference.projectID != null && studyReference.projectID.length() != 0) {
            projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                    studyReference.studyUID, null, null, null, "ADD STUDY", description + ":" + studyDate);
            log.info("adding study:" + studyUID + " to project:" + studyReference.projectID);
            projectOperations.addStudyToProject(username, studyUID, studyReference.subjectID,
                    studyReference.projectID);
        }
        if (!EPADConfig.xnatUploadProjectID.equals(studyReference.projectID))
            projectOperations.addStudyToProject(username, studyUID, studyReference.subjectID,
                    EPADConfig.xnatUploadProjectID);
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createFile(String username, ProjectReference projectReference, File uploadedFile, String description,
            String fileType, String sessionID) throws Exception {
        if (projectReference.projectID != null && projectReference.projectID
                .equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned")))
            throw new Exception("Files can not be uploaded to this project:" + projectReference.projectID);
        projectOperations.createEventLog(username, projectReference.projectID, null, null, null, null, null,
                "CREATE FILE", description + ":" + fileType);
        if (fileType != null && fileType.equalsIgnoreCase("annotation")) {
            if (AIMUtil.saveAIMAnnotation(uploadedFile, projectReference.projectID, sessionID, username))
                throw new Exception("Error saving AIM file");
        } else {
            createFile(username, projectReference.projectID, null, null, null, uploadedFile, description, fileType,
                    sessionID);
        }
        return HttpServletResponse.SC_OK;
    }

    @Override
    public void createFile(String username, String projectID, String subjectID, String studyID, String seriesID,
            File uploadedFile, String description, String fileType, String sessionID) throws Exception {
        //      String templateLevelType="image";//default
        //fill if template
        Template template = null;

        if (!projectOperations.hasAccessToProject(username, projectID))
            throw new Exception("No permissions to upload to project " + projectID);
        String filename = uploadedFile.getName();
        log.info("filename:" + filename);
        if (filename.startsWith("temp")) {
            int dash = filename.indexOf("-");
            filename = filename.substring(dash + 1);
        }
        if (UserProjectService.isDicomFile(uploadedFile)) {
            createImage(username, projectID, uploadedFile, sessionID);
        } else if (uploadedFile.getName().toLowerCase().endsWith(".zip")) {
            FileType type = null;
            if (fileType != null && fileType.equals(FileType.PARAMETERS.getName())) {
                type = FileType.PARAMETERS;
            }
            if (fileType != null && fileType.equals(FileType.TEMPLATE.getName())) {
                type = FileType.TEMPLATE;
            } else if (fileType != null && fileType.equals(FileType.IMAGE.getName())) {
                type = FileType.IMAGE;
            }
            projectOperations.createFile(username, projectID, subjectID, studyID, seriesID, uploadedFile, filename,
                    description, type);
            log.info("Unzipping " + uploadedFile.getAbsolutePath());
            EPADFileUtils.extractFolder(uploadedFile.getAbsolutePath());
            //to prevent infinite loop for zip uploads
            File parent = uploadedFile.getParentFile();
            File zipDirectory = new File(parent,
                    uploadedFile.getName().substring(0, uploadedFile.getName().length() - 4));
            File[] files1 = zipDirectory.listFiles();
            boolean hasDICOMs = false;
            List<File> files = new ArrayList<File>();
            for (File f : files1) {
                files.add(f);
            }
            for (int i = 0; i < files.size(); i++) {
                File file = files.get(i);
                if (file.isDirectory()) {
                    File[] files2 = file.listFiles();
                    for (File f : files2) {
                        files.add(f);
                    }
                    continue;
                }

                if (!UserProjectService.isDicomFile(file) || file.getName().toLowerCase().endsWith(".zip")) {
                    if (file.getName().toLowerCase().endsWith(".xml"))
                        createFile(username, projectID, subjectID, studyID, seriesID, file, description,
                                FileType.TEMPLATE.getName(), sessionID);
                    else
                        createFile(username, projectID, subjectID, studyID, seriesID, file, description, null,
                                sessionID);
                    file.delete();

                } else {
                    UserProjectService.createProjectEntitiesFromDICOMFile(file, projectID, sessionID, username);
                    hasDICOMs = true;
                }
            }
            uploadedFile.delete();
            if (hasDICOMs)
                Dcm4CheeOperations.dcmsnd(zipDirectory, true);
        } else {
            FileType type = null;
            if (fileType != null && fileType.equals(FileType.PARAMETERS.getName())) {
                type = FileType.PARAMETERS;
            }
            if (fileType != null && fileType.equals(FileType.TEMPLATE.getName())) {
                type = FileType.TEMPLATE;
                if (EPADFileUtils.isImage(uploadedFile) || uploadedFile.getName().toLowerCase().endsWith(".zip"))
                    throw new Exception(
                            "This does not appear to be a template file. The client should check this.");
                //check if the template code exists in the system 
                //            String codeValue=getTemplateCode(uploadedFile);
                //            if (projectOperations.get) {
                //               throw new Exception("Template with code "+ codeValue + " already exists");
                //            }
                if (!EPADFileUtils.isValidXml(uploadedFile, EPADConfig.templateXSDPath)) {
                    String error = EPADFileUtils.validateXml(uploadedFile, EPADConfig.templateXSDPath);
                    if (!(error.contains("content of element 'Template' is not complete")
                            && getTemplateType(uploadedFile).startsWith("SEG")))
                        throw new Exception("Invalid Template file: " + error);
                }
                //read the file and extract a template object, it will be completed and saved after the file is created 
                template = getFirstTemplateInfo(uploadedFile);

                //this should be uncommented once the ui is able to add project template relation from the interface
                //            if (templateExists(template.getTemplateCode()))
                //               throw new Exception("Invalid Template code "+ template.getTemplateCode() +" already exists in the system ");

                projectOperations.createEventLog(username, projectID, subjectID, studyID, seriesID, null, null,
                        uploadedFile.getName(), "UPLOAD TEMPLATE", description, false);
            } else if (fileType != null && fileType.equals(FileType.IMAGE.getName())) {
                type = FileType.IMAGE;
            } else if (EPADFileUtils.isImage(uploadedFile)) {
                type = FileType.IMAGE;
            }
            log.info("filename:" + filename + " type:" + type);
            if (type == null && filename.toLowerCase().endsWith(".xml")) {
                if (EPADFileUtils.isValidXml(uploadedFile, EPADConfig.templateXSDPath)) {
                    type = FileType.TEMPLATE;
                } else if (AnnotationValidator.ValidateXML(uploadedFile.getAbsolutePath(),
                        EPADConfig.xsdFilePathV4)) {
                    type = FileType.ANNOTATION;
                    if (!AIMUtil.saveAIMAnnotation(uploadedFile, projectID, sessionID, username)) {
                        return;
                    } else
                        log.warning("Error saving AIM file to Exist DB:" + uploadedFile.getName());
                } else if (AnnotationValidator.ValidateXML(uploadedFile.getAbsolutePath(),
                        EPADConfig.xsdFilePath)) {
                    type = FileType.ANNOTATION;
                    if (!AIMUtil.saveAIMAnnotation(uploadedFile, projectID, sessionID, username)) {
                        return;
                    } else
                        log.warning("Error saving AIM file to Exist DB:" + uploadedFile.getName());
                }
            }

            if (type == null && PixelMedUtils.isDicomSR(uploadedFile.getAbsolutePath())) {
                log.info("DicomSR found in createFile. processing");
                type = FileType.DICOMSR;
                Aim2DicomSRConverter converter = new Aim2DicomSRConverter();
                String xml = converter.DicomSR2Aim(uploadedFile.getAbsolutePath(), projectID);
                if (xml == null) {
                    log.info("Could not convert from dicom sr");
                } else {
                    String tmpAimName = "/tmp/tmpAim" + System.currentTimeMillis() + ".xml";
                    File tmpAim = new File(tmpAimName);
                    EPADFileUtils.write(tmpAim, xml);
                    log.info("tmp aim path:" + tmpAim.getAbsolutePath());

                    if (AnnotationValidator.ValidateXML(tmpAim.getAbsolutePath(), EPADConfig.xsdFilePath)) {
                        log.info("xml produced from dicom sr is valid");
                        if (AIMUtil.saveAIMAnnotation(tmpAim, projectID, 0, sessionID, username, false, true))
                            log.warning("Error processing aim file:" + uploadedFile.getName());
                    } else
                        log.warning("xml produced from dicom sr is NOT valid");
                }
            }

            EpadFile file = null;
            if (type == null || !type.equals(FileType.TEMPLATE)) {
                projectOperations.createEventLog(username, projectID, subjectID, studyID, seriesID, null, null,
                        uploadedFile.getName(), "UPLOAD FILE", description, false);
                file = projectOperations.createFile(username, projectID, subjectID, studyID, seriesID, uploadedFile,
                        filename, description, type);
            }
            //if it is a template put the file information and create the template entry in db
            if (type != null && fileType != null && fileType.equals(FileType.TEMPLATE.getName())) {
                //temporary fix for uploading same template to different projects. should be removed once the ui is able to add project template relation from the interface
                Template existingTemplate = getTemplate(template.getTemplateCode());
                if (existingTemplate != null) {
                    //two different possibilities; either the user uploaded same file to different projects or uses the same code
                    EpadFile ef = (EpadFile) projectOperations.getDBObject(EpadFile.class,
                            existingTemplate.getFileId());

                    //if same file just remove the extras and put the project relations
                    if (filename.equalsIgnoreCase(ef.getName()) && uploadedFile.length() == ef.getLength()
                            && !projectID.equals(ef.getProjectId())) {
                        log.info("same file for template=" + template.getTemplateName()
                                + " just putting the project relation");
                        file = ef;
                        template = existingTemplate;
                    } else {
                        throw new Exception("Invalid Template code " + template.getTemplateCode()
                                + " already exists in the system ");
                    }
                } else {
                    //get this out of if else once the ui is able to add project template relation from the interface
                    file = projectOperations.createFile(username, projectID, subjectID, studyID, seriesID,
                            uploadedFile, filename, description, type, template.getTemplateLevelType());
                    template.setFileId(file.getId());
                    template.save();
                }

                log.info("template db entry is created for template=" + template.getTemplateName());
                projectOperations.setProjectTemplate(username, projectID, template.getTemplateCode(), true);

            }

            if (type != null && type.equals(FileType.IMAGE) && seriesID != null) {
                NonDicomSeries ndSeries = projectOperations.getNonDicomSeries(seriesID);
                if (ndSeries != null && ndSeries.getReferencedSeries() != null
                        && ndSeries.getReferencedSeries().length() > 0) {
                    try {
                        AIMUtil.generateAIMForNiftiDSO(username, projectID, subjectID, studyID, seriesID,
                                EPADFileUtils.removeExtension(filename), uploadedFile);
                    } catch (Exception x) {
                        log.warning("Error generating Annotation for Nifti DSO", x);
                    }
                    try {
                        DSOUtil.writePNGMasksForNiftiDSO(subjectID, studyID, seriesID,
                                EPADFileUtils.removeExtension(filename), uploadedFile);
                    } catch (Exception x) {
                        log.warning("Error generating PNG masks for Nifti DSO", x);
                    }
                }
            }
            if (type != null && type.equals(FileType.IMAGE) && filename.endsWith(".nii") && !filename
                    .equalsIgnoreCase(EPADConfig.getParamValue("GroundTruthDSOName", "GroundTruth.nii"))) {
                (new Thread(new DSOEvaluationTask(username, projectID, subjectID, studyID, seriesID, filename)))
                        .start();
            }
        }
    }

    private boolean templateExists(String templateCode) throws Exception {
        List<Template> templates = new Template()
                .getObjects("LOWER(templateCode)='" + templateCode.toLowerCase() + "'");
        if (templates != null && !templates.isEmpty())
            return true;
        return false;
    }

    private List<Template> getTemplates(String templateCode) throws Exception {
        List<Template> templates = new Template()
                .getObjects("LOWER(templateCode)='" + templateCode.toLowerCase() + "'");
        if (templates != null && !templates.isEmpty())
            return templates;
        return null;
    }

    private Template getTemplate(String templateCode) throws Exception {
        Template template = (Template) new Template()
                .getObject("LOWER(templateCode)='" + templateCode.toLowerCase() + "'");
        return template;
    }

    private Template getFirstTemplateInfo(File templateFile) {
        Template template = new Template();
        try {
            String xml = EPADFileUtils.readFileAsString(templateFile);
            JSONObject root = XML.toJSONObject(xml);
            JSONObject container = root.getJSONObject("TemplateContainer");
            JSONArray templateObjs = new JSONArray();
            try {
                JSONObject templateObj = container.getJSONObject("Template");
                templateObjs.put(templateObj);
            } catch (Exception x) {
                templateObjs = container.getJSONArray("Template");
            }
            for (int i = 0; i < templateObjs.length(); i++) {
                JSONObject templateObj = templateObjs.getJSONObject(i);
                //extract template information and put it in template
                //returns the first
                template.setTemplateLevelType(templateObj.optString("templateType").toLowerCase());
                if (template.getTemplateLevelType().equals(""))
                    template.setTemplateLevelType("image");
                template.setTemplateUID(templateObj.optString("uid"));

                template.setTemplateName(templateObj.optString("name"));
                template.setAuthors(templateObj.optString("authors"));
                template.setVersion(templateObj.optString("version"));
                template.setTemplateCreationDate(templateObj.optString("creationDate"));
                template.setTemplateDescription(templateObj.optString("description"));
                template.setCodingSchemeVersion(templateObj.optString("codingSchemeVersion"));
                template.setTemplateType(templateObj.optString("codeMeaning"));
                template.setTemplateCode(templateObj.optString("codeValue"));
                template.setCodingSchemeDesignator(templateObj.optString("codingSchemeDesignator"));
                template.setModality(templateObj.optString("modality"));
                return template;
            }
        } catch (Exception x) {
        }
        return template;
    }

    private String getTemplateType(File templateFile) {
        try {
            String xml = EPADFileUtils.readFileAsString(templateFile);
            JSONObject root = XML.toJSONObject(xml);
            JSONObject container = root.getJSONObject("TemplateContainer");
            JSONArray templateObjs = new JSONArray();
            try {
                JSONObject templateObj = container.getJSONObject("Template");
                templateObjs.put(templateObj);
            } catch (Exception x) {
                templateObjs = container.getJSONArray("Template");
            }
            for (int i = 0; i < templateObjs.length(); i++) {
                JSONObject templateObj = templateObjs.getJSONObject(i);
                return templateObj.getString("codeMeaning");
            }
        } catch (Exception x) {
        }
        return "";
    }

    private String getTemplateLevelType(File templateFile) {
        try {
            String xml = EPADFileUtils.readFileAsString(templateFile);
            JSONObject root = XML.toJSONObject(xml);
            JSONObject container = root.getJSONObject("TemplateContainer");
            JSONArray templateObjs = new JSONArray();
            try {
                JSONObject templateObj = container.getJSONObject("Template");
                templateObjs.put(templateObj);
            } catch (Exception x) {
                templateObjs = container.getJSONArray("Template");
            }
            for (int i = 0; i < templateObjs.length(); i++) {
                JSONObject templateObj = templateObjs.getJSONObject(i);
                if (templateObj != null && templateObj.getString("templateType") != null)
                    return templateObj.getString("templateType").toLowerCase();
                return "image";
            }
        } catch (Exception x) {
        }
        return "";
    }

    @Override
    public int createFile(String username, SubjectReference subjectReference, File uploadedFile, String description,
            String fileType, String sessionID) throws Exception {
        projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                null, null, null, uploadedFile.getName(), "CREATE FILE", description + ":" + fileType, false);
        if (fileType != null && fileType.equalsIgnoreCase(FileType.ANNOTATION.getName())) {
            if (AIMUtil.saveAIMAnnotation(uploadedFile, subjectReference.projectID, sessionID, username))
                throw new Exception("Error saving AIM file");
        } else {
            createFile(username, subjectReference.projectID, subjectReference.subjectID, null, null, uploadedFile,
                    description, fileType, sessionID);
        }
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createFile(String username, StudyReference studyReference, File uploadedFile, String description,
            String fileType, String sessionID) throws Exception {
        projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                studyReference.studyUID, null, null, null, uploadedFile.getName(), "CREATE FILE",
                description + ":" + fileType, false);
        if (fileType != null && fileType.equalsIgnoreCase(FileType.ANNOTATION.getName())) {
            if (AIMUtil.saveAIMAnnotation(uploadedFile, studyReference.projectID, sessionID, username))
                throw new Exception("Error saving AIM file");
        } else {
            createFile(username, studyReference.projectID, studyReference.subjectID, studyReference.studyUID, null,
                    uploadedFile, description, fileType, sessionID);
        }
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createFile(String username, SeriesReference seriesReference, File uploadedFile, String description,
            String fileType, String sessionID) throws Exception {
        projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID, seriesReference.seriesUID, null, null, uploadedFile.getName(),
                "CREATE FILE", description + ":" + fileType, false);
        return createFile(username, seriesReference, uploadedFile, description, fileType, sessionID, false, null,
                null);
    }

    @Override
    public int createFile(String username, SeriesReference seriesReference, File uploadedFile, String description,
            String fileType, String sessionID, boolean convertToDICOM, String modality, String instanceNumber)
            throws Exception {
        projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID, seriesReference.seriesUID, null, null, uploadedFile.getName(),
                "CREATE FILE", description + ":" + fileType + ":" + modality, false);
        if (fileType != null && fileType.equalsIgnoreCase(FileType.ANNOTATION.getName())) {
            if (AIMUtil.saveAIMAnnotation(uploadedFile, seriesReference.projectID, sessionID, username))
                throw new Exception("Error saving AIM file");
        } else {
            if (convertToDICOM) {
                Subject subject = projectOperations.getSubject(seriesReference.subjectID);
                String patientName = "";
                if (subject != null)
                    patientName = subject.getName();
                // TODO: use modality
                File dicomFile = new File(replaceExtension(uploadedFile.getAbsolutePath(), "dcm"));
                new ImageToDicom(uploadedFile.getAbsolutePath(), dicomFile.getAbsolutePath(), patientName,
                        seriesReference.seriesUID, seriesReference.studyUID, seriesReference.seriesUID,
                        instanceNumber);
                uploadedFile.delete();
                createImage(username, seriesReference.projectID, dicomFile, sessionID);
            } else {
                createFile(username, seriesReference.projectID, seriesReference.subjectID, seriesReference.studyUID,
                        seriesReference.seriesUID, uploadedFile, description, fileType, sessionID);
            }
        }
        return HttpServletResponse.SC_OK;
    }

    private String replaceExtension(String filePath, String newExt) {
        int dot = filePath.lastIndexOf(".");
        if (dot != -1)
            filePath = filePath.substring(0, dot);
        filePath = filePath + "." + newExt;
        return filePath;
    }

    @Override
    public int createFile(String username, ImageReference imageReference, File uploadedFile, String description,
            String fileType, String sessionID) throws Exception {
        projectOperations.createEventLog(username, imageReference.projectID, imageReference.subjectID,
                imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID, null,
                uploadedFile.getName(), "CREATE FILE", description + ":" + fileType, false);
        if (fileType != null && fileType.equalsIgnoreCase(FileType.ANNOTATION.getName())) {
            if (AIMUtil.saveAIMAnnotation(uploadedFile, imageReference.projectID, sessionID, username))
                throw new Exception("Error saving AIM file");
        } else {
            createFile(username, imageReference.projectID, imageReference.subjectID, imageReference.studyUID, null,
                    uploadedFile, description, fileType, sessionID);
        }
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createImage(String username, String projectID, File dicomFile, String sessionID) throws Exception {
        projectOperations.createEventLog(username, projectID, null, null, null, null, null, dicomFile.getName(),
                "UPLOAD DICOM", dicomFile.getName(), false);
        if (UserProjectService.isDicomFile(dicomFile)) {
            UserProjectService.createProjectEntitiesFromDICOMFile(dicomFile, projectID, sessionID, username);
            Dcm4CheeOperations.dcmsnd(dicomFile.getParentFile(), true);
        } else
            throw new Exception("Invalid DICOM file");
        return HttpServletResponse.SC_OK;
    }

    @Override
    public int createSystemTemplate(String username, File templateFile, String sessionID) throws Exception {
        projectOperations.createEventLog(username, null, null, null, null, null, null, "CREATE SYSTEM TEMPLATE",
                templateFile.getName());
        if (!EPADFileUtils.isValidXml(templateFile, EPADConfig.templateXSDPath))
            throw new Exception("Invalid Template file:" + templateFile.getName());
        FileUtils.copyFileToDirectory(templateFile, new File(EPADConfig.getEPADWebServerTemplatesDir()));
        return HttpServletResponse.SC_OK;
    }

    @Override
    public EPADFileList getFileDescriptions(ProjectReference projectReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean toplevelOnly) throws Exception {
        List<EpadFile> files = projectOperations.getProjectFiles(projectReference.projectID, toplevelOnly);
        List<EPADFile> efiles = new ArrayList<EPADFile>();
        for (EpadFile file : files) {
            String subjectId = null;
            String patientName = null;
            String studyId = null;
            if (file.getSubjectId() != null && file.getSubjectId() != 0) {
                Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
                subjectId = subject.getSubjectUID();
                patientName = subject.getName();
            }
            if (file.getStudyId() != null && file.getStudyId() != 0) {
                Study study = (Study) projectOperations.getDBObject(Study.class, file.getStudyId());
                studyId = study.getStudyUID();
            }
            EPADFile efile = new EPADFile(projectReference.projectID, subjectId, patientName, studyId,
                    file.getSeriesUid(), file.getName(), file.getLength(), file.getFileType(),
                    new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()),
                    getEpadFilePath(file), file.isEnabled(), file.getDescription());
            boolean filter = searchFilter.shouldFilterFileType(file.getFileType());
            if (!filter)
                efiles.add(efile);
        }
        return new EPADFileList(efiles);
    }

    private String getEpadFilePath(EpadFile file) {
        String path = "files/" + file.getRelativePath();
        String fileName = file.getId() + file.getExtension();
        if (path.endsWith("/"))
            return path + fileName;
        else
            return path + "/" + fileName;
    }

    @Override
    public EPADFile getFileDescription(ProjectReference projectReference, String filename, String username,
            String sessionID) throws Exception {
        EpadFile file = projectOperations.getEpadFile(projectReference.projectID, null, null, null, filename);
        if (file == null)
            return null;
        String subjectId = null;
        String patientName = null;
        String studyId = null;
        if (file.getSubjectId() != null && file.getSubjectId() != 0) {
            Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
            subjectId = subject.getSubjectUID();
            patientName = subject.getName();
        }
        if (file.getStudyId() != null && file.getStudyId() != 0) {
            Study study = (Study) projectOperations.getDBObject(Study.class, file.getStudyId());
            studyId = study.getStudyUID();
        }
        EPADFile efile = new EPADFile(projectReference.projectID, subjectId, patientName, studyId,
                file.getSeriesUid(), file.getName(), file.getLength(), file.getFileType(),
                new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()), getEpadFilePath(file),
                file.isEnabled(), file.getDescription());
        return efile;
    }

    @Override
    public EPADFileList getFileDescriptions(SubjectReference subjectReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean toplevelOnly) throws Exception {
        List<EpadFile> files = projectOperations.getSubjectFiles(subjectReference.projectID,
                subjectReference.subjectID, toplevelOnly);
        List<EPADFile> efiles = new ArrayList<EPADFile>();
        for (EpadFile file : files) {
            String patientName = null;
            String studyId = null;
            if (file.getSubjectId() != null && file.getSubjectId() != 0) {
                Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
                patientName = subject.getName();
            }
            if (file.getStudyId() != null && file.getStudyId() != 0) {
                Study study = (Study) projectOperations.getDBObject(Study.class, file.getStudyId());
                studyId = study.getStudyUID();
            }
            EPADFile efile = new EPADFile(subjectReference.projectID, subjectReference.subjectID, patientName,
                    studyId, file.getSeriesUid(), file.getName(), file.getLength(), file.getFileType(),
                    new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()),
                    getEpadFilePath(file), file.isEnabled(), file.getDescription());
            boolean filter = searchFilter.shouldFilterFileType(file.getFileType());
            if (!filter)
                efiles.add(efile);
        }
        return new EPADFileList(efiles);
    }

    @Override
    public EPADFile getFileDescription(SubjectReference subjectReference, String filename, String username,
            String sessionID) throws Exception {
        EpadFile file = projectOperations.getEpadFile(subjectReference.projectID, subjectReference.subjectID, null,
                null, filename);
        if (file == null)
            return null;
        String patientName = null;
        String studyId = null;
        if (file.getSubjectId() != null && file.getSubjectId() != 0) {
            Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
            patientName = subject.getName();
        }
        if (file.getStudyId() != null && file.getStudyId() != 0) {
            Study study = (Study) projectOperations.getDBObject(Study.class, file.getStudyId());
            studyId = study.getStudyUID();
        }
        EPADFile efile = new EPADFile(subjectReference.projectID, subjectReference.subjectID, patientName, studyId,
                file.getSeriesUid(), file.getName(), file.getLength(), file.getFileType(),
                new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()), getEpadFilePath(file),
                file.isEnabled(), file.getDescription());
        return efile;
    }

    @Override
    public EPADFileList getFileDescriptions(StudyReference studyReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean toplevelOnly) throws Exception {
        List<EPADFile> efiles = getEPADFiles(studyReference, username, sessionID, searchFilter, toplevelOnly);
        return new EPADFileList(efiles);
    }

    @Override
    public List<EPADFile> getEPADFiles(StudyReference studyReference, String username, String sessionID,
            EPADSearchFilter searchFilter, boolean toplevelOnly) throws Exception {
        List<EpadFile> files = projectOperations.getStudyFiles(studyReference.projectID, studyReference.subjectID,
                studyReference.studyUID, toplevelOnly);
        List<EPADFile> efiles = new ArrayList<EPADFile>();
        for (EpadFile file : files) {
            String patientName = null;
            if (file.getSubjectId() != null && file.getSubjectId() != 0) {
                Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
                patientName = subject.getName();
            }
            EPADFile efile = new EPADFile(studyReference.projectID, studyReference.subjectID, patientName,
                    studyReference.studyUID, file.getSeriesUid(), file.getName(), file.getLength(),
                    file.getFileType(), new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()),
                    getEpadFilePath(file), file.isEnabled(), file.getDescription());
            boolean filter = searchFilter.shouldFilterFileType(file.getFileType());
            if (!filter)
                efiles.add(efile);
        }
        return efiles;
    }

    @Override
    public EPADFile getFileDescription(StudyReference studyReference, String filename, String username,
            String sessionID) throws Exception {
        EpadFile file = projectOperations.getEpadFile(studyReference.projectID, studyReference.subjectID,
                studyReference.studyUID, null, filename);
        if (file == null)
            return null;
        String patientName = null;
        if (file.getSubjectId() != null && file.getSubjectId() != 0) {
            Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
            patientName = subject.getName();
        }
        EPADFile efile = new EPADFile(studyReference.projectID, studyReference.subjectID, patientName,
                studyReference.studyUID, file.getSeriesUid(), file.getName(), file.getLength(), file.getFileType(),
                new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()), getEpadFilePath(file),
                file.isEnabled(), file.getDescription());
        return efile;
    }

    @Override
    public EPADFileList getFileDescriptions(SeriesReference seriesReference, String username, String sessionID,
            EPADSearchFilter searchFilter) throws Exception {
        List<EPADFile> efiles = getEPADFiles(seriesReference, username, sessionID, searchFilter);
        return new EPADFileList(efiles);
    }

    @Override
    public List<EPADFile> getEPADFiles(SeriesReference seriesReference, String username, String sessionID,
            EPADSearchFilter searchFilter) throws Exception {
        List<EpadFile> files = projectOperations.getSeriesFiles(seriesReference.projectID,
                seriesReference.subjectID, seriesReference.studyUID, seriesReference.seriesUID);
        List<EPADFile> efiles = new ArrayList<EPADFile>();
        for (EpadFile file : files) {
            String subjectId = null;
            String patientName = null;
            if (file.getSubjectId() != null && file.getSubjectId() != 0) {
                Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
                subjectId = subject.getSubjectUID();
                patientName = subject.getName();
            }
            EPADFile efile = new EPADFile(seriesReference.projectID, seriesReference.subjectID, patientName,
                    seriesReference.studyUID, file.getSeriesUid(), file.getName(), file.getLength(),
                    file.getFileType(), new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()),
                    getEpadFilePath(file), file.isEnabled(), file.getDescription());
            boolean filter = searchFilter.shouldFilterFileType(file.getFileType());
            if (!filter)
                efiles.add(efile);
        }
        return efiles;
    }

    @Override
    public EPADFile getFileDescription(SeriesReference seriesReference, String filename, String username,
            String sessionID) throws Exception {
        EpadFile file = projectOperations.getEpadFile(seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID, seriesReference.seriesUID, filename);
        String patientName = null;
        if (file.getSubjectId() != null && file.getSubjectId() != 0) {
            Subject subject = (Subject) projectOperations.getDBObject(Subject.class, file.getSubjectId());
            patientName = subject.getName();
        }
        EPADFile efile = new EPADFile(seriesReference.projectID, seriesReference.subjectID, patientName,
                seriesReference.studyUID, file.getSeriesUid(), file.getName(), file.getLength(), file.getFileType(),
                new SimpleDateFormat("yyyy-dd-MM HH:mm:ss").format(file.getCreatedTime()), getEpadFilePath(file),
                file.isEnabled(), file.getDescription());
        return efile;
    }

    @Override
    public EPADTemplateContainerList getTemplateDescriptions(String username, String sessionID) throws Exception {
        return getTemplateDescriptions(username, sessionID, null);
    }

    @Override
    public EPADTemplateContainerList getTemplateDescriptions(String username, String sessionID,
            String templateLevelFilter) throws Exception {
        return getTemplateDescriptions(username, sessionID, templateLevelFilter, false);
    }

    @Override
    public EPADTemplateContainer dbtemplate2Container(Template t) throws Exception {
        List<EPADTemplate> epadTmpls = new ArrayList<EPADTemplate>();
        //the template is the first template anyway. not supporting multiple templates now
        EPADTemplate epadTmpl = new EPADTemplate(t.getTemplateUID(), t.getTemplateName(), t.getTemplateType(),
                t.getTemplateCode(), t.getTemplateDescription(), t.getModality(), t.getTemplateLevelType());
        epadTmpls.add(epadTmpl);
        EpadFile f = (EpadFile) projectOperations.getDBObject(EpadFile.class, t.getFileId());
        if (f != null) {
            EPADTemplateContainer template = new EPADTemplateContainer("", "", "", "", "", f.getName(),
                    f.getLength(), FileType.TEMPLATE.getName(), formatDate(f.getCreatedTime()), getEpadFilePath(f),
                    f.isEnabled(), f.getDescription(), t.getTemplateLevelType());
            template.templateName = t.getTemplateName();
            template.templateType = t.getTemplateType();
            template.templateCode = t.getTemplateCode();
            template.templateDescription = t.getTemplateDescription();
            template.modality = t.getModality();
            template.templates = epadTmpls;
            return template;
        }
        return null;

    }

    @Override
    public void migrateTemplates() throws Exception {
        List<EpadFile> efiles = projectOperations.getEpadFiles(null, null, null, null, FileType.TEMPLATE, false);
        for (EpadFile efile : efiles) {
            File tfile = new File(EPADConfig.getEPADWebServerResourcesDir() + getEpadFilePath(efile));
            Template template = getFirstTemplateInfo(tfile);
            if (template.getTemplateCode() == null) {
                log.warning("Template code couldn't be retrieved. Skipping file");
                continue;
            }
            Template existingTemplate = getTemplate(template.getTemplateCode());
            if (existingTemplate != null) {
                //two different possibilities; either the user uploaded same file to different projects or uses the same code
                EpadFile ef = (EpadFile) projectOperations.getDBObject(EpadFile.class,
                        existingTemplate.getFileId());

                //if same file just remove the extras and put the project relations
                if (efile.getName().equals(ef.getName()) && efile.getLength() == ef.getLength()
                        && !efile.getProjectId().equals(ef.getProjectId())) {
                    log.info("same file for template=" + template.getTemplateName()
                            + " just putting the project relation");
                }
                //if same code for different files put it in the log
                else {
                    Project project = (Project) projectOperations.getDBObject(Project.class, efile.getProjectId());
                    projectOperations.createEventLog("admin", project.getProjectId(), null, null, null, null, null,
                            efile.getName(),
                            "The same template code cannot be used for different templates code saved as "
                                    + template.getTemplateCode() + "-2",
                            template.getTemplateCode(), true);
                    template.setTemplateCode(template.getTemplateCode() + "-2");
                    template.setFileId(efile.getId());
                    template.save();
                    log.info("template db entry is created for template=" + template.getTemplateName() + " as "
                            + template.getTemplateCode());
                }

            } else {
                template.setFileId(efile.getId());
                template.setCreator(efile.getCreator());
                template.save();
                log.info("template db entry is created for template=" + template.getTemplateName() + " as "
                        + template.getTemplateCode());
            }
            Project project = (Project) projectOperations.getDBObject(Project.class, efile.getProjectId());
            projectOperations.setProjectTemplate("admin", project.getProjectId(), template.getTemplateCode(),
                    efile.isEnabled());

        }

        //get the disabled templates and set their enable attribute
        List<DisabledTemplate> dts = new DisabledTemplate().getObjects("");
        if (dts != null && !dts.isEmpty()) {
            for (DisabledTemplate dt : dts) {
                //it was actually file name but the if check uses filename,templatename and templateCode so lets check all
                //if (disabledTemplatesNames.contains(template.fileName) || disabledTemplatesNames.contains(template.templateName) || disabledTemplatesNames.contains(template.templateCode))
                for (EpadFile efile : efiles) {
                    File tfile = new File(EPADConfig.getEPADWebServerResourcesDir() + getEpadFilePath(efile));
                    //we do not actually need to get this project id, but putting to get the correct template container object
                    Project fileProject = (Project) projectOperations.getDBObject(Project.class,
                            efile.getProjectId());
                    Project disableProject = (Project) projectOperations.getDBObject(Project.class,
                            dt.getProjectId());
                    EPADTemplateContainer tc = convertEpadFileToTemplate(fileProject.getProjectId(), efile, tfile);
                    if (tc.fileName.equalsIgnoreCase(dt.getTemplateName())
                            || tc.templateName.equalsIgnoreCase(dt.getTemplateName())
                            || tc.templateCode.equalsIgnoreCase(dt.getTemplateName())) {
                        projectOperations.setProjectTemplate("admin", disableProject.getProjectId(),
                                tc.templateCode, false);
                        dt.delete();
                    }

                }

            }
        }

    }

    @Override
    public EPADTemplateContainerList getTemplateDescriptions(String username, String sessionID,
            String templateLevelFilter, boolean includeSystemTemplates) throws Exception {

        EPADTemplateContainerList fileList = new EPADTemplateContainerList();

        //not supported anymore but should we put just in case
        if (includeSystemTemplates)
            throw new Exception("System templates are not supported anymore");
        //      EPADTemplateContainerList oldList = getSystemTemplateDescriptions(username, sessionID);
        //      if (includeSystemTemplates)
        //         fileList = oldList;

        String criteria = "";
        if (templateLevelFilter != null)
            criteria = "LOWER(templateLevelType) like '" + templateLevelFilter.toLowerCase() + "%'";
        //get all templates
        List<Template> dbTemplates = new Template().getObjects(criteria);
        //new method. use templates table. version 2.3
        if (dbTemplates != null && !dbTemplates.isEmpty()) {
            for (Template t : dbTemplates) {
                Set<EPADProjectTemplate> userProjects = new HashSet<EPADProjectTemplate>();

                //for each create the EPADTemplate and EPADTemplateContainer
                EPADTemplateContainer template = dbtemplate2Container(t);
                //if template couldn't be retrieved skip
                if (template == null)
                    continue;
                //get project information and put it in
                List<Long> projects = projectOperations.getProjectsForTemplate(t.getId());
                //new format for the template, got project-template records
                if (projects != null && !projects.isEmpty()) {
                    for (Long pId : projects) {
                        Project project = (Project) projectOperations.getDBObject(Project.class, pId);

                        if (projectOperations.hasAccessToProject(username, project.getProjectId())
                                || project.getProjectId().equals(EPADConfig.xnatUploadProjectID)) {
                            String defTemplate = null;
                            boolean defaultTemplate = false;
                            Project userProj = projectOperations.getProjectForUser(username,
                                    project.getProjectId());
                            if (userProj != null)
                                defTemplate = userProj.getDefaultTemplate();
                            if (t.getTemplateCode().equals(defTemplate))
                                defaultTemplate = true;
                            EPADProjectTemplate pt = new EPADProjectTemplate(project.getProjectId(),
                                    projectOperations.getProjectTemplate(username, project.getProjectId(),
                                            t.getTemplateCode()),
                                    defaultTemplate);

                            userProjects.add(pt);
                        }
                    }

                    //default template? for what should be related to project.

                    //disabled templates get them and remove from user projects
                    //is done for project
                    //               List<Long> disabledProjects = projectOperations.getDisabledProjectsForTemplate(t.getId());
                    //               for (Long pId:disabledProjects) {
                    //                  Project project = (Project) projectOperations.getDBObject(Project.class, pId);
                    //                  userProjects.remove(project.getProjectId());
                    //               }

                    //??? it is related to project!!
                    //            boolean enabled = efile.isEnabled();
                    //            template.enabled = enabled;

                    template.projectTemplates = new ArrayList<EPADProjectTemplate>();
                    template.projectTemplates.addAll(userProjects);
                    //if there are project-template records we do not care about the file tuple anymore
                    //it is ignoring the file projectid
                    //we need a way to put the projectid initially. it is in main

                    //just to put smt for ui. should be removed
                    if (template.projectTemplates != null && !template.projectTemplates.isEmpty()) {
                        for (EPADProjectTemplate pt : template.projectTemplates) {
                            template.projectID += pt.projectID + ",";
                        }
                        template.projectID = template.projectID.trim().replaceAll(",+$", "");
                        //                  template.projectID=template.projectTemplates.get(0).projectID;
                    }
                    fileList.addTemplate(template);

                }

            }
        }
        //old format, no project-template records. use the old retrieval
        else {
            List<EpadFile> efiles = projectOperations.getEpadFiles(null, null, null, null, FileType.TEMPLATE,
                    false);
            //         if (efiles.size() == 0 && includeSystemTemplates)
            //            fileList = oldList;
            Map<String, List<String>> disabledTemplates = new HashMap<String, List<String>>();
            for (EpadFile efile : efiles) {
                Set<String> userProjects = new HashSet<String>();

                //get projects from project_template
                //if there are tuples in project_template for this template use that instead
                //we need the code to check in the project_template table.
                //convert to template container object here
                File tfile = new File(EPADConfig.getEPADWebServerResourcesDir() + getEpadFilePath(efile));
                //sending null as project id instead of project.getProjectId()
                EPADTemplateContainer template = convertEpadFileToTemplate(null, efile, tfile);
                Project project = (Project) projectOperations.getDBObject(Project.class, efile.getProjectId());
                String defTemplate = null;
                Project userProj = projectOperations.getProjectForUser(username, project.getProjectId());
                if (userProj != null) {
                    defTemplate = userProj.getDefaultTemplate();
                }
                List<String> disabledTemplatesNames = disabledTemplates.get(project.getProjectId());
                if (disabledTemplatesNames == null) {
                    disabledTemplatesNames = projectOperations.getDisabledTemplates(project.getProjectId());
                    disabledTemplates.put(project.getProjectId(), disabledTemplatesNames);
                }
                if (userProjects.contains(project.getProjectId())
                        || projectOperations.hasAccessToProject(username, project.getProjectId())
                        || project.getProjectId().equals(EPADConfig.xnatUploadProjectID)) {
                    userProjects.add(project.getProjectId());

                    List<EPADTemplate> templates = template.templates;
                    for (EPADTemplate t : templates) {
                        if (t.getTemplateCode().equals(defTemplate)) {
                            t.defaultTemplate = true;
                        } else
                            t.defaultTemplate = false;
                    }
                    boolean enabled = efile.isEnabled();
                    if (disabledTemplatesNames.contains(template.fileName)
                            || disabledTemplatesNames.contains(template.templateName)
                            || disabledTemplatesNames.contains(template.templateCode))
                        enabled = false;
                    template.enabled = enabled;
                    template.projectID = project.getProjectId();
                    template.projectIDs = new ArrayList<String>();
                    template.projectIDs.add(project.getProjectId());

                    if (templateLevelFilter == null || template.templateLevelType.toLowerCase()
                            .startsWith(templateLevelFilter.toLowerCase()))
                        fileList.addTemplate(template);

                }
            }
        }
        return fileList;
    }

    //   @Override
    //   public EPADTemplateContainerList getTemplateDescriptions(String username,
    //         String sessionID, String templateLevelFilter, boolean includeSystemTemplates) throws Exception {
    //      EPADTemplateContainerList oldList = getSystemTemplateDescriptions(username, sessionID);
    //      EPADTemplateContainerList fileList = new EPADTemplateContainerList();
    //      List<EpadFile> efiles = projectOperations.getEpadFiles(null, null, null, null, FileType.TEMPLATE, false);
    //      if (efiles.size() == 0 && includeSystemTemplates)
    //         fileList = oldList;
    //      Map<String, List<String>> disabledTemplates = new HashMap<String, List<String>>();
    //      for (EpadFile efile: efiles)
    //      {
    //         Set<String> userProjects = new HashSet<String>();
    //         
    //         //get projects from project_template
    //         //if there are tuples in project_template for this template use that instead
    //         //we need the code to check in the project_template table.
    //         //convert to template container object here
    //         File tfile = new File(EPADConfig.getEPADWebServerResourcesDir() + getEpadFilePath(efile));
    //         //sending null as project id instead of project.getProjectId()
    //         EPADTemplateContainer template = convertEpadFileToTemplate(null, efile, tfile);
    //         //check the project_template table
    //         //disable
    //         List<Long> projects = null; //projectOperations.getProjectsForTemplate(template.fileName);
    //         //new format for the template, got project-template records
    //         if (projects!=null && !projects.isEmpty()){
    //            for (Long pId:projects) {
    //               Project project = (Project) projectOperations.getDBObject(Project.class, pId);
    //               String defTemplate = null;
    //               Project userProj = projectOperations.getProjectForUser(username, project.getProjectId());
    //               if (userProj != null)
    //               {
    //                  defTemplate = userProj.getDefaultTemplate();
    //               }
    //               List<String> disabledTemplatesNames = disabledTemplates.get(project.getProjectId());
    //               if (disabledTemplatesNames == null)
    //               {
    //                  disabledTemplatesNames = projectOperations.getDisabledTemplates(project.getProjectId());
    //                  disabledTemplates.put(project.getProjectId(), disabledTemplatesNames);
    //               }
    //               if (userProjects.contains(project.getProjectId()) || projectOperations.hasAccessToProject(username, project.getProjectId())
    //                     || project.getProjectId().equals(EPADConfig.xnatUploadProjectID))
    //               {
    //                  userProjects.add(project.getProjectId());
    //                  
    //                  List<EPADTemplate> templates = template.templates;
    //                  for (EPADTemplate t: templates)
    //                  {
    //                     if (t.getTemplateCode().equals(defTemplate))
    //                     {
    //                        t.defaultTemplate = true;
    //                     }
    //                     else
    //                        t.defaultTemplate = false;
    //                  }
    //                  if (disabledTemplatesNames.contains(template.fileName) || disabledTemplatesNames.contains(template.templateName) || disabledTemplatesNames.contains(template.templateCode))
    //                     userProjects.remove(project.getProjectId());
    //                  
    //                  
    //               }
    //               
    //               
    //            }
    //            
    //            boolean enabled = efile.isEnabled();
    //            
    //            template.enabled = enabled;
    //            
    //            template.projectIDs=new ArrayList<String>();
    //            template.projectIDs.addAll(userProjects);
    //            //if there are project-template records we do not care about the file tuple anymore
    //            //it is ignoring the file projectid
    //            //we need a way to put the projectid initially. it is in main
    //            
    //            //just to put smt for ui. should be removed
    //            if (template.projectIDs!=null && !template.projectIDs.isEmpty())
    //               template.projectID=template.projectIDs.get(0);
    //            
    //            if (templateLevelFilter==null || template.templateLevelType.toLowerCase().startsWith(templateLevelFilter.toLowerCase()))
    //               fileList.addTemplate(template);
    //            
    //         }
    //         //old format, no project-template records. use the old retrieval
    //         else {
    //            Project project = (Project) projectOperations.getDBObject(Project.class, efile.getProjectId());
    //            String defTemplate = null;
    //            Project userProj = projectOperations.getProjectForUser(username, project.getProjectId());
    //            if (userProj != null)
    //            {
    //               defTemplate = userProj.getDefaultTemplate();
    //            }
    //            List<String> disabledTemplatesNames = disabledTemplates.get(project.getProjectId());
    //            if (disabledTemplatesNames == null)
    //            {
    //               disabledTemplatesNames = projectOperations.getDisabledTemplates(project.getProjectId());
    //               disabledTemplates.put(project.getProjectId(), disabledTemplatesNames);
    //            }
    //            if (userProjects.contains(project.getProjectId()) || projectOperations.hasAccessToProject(username, project.getProjectId())
    //                  || project.getProjectId().equals(EPADConfig.xnatUploadProjectID))
    //            {
    //               userProjects.add(project.getProjectId());
    //               
    //               List<EPADTemplate> templates = template.templates;
    //               for (EPADTemplate t: templates)
    //               {
    //                  if (t.getTemplateCode().equals(defTemplate))
    //                  {
    //                     t.defaultTemplate = true;
    //                  }
    //                  else
    //                     t.defaultTemplate = false;
    //               }
    //               boolean enabled = efile.isEnabled();
    //               if (disabledTemplatesNames.contains(template.fileName) || disabledTemplatesNames.contains(template.templateName) || disabledTemplatesNames.contains(template.templateCode))
    //                  enabled = false;
    //               template.enabled = enabled;
    //               template.projectID=project.getProjectId();
    //               template.projectIDs=new ArrayList<String>();
    //               template.projectIDs.add(project.getProjectId());
    //               
    //               if (templateLevelFilter==null || template.templateLevelType.toLowerCase().startsWith(templateLevelFilter.toLowerCase()))
    //                  fileList.addTemplate(template);
    //               
    //            }
    //         }
    //      }
    //      return fileList;
    //   }

    @Override
    public EPADTemplateContainerList getSystemTemplateDescriptions(String username, String sessionID)
            throws Exception {
        return getSystemTemplateDescriptions(username, sessionID, null);
    }

    @Override
    public EPADTemplateContainerList getSystemTemplateDescriptions(String username, String sessionID,
            String templateLevelFilter) throws Exception {
        EPADTemplateContainerList fileList = new EPADTemplateContainerList();
        File[] templates = new File(EPADConfig.getEPADWebServerTemplatesDir()).listFiles();
        //this method is not used any more. leaving the old version of disabled templates
        List<String> disabledTemplatesNames = projectOperations
                .getDisabledTemplates(EPADConfig.xnatUploadProjectID);
        for (File template : templates) {
            if (template.isDirectory())
                continue;
            String name = template.getName();
            String description = "";
            if (!name.toLowerCase().endsWith(".xml"))
                continue;
            String templateUID = "";
            String templateName = "";
            String templateType = "";
            String templateLevelType = "";
            String templateCode = "";
            String templateDescription = "";
            String modality = "";
            List<EPADTemplate> epadTmpls = new ArrayList<EPADTemplate>();
            try {
                String xml = EPADFileUtils.readFileAsString(template);
                JSONObject root = XML.toJSONObject(xml);
                JSONObject container = root.getJSONObject("TemplateContainer");
                JSONArray templateObjs = new JSONArray();
                try {
                    JSONObject templateObj = container.getJSONObject("Template");
                    templateObjs.put(templateObj);
                } catch (Exception x) {
                    templateObjs = container.getJSONArray("Template");
                }
                for (int i = 0; i < templateObjs.length(); i++) {
                    JSONObject templateObj = templateObjs.getJSONObject(i);
                    templateUID = templateObj.getString("uid");
                    templateName = templateObj.getString("name");
                    templateType = templateObj.getString("codeMeaning");
                    try {
                        templateCode = templateObj.getString("codeValue");
                    } catch (Exception x) {
                        log.warning("Error getting code value for template " + template.getAbsolutePath());
                    }
                    try {
                        templateDescription = templateObj.getString("description");
                        modality = templateObj.getString("modality");
                    } catch (Exception x) {
                    }

                    try {
                        templateLevelType = templateObj.getString("templateType");
                    } catch (Exception x) {
                        templateLevelType = "image";
                    }
                    if (templateLevelType == null)
                        templateLevelType = "image";

                    if (templateLevelFilter == null
                            || templateLevelType.toLowerCase().startsWith(templateLevelFilter.toLowerCase())) {
                        EPADTemplate epadTmpl = new EPADTemplate(templateUID, templateName, templateType,
                                templateCode, templateDescription, modality, templateLevelType);
                        epadTmpls.add(epadTmpl);
                    }
                }
            } catch (Exception x) {
                log.warning("JSON Error", x);
            }
            boolean enabled = true;
            if (disabledTemplatesNames.contains(template.getName()) || disabledTemplatesNames.contains(templateName)
                    || disabledTemplatesNames.contains(templateCode))
                enabled = false;
            if (description == null || description.trim().length() == 0) {
                description = "image"; // Image template type
                //            if (templateCode.startsWith("SEG"))
                //               description = "segmentation"; // Image template type
            }
            //ml changed first param from "" to default project
            EPADTemplateContainer epadContainer = new EPADTemplateContainer(EPADConfig.xnatUploadProjectID, "", "",
                    "", "", name, template.length(), FileType.TEMPLATE.getName(),
                    formatDate(new Date(template.lastModified())), "templates/" + template.getName(), enabled,
                    description, templateLevelType);
            epadContainer.templateName = templateName;
            epadContainer.templateType = templateType;
            epadContainer.templateCode = templateCode;
            epadContainer.templateDescription = templateDescription;
            epadContainer.modality = modality;
            epadContainer.templates = epadTmpls;
            fileList.addTemplate(epadContainer);
        }
        return fileList;
    }

    @Override
    public EPADTemplateContainerList getProjectTemplateDescriptions(String projectID, String username,
            String sessionID) throws Exception {
        return getProjectTemplateDescriptions(projectID, username, sessionID, null);

    }

    @Override
    public EPADTemplateContainerList getProjectTemplateDescriptions(String projectID, String username,
            String sessionID, String templateLevelFilter) throws Exception {
        EPADTemplateContainerList fileList = getTemplateDescriptions(username, sessionID, templateLevelFilter);
        EPADTemplateContainerList templates = new EPADTemplateContainerList();
        boolean isInAllProject = false;
        for (EPADTemplateContainer t : fileList.ResultSet.Result) {
            if (t.projectTemplates != null) {
                for (EPADProjectTemplate pt : t.projectTemplates) {
                    if (pt.projectID.equalsIgnoreCase(projectID)) {
                        log.info("adding template " + t.templateCode);
                        templates.addTemplate(t);

                    }
                    if (pt.projectID.equals(EPADConfig.xnatUploadProjectID)) {

                        isInAllProject = true;
                    }
                }
            } else if ((t.projectID != null && t.projectID.equalsIgnoreCase(projectID))) {
                templates.addTemplate(t);
            }
            //if the template's project is all project and template is not disabled for this project
            if (isInAllProject) {
                List<String> disabledTemplatesNames = projectOperations.getDisabledTemplateCodes(projectID);
                //can keep the same it is using templatecode (starting 2.3)
                if (!(disabledTemplatesNames.contains(t.fileName) || disabledTemplatesNames.contains(t.templateName)
                        || disabledTemplatesNames.contains(t.templateCode))) {
                    if (!templates.ResultSet.Result.contains(t)) {
                        templates.addTemplate(t);
                    }
                } else {
                    log.info("disabled in project, removing template " + t.templateCode);
                    templates.ResultSet.Result.remove(t);
                    templates.ResultSet.totalRecords--;
                }

            }

        }
        return templates;

        //      EPADTemplateContainerList fileList = new EPADTemplateContainerList();
        //      List<EpadFile> efiles = projectOperations.getEpadFiles(projectID, null, null, null, FileType.TEMPLATE, false);
        //      Set<String> templateCodes = new HashSet<String>();
        //      //ml defaulttemplate
        //      Project userProj = projectOperations.getProjectForUser(username, projectID);
        //      String defTemplate="";
        //      if (userProj != null)
        //      {
        //         defTemplate = userProj.getDefaultTemplate();
        //      }
        //
        //      for (EpadFile efile: efiles)
        //      {
        //         EPADTemplateContainer template = convertEpadFileToTemplate(projectID, efile, new File(EPADConfig.getEPADWebServerResourcesDir() + getEpadFilePath(efile)));
        //         if (!template.templateLevelType.equalsIgnoreCase(efile.getTemplateLevelType())) {//file (db) and template (xml) different
        //            log.info("xml and db different for template "+template.templateName +"!! Updating db. it was "+ efile.getTemplateLevelType()+ " changing to " +template.templateLevelType);
        //            efile.setTemplateLevelType(template.templateLevelType);
        //            efile.save();
        //         }
        //         if (template.enabled && (templateLevelFilter==null || template.templateLevelType.toLowerCase().startsWith(templateLevelFilter.toLowerCase())))
        //         {
        //            log.info("description " + templateLevelFilter+ " template " + template.templateLevelType);
        //            //ml default template
        //            List<EPADTemplate> templates = template.templates;
        //            for (EPADTemplate t: templates)
        //            {
        //               log.info("template : " +t.getTemplateCode() + " defaulttemplate :"+defTemplate);
        //               if (t.getTemplateCode().equals(defTemplate))
        //               {
        //                  t.defaultTemplate = true;
        //               }
        //               else
        //                  t.defaultTemplate = false;
        //            }
        //            fileList.addTemplate(template);
        //            templateCodes.add(template.templateCode);
        //         }
        //      }
        //      efiles = projectOperations.getEpadFiles(EPADConfig.xnatUploadProjectID, null, null, null, FileType.TEMPLATE, false);
        //      List<String> disabledTemplatesNames = projectOperations.getDisabledTemplates(projectID);
        //
        //
        //      log.info("Default template for project "+ userProj.getName() + " is "+defTemplate);
        //
        //      for (EpadFile efile: efiles)
        //      {
        //
        //         EPADTemplateContainer template = convertEpadFileToTemplate(projectID, efile, new File(EPADConfig.getEPADWebServerResourcesDir() + getEpadFilePath(efile)));
        //         log.info("template enabled: " +template.enabled + " code: "+ template.templateCode + " codecontain:"+templateCodes.contains(template.templateCode));
        //         if (template.enabled && !disabledTemplatesNames.contains(template.fileName) 
        //               && !disabledTemplatesNames.contains(template.templateName) 
        //               && !disabledTemplatesNames.contains(template.templateCode) 
        //               && !templateCodes.contains(template.templateCode)  
        //               && (templateLevelFilter==null || template.templateLevelType.toLowerCase().startsWith(templateLevelFilter.toLowerCase()))){
        //
        //            //ml default template
        //            List<EPADTemplate> templates = template.templates;
        //            for (EPADTemplate t: templates)
        //            {
        //               log.info("template : " +t.getTemplateCode() + " defaulttemplate :"+defTemplate);
        //               if (t.getTemplateCode().equals(defTemplate))
        //               {
        //                  t.defaultTemplate = true;
        //               }
        //               else
        //                  t.defaultTemplate = false;
        //            }
        //
        //            fileList.addTemplate(template);
        //         }
        //
        //      }
        //      return fileList;
    }

    private EPADTemplateContainer convertEpadFileToTemplate(String projectId, EpadFile efile, File templateFile) {
        String description = efile.getDescription();
        String templateName = "";
        String templateType = "";
        String templateLevelType = "";
        String templateCode = "";
        String templateDescription = "";
        String modality = "";
        List<EPADTemplate> epadTmpls = new ArrayList<EPADTemplate>();
        try {
            String xml = EPADFileUtils.readFileAsString(templateFile);
            JSONObject root = XML.toJSONObject(xml);
            JSONObject container = root.getJSONObject("TemplateContainer");
            JSONArray templateObjs = new JSONArray();
            try {
                JSONObject templateObj = container.getJSONObject("Template");
                templateObjs.put(templateObj);
            } catch (Exception x) {
                templateObjs = container.getJSONArray("Template");
            }
            for (int i = 0; i < templateObjs.length(); i++) {
                JSONObject templateObj = templateObjs.getJSONObject(i);
                String templateUID = templateObj.getString("uid");
                templateName = templateObj.getString("name");
                templateType = templateObj.getString("codeMeaning");
                templateCode = templateObj.getString("codeValue");
                try {
                    templateDescription = templateObj.getString("description");
                    modality = templateObj.getString("modality");
                } catch (Exception x) {
                }
                try {
                    templateLevelType = templateObj.getString("templateType").toLowerCase();
                } catch (Exception x) {
                    templateLevelType = "image";
                }
                if (templateLevelType == null) //if still null change to default
                    templateLevelType = "image";
                EPADTemplate epadTmpl = new EPADTemplate(templateUID, templateName, templateType, templateCode,
                        templateDescription, modality, templateLevelType);
                epadTmpls.add(epadTmpl);
            }
        } catch (Exception x) {
        }
        if (description == null || description.trim().length() == 0) {
            description = "image"; // Image template type
            //         if (templateCode.startsWith("SEG"))
            //            description = "segmentation"; // Image template type            
        }
        EPADTemplateContainer template = new EPADTemplateContainer(projectId, "", "", "", "", efile.getName(),
                efile.getLength(), FileType.TEMPLATE.getName(), formatDate(efile.getCreatedTime()),
                getEpadFilePath(efile), efile.isEnabled(), description, templateLevelType);
        template.templateName = templateName;
        template.templateType = templateType;
        template.templateCode = templateCode;
        template.templateDescription = templateDescription;
        template.modality = modality;
        template.templates = epadTmpls;
        return template;
    }

    @Override
    public void deleteFile(String username, ProjectReference projectReference, String fileName) throws Exception {
        projectOperations.createEventLog(username, projectReference.projectID, null, null, null, null, null,
                fileName, "DELETE FILE", fileName, false);
        User user = projectOperations.getUser(username);
        Project project = projectOperations.getProject(projectReference.projectID);
        if (user.isAdmin() && fileName.equals("*")) {
            List<EpadFile> files = projectOperations.getEpadFiles(projectReference.projectID, null, null, null,
                    null, true);
            for (EpadFile file : files) {
                try {
                    projectOperations.deleteFile(username, projectReference.projectID, null, null, null,
                            file.getName());
                } catch (Exception x) {

                }
            }

        } else {
            EpadFile file = projectOperations.getEpadFile(projectReference.projectID, null, null, null, fileName);
            if (file.getFileType().equalsIgnoreCase(FileType.TEMPLATE.getName())) {
                throw new Exception(
                        "Do not use this endpoint for deleting templates. Use delete template endpoint");
            }
            if (file == null && !user.isAdmin())
                throw new Exception("No permissions to delete system template");
            if (file != null && !username.equals(file.getCreator())
                    && !projectOperations.isOwner(username, projectReference.projectID))
                throw new Exception("No permissions to delete this template");
            if (file != null) {
                projectOperations.deleteFile(username, projectReference.projectID, null, null, null, fileName);
            } else {
                File template = new File(EPADConfig.getEPADWebServerTemplatesDir(), fileName);
                if (template.exists())
                    template.delete();
                else
                    throw new Exception("Template file not found");
            }
        }
    }

    @Override
    public void deleteTemplate(String username, String templatecode) throws Exception {
        Template t = getTemplate(templatecode);
        if (t == null) {
            log.warning("Template with code " + templatecode + " does not exist");
            return;
        }

        User requestor = projectOperations.getUser(username);
        EpadFile f = (EpadFile) projectOperations.getDBObject(EpadFile.class, t.getFileId());
        if (f == null) {
            log.warning("No file for template with code " + templatecode);
            return;
        }
        List<EpadFile> files = new EpadFile().getObjects(" name='" + f.getName() + "' and length=" + f.getLength());
        int usersFiles = 0;
        for (EpadFile fl : files) {
            log.info("found file:" + fl.getId());
            if (username.equals(fl.getCreator()))
                usersFiles++;
        }
        if (!requestor.isAdmin() && !(usersFiles == files.size()))
            throw new Exception("No permissions to delete template");
        log.info("Deleting Template, templatecode: " + templatecode);

        new ProjectToTemplate().deleteObjects("template_id=" + t.getId());
        //migration check multiple files
        if (usersFiles > 1) {
            for (EpadFile fl : files) {
                deleteFile(username, fl.getId());
            }
        } else {
            deleteFile(username, t.getFileId());
        }
        //deleteFile also deletes the template and projecttemplate entries. it is ok, I am handling migration first 
        new Template().deleteObjects("id=" + t.getId());

    }

    @Override
    public void deleteFile(String username, long fileId) throws Exception {
        EpadFile f = (EpadFile) projectOperations.getDBObject(EpadFile.class, fileId);
        Project p = (Project) projectOperations.getDBObject(Project.class, f.getProjectId());
        projectOperations.deleteFile(username, p.getProjectId(), null, null, null, f.getName(), f.getFileType());
    }

    @Override
    public void deleteFile(String username, SubjectReference subjectReference, String fileName) throws Exception {
        projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                null, null, null, fileName, "DELETE FILE", fileName, false);
        projectOperations.deleteFile(username, subjectReference.projectID, subjectReference.subjectID, null, null,
                fileName);
    }

    @Override
    public void deleteFile(String username, StudyReference studyReference, String fileName) throws Exception {
        projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                studyReference.studyUID, null, null, null, fileName, "DELETE FILE", fileName, false);
        projectOperations.deleteFile(username, studyReference.projectID, studyReference.subjectID,
                studyReference.studyUID, null, fileName);
    }

    @Override
    public void deleteFile(String username, SeriesReference seriesReference, String fileName) throws Exception {
        projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID, seriesReference.seriesUID, null, null, fileName, "DELETE FILE", fileName,
                false);
        projectOperations.deleteFile(username, seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID, seriesReference.seriesUID, fileName);
    }

    @Override
    public void deleteFile(String username, String fileName) throws Exception {
        projectOperations.createEventLog(username, null, null, null, null, null, null, fileName, "DELETE FILE",
                fileName, false);
        projectOperations.deleteFile(username, null, null, null, null, fileName);
    }

    @Override
    public String setSubjectStatus(SubjectReference subjectReference, String sessionID, String username)
            throws Exception {
        projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                null, null, null, "SET STATUS", subjectReference.status);
        projectOperations.setUserStatusForProjectAndSubject(username, subjectReference.projectID,
                subjectReference.subjectID, subjectReference.status);
        return "";
    }

    @Override
    public int projectDelete(String projectID, String sessionID, String username) throws Exception {
        int xnatStatusCode;

        if (projectID.equals(EPADConfig.xnatUploadProjectID))
            throw new RuntimeException("Project " + EPADConfig.xnatUploadProjectID + " can not be deleted");
        projectOperations.createEventLog(username, projectID, null, null, null, null, null, "DELETE PROJECT", null);
        projectOperations.deleteProject(username, projectID);
        this.deleteAllAims(projectID, null, null, null, true);
        xnatStatusCode = HttpServletResponse.SC_OK;
        return xnatStatusCode;
    }

    @Override
    public int subjectDelete(SubjectReference subjectReference, String sessionID, String username)
            throws Exception {
        return subjectDelete(subjectReference, sessionID, username, false);
    }

    @Override
    public int subjectDelete(SubjectReference subjectReference, String sessionID, String username, boolean all)
            throws Exception {
        List<Study> studies = projectOperations.getStudiesForSubject(subjectReference.subjectID);
        int xnatStatusCode;
        User user = projectOperations.getUser(username);
        if (!user.isAdmin() && !projectOperations.isOwner(username, subjectReference.projectID))
            throw new Exception("No permissions to delete Patient: " + subjectReference.subjectID + " in project "
                    + subjectReference.projectID);

        if (!user.isAdmin() && all) {
            throw new Exception("No permissions to delete Patient: " + subjectReference.subjectID
                    + " from system. You are not admin. Please select delete from project. ");
        }

        projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                null, null, null, "DELETE SUBJECT", null);
        log.info("Scheduling deletion task for patient " + subjectReference.subjectID + " in project "
                + subjectReference.projectID + " from user " + username);

        //ml all added for deleting from system 
        (new Thread(
                new SubjectDataDeleteTask(subjectReference.projectID, subjectReference.subjectID, username, all)))
                        .run();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        projectOperations.deleteSubject(username, subjectReference.subjectID, subjectReference.projectID);
        this.deleteAllAims(subjectReference.projectID, subjectReference.subjectID, null, null, true);
        xnatStatusCode = HttpServletResponse.SC_OK;

        return xnatStatusCode;
    }

    @Override
    public String studyDelete(StudyReference studyReference, String sessionID, boolean deleteAims, String username)
            throws Exception {
        return this.studyDelete(studyReference, sessionID, deleteAims, username, false);

    }

    @Override
    public String studyDelete(StudyReference studyReference, String sessionID, boolean deleteAims, String username,
            boolean all) throws Exception {
        int xnatStatusCode;
        User user = projectOperations.getUser(username);
        if (!user.isAdmin() && !projectOperations.isOwner(username, studyReference.projectID))
            throw new Exception("No permissions to delete Study: " + studyReference.studyUID + " in project "
                    + studyReference.projectID);
        if (!user.isAdmin() && all)
            throw new Exception("No permissions to delete Study: " + studyReference.studyUID
                    + " from system. You are not admin. Please select delete from project. ");

        projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                studyReference.studyUID, null, null, null, "DELETE STUDY", null);

        if (projectOperations.getProjectsForStudy(studyReference.studyUID).size() > 1) {
            //do this if not trying to delete from all. 
            //if we do it when the study is in only all project the StudyDataTask throws null pointer exception
            log.info("Deleting in XNAT: study " + studyReference.studyUID + " for patient "
                    + studyReference.subjectID + " in project " + studyReference.projectID + " from user "
                    + username);

            projectOperations.deleteStudy(username, studyReference.studyUID, studyReference.subjectID,
                    studyReference.projectID);
        }
        this.deleteAllAims(studyReference.projectID, studyReference.subjectID, studyReference.studyUID, null, true);
        xnatStatusCode = HttpServletResponse.SC_OK;

        log.info("Delete Study Status from XNAT:" + xnatStatusCode);
        if (XNATDeletionOperations.successStatusCode(xnatStatusCode)) {
            log.info("Scheduling deletion task for study " + studyReference.studyUID + " for patient "
                    + studyReference.subjectID + " in project " + studyReference.projectID + " from user "
                    + username);
            //ml all added
            (new Thread(new StudyDataDeleteTask(username, studyReference.projectID, studyReference.subjectID,
                    studyReference.studyUID, deleteAims, all))).run();
            return "";
        } else
            return "Error deleting Study in XNAT";
    }

    @Override
    public void deleteStudyFromEPadAndDcm4CheeDatabases(String studyUID, boolean deleteAims) {
        // Now delete studies from dcm4chee and ePAD's database; includes deleting PNGs for studies.
        Set<String> seriesUIDs = dcm4CheeDatabaseOperations.getAllSeriesUIDsInStudy(studyUID);
        log.info("Found " + seriesUIDs.size() + " series in study " + studyUID);
        if (!seriesUIDs.isEmpty()) {
            log.info("Deleting study " + studyUID + " from dcm4chee's database");
            boolean success = Dcm4CheeOperations.deleteStudy(studyUID); // Must run after finding series in DCM4CHEE
            if (!success) { //do not throw error if the study doesn't have any series
                throw new RuntimeException("Error deleting study in dcm4chee");
            }
        }
        // First delete all series in study from ePAD's database; then delete the study itself.
        // Should not delete until after deleting study in DCM4CHEE or PNG pipeline will activate.
        for (String seriesUID : seriesUIDs) {
            log.info("Deleting series " + seriesUID + " from ePAD database");
            epadDatabaseOperations.deleteSeries(seriesUID);
        }
        log.info("Deleting study " + studyUID + " from ePAD database");
        epadDatabaseOperations.deleteStudy(studyUID);

        // Delete the underlying PNGs for the study
        PNGFilesOperations.deletePNGsForStudy(studyUID);

        if (deleteAims)
            deleteAllStudyAims(studyUID, false);
    }

    @Override
    public void deleteAllStudyAims(String studyUID, boolean deleteDSOs) {
        // Delete all Study AIMs
        StudyReference sref = new StudyReference(null, null, studyUID);
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(sref);
        for (EPADAIM aim : aims) {
            epadDatabaseOperations.deleteAIM("", aim.aimID);
            AIMUtil.deleteAIM(aim.aimID, aim.projectID);
        }
    }

    @Override
    public void deleteStudiesFromEPadAndDcm4CheeDatabases(Set<String> studyUIDs) {
        for (String studyUID : studyUIDs)
            deleteStudyFromEPadAndDcm4CheeDatabases(studyUID, true);
    }

    @Override
    public String createProjectAIM(String username, ProjectReference projectReference, String aimID, File aimFile,
            String sessionID) {
        try {
            EPADAIM aim = epadDatabaseOperations.getAIM(aimID);
            if (!"admin".equals(username)
                    && !projectOperations.hasAccessToProject(username, projectReference.projectID)
                    && (aim == null || !aim.userName.equalsIgnoreCase(username))) {
                log.warning("No permissions to update AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to update AIM:" + aimID + " for user " + username);
            }
            projectOperations.createEventLog(username, projectReference.projectID, null, null, null, null, aimID,
                    "CREATE AIM", aimFile.getName());
            if (aim != null && !aim.projectID.equals(projectReference.projectID)) {
                moveAIMtoProject(aim, projectReference.projectID, username);
            }
            if (!AIMUtil.saveAIMAnnotation(aimFile, projectReference.projectID, sessionID, username))
                return "";
            else
                return "Error saving AIM file";
        } catch (Exception e) {
            log.warning("Error saving AIM file ", e);
            return e.getMessage();
        }
    }

    private void moveAIMtoProject(EPADAIM aim, String projectID, String username) throws Exception {
        if (projectID.equals(EPADConfig.xnatUploadProjectID))
            throw new Exception("Invalid projectID for an AIM");
        String aimID = aim.aimID;
        if (aim.studyUID != null && aim.studyUID.length() > 0
                && projectOperations.isStudyInProjectAndSubject(projectID, aim.subjectID, aim.studyUID)) {
            epadDatabaseOperations.updateAIM(aimID, projectID, username);
        } else if (aim.subjectID != null && aim.subjectID.length() > 0
                && projectOperations.isSubjectInProject(aim.subjectID, projectID)) {
            epadDatabaseOperations.updateAIM(aimID, projectID, username);
        } else if (aim.subjectID == null || aim.subjectID.length() == 0) {
            epadDatabaseOperations.updateAIM(aimID, projectID, username);
        } else {
            throw new Exception("Invalid projectID for this AIM");
        }
    }

    @Override
    public String createSubjectAIM(String username, SubjectReference subjectReference, String aimID, File aimFile,
            String sessionID) {
        if (subjectReference.projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))
                || subjectReference.projectID.equals(EPADConfig.xnatUploadProjectID))
            return "AIM can not be added to project:" + subjectReference.projectID;
        try {
            projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                    null, null, aimID, "CREATE AIM", aimFile.getName());
            EPADAIM aim = epadDatabaseOperations.addAIM(username, subjectReference, aimID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to update AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to update AIM:" + aimID + " for user " + username);
            }
            if (!aim.projectID.equals(subjectReference.projectID)) {
                moveAIMtoProject(aim, subjectReference.projectID, username);
            }
            if (!AIMUtil.saveAIMAnnotation(aimFile, aim.projectID, sessionID, username))
                return "";
            else
                return "Error saving AIM file";
        } catch (Exception e) {
            log.warning("Error saving AIM file ", e);
            return e.getMessage();
        }
    }

    @Override
    public String createStudyAIM(String username, StudyReference studyReference, String aimID, File aimFile,
            String sessionID) {
        if (studyReference.projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))
                || studyReference.projectID.equals(EPADConfig.xnatUploadProjectID))
            return "AIM can not be added to project:" + studyReference.projectID;
        try {
            projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                    studyReference.studyUID, null, null, aimID, "CREATE AIM", aimFile.getName());
            EPADAIM aim = epadDatabaseOperations.addAIM(username, studyReference, aimID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to update AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to update AIM:" + aimID + " for user " + username);
            }
            if (!aim.projectID.equals(studyReference.projectID)) {
                moveAIMtoProject(aim, studyReference.projectID, username);
            }
            if (!AIMUtil.saveAIMAnnotation(aimFile, aim.projectID, sessionID, username))
                return "";
            else
                return "Error saving AIM file";
        } catch (Exception e) {
            log.warning("Error saving AIM file ", e);
            return e.getMessage();
        }
    }

    @Override
    public String createSeriesAIM(String username, SeriesReference seriesReference, String aimID, File aimFile,
            String sessionID) {
        if (seriesReference.projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))
                || seriesReference.projectID.equals(EPADConfig.xnatUploadProjectID))
            return "AIM can not be added to project:" + seriesReference.projectID;
        try {
            projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                    seriesReference.studyUID, seriesReference.seriesUID, null, aimID, "CREATE AIM",
                    aimFile.getName());
            EPADAIM aim = epadDatabaseOperations.addAIM(username, seriesReference, aimID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to update AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to update AIM:" + aimID + " for user " + username);
            }
            if (!aim.projectID.equals(seriesReference.projectID)) {
                moveAIMtoProject(aim, seriesReference.projectID, username);
            }
            if (!AIMUtil.saveAIMAnnotation(aimFile, aim.projectID, sessionID, username))
                return "";
            else
                return "Error saving AIM file";
        } catch (Exception e) {
            log.warning("Error saving AIM file ", e);
            return e.getMessage();
        }
    }

    @Override
    public String createImageAIM(String username, ImageReference imageReference, String aimID, File aimFile,
            String sessionID) {
        if (imageReference.projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))
                || imageReference.projectID.equals(EPADConfig.xnatUploadProjectID))
            return "AIM can not be added to project:" + imageReference.projectID;
        try {
            projectOperations.createEventLog(username, imageReference.projectID, imageReference.subjectID,
                    imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID, aimID, "CREATE AIM",
                    aimFile.getName());
            EPADAIM aim = epadDatabaseOperations.addAIM(username, imageReference, aimID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to update AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to update AIM:" + aimID + " for user " + username);
            }
            if (!aim.projectID.equals(imageReference.projectID)) {
                moveAIMtoProject(aim, imageReference.projectID, username);
            }
            if (!AIMUtil.saveAIMAnnotation(aimFile, aim.projectID, sessionID, username))
                return "";
            else
                return "Error saving AIM file";
        } catch (Exception e) {
            log.warning("Error saving AIM file ", e);
            return e.getMessage();
        }
    }

    @Override
    public String createFrameAIM(String username, FrameReference frameReference, String aimID, File aimFile,
            String sessionID) {
        if (frameReference.projectID.equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))
                || frameReference.projectID.equals(EPADConfig.xnatUploadProjectID))
            return "AIM can not be added to project:" + frameReference.projectID;
        try {
            projectOperations.createEventLog(username, frameReference.projectID, frameReference.subjectID,
                    frameReference.studyUID, frameReference.seriesUID, frameReference.imageUID, aimID, "CREATE AIM",
                    aimFile.getName() + ":" + frameReference.frameNumber);
            EPADAIM aim = epadDatabaseOperations.addAIM(username, frameReference, aimID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to update AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to update AIM:" + aimID + " for user " + username);
            }
            if (!aim.projectID.equals(frameReference.projectID)) {
                moveAIMtoProject(aim, frameReference.projectID, username);
            }
            if (!AIMUtil.saveAIMAnnotation(aimFile, aim.projectID, frameReference.frameNumber, sessionID, username,
                    false))
                return "";
            else
                return "Error saving AIM file";
        } catch (Exception e) {
            log.warning("Error saving AIM file ", e);
            return e.getMessage();
        }
    }

    @Override
    public int projectAIMDelete(ProjectReference projectReference, String aimID, String sessionID,
            boolean deleteDSO, String username) throws Exception {
        try {
            projectOperations.createEventLog(username, projectReference.projectID, null, null, null, null, aimID,
                    "DELETE AIM", "deleteDSO:" + deleteDSO);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (aim == null) {
                log.warning("AIM " + aimID + " not found");
                return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
            }
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (!aim.projectID.equals(projectReference.projectID)) {
                epadDatabaseOperations.removeProjectFromAIM(projectReference.projectID, aimID);
                return HttpServletResponse.SC_OK;
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            log.info("Deleting AIM, deleteDSO:" + deleteDSO + " dsoSeriesUID:" + aim.dsoSeriesUID + " aimID:"
                    + aimID);
            AIMUtil.deleteAIM(aimID, projectReference.projectID);
            epadDatabaseOperations.deleteAIM(username, projectReference, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                log.info("Deleting DSO Series:" + aim.dsoSeriesUID + " In project:" + aim.projectID);
                this.deleteSeries(new SeriesReference(projectReference.projectID, aim.subjectID, aim.studyUID,
                        aim.dsoSeriesUID), false);
            }
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0) {
                List<EPADAIM> otheraims = epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID);
                if (otheraims.size() == 0 || (otheraims.size() == 1
                        && otheraims.get(0).projectID.equals(EPADConfig.xnatUploadProjectID))) {
                    String error = this.deleteSeries(new SeriesReference(projectReference.projectID, aim.subjectID,
                            aim.studyUID, aim.dsoSeriesUID), false);
                    if (error != null && error.length() > 0) {
                        log.warning("Error deleting DSO, seriesUID:" + aim.dsoSeriesUID);
                        epadDatabaseOperations.insertEpadEvent(username, "Error deleting DSO Series",
                                aim.dsoSeriesUID, "", aim.subjectID, aim.subjectID, aim.studyUID,
                                projectReference.projectID, error);
                    }
                } else {
                    log.info("DSO not deleted, seriesUID:" + aim.dsoSeriesUID);
                    epadDatabaseOperations.insertEpadEvent(username, "DSO Series not deleted", aim.dsoSeriesUID, "",
                            aim.subjectID, aim.subjectID, aim.studyUID, projectReference.projectID,
                            "DSO referenced by another AIM in " + otheraims.get(0).projectID);
                }
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public int subjectAIMDelete(SubjectReference subjectReference, String aimID, String sessionID,
            boolean deleteDSO, String username) throws Exception {
        try {
            projectOperations.createEventLog(username, subjectReference.projectID, subjectReference.subjectID, null,
                    null, null, aimID, "DELETE AIM", "deleteDSO:" + deleteDSO);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            AIMUtil.deleteAIM(aimID, subjectReference.projectID);
            epadDatabaseOperations.deleteAIM(username, subjectReference, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                this.deleteSeries(new SeriesReference(subjectReference.projectID, aim.subjectID, aim.studyUID,
                        aim.dsoSeriesUID), false);
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public int studyAIMDelete(StudyReference studyReference, String aimID, String sessionID, boolean deleteDSO,
            String username) throws Exception {
        try {
            projectOperations.createEventLog(username, studyReference.projectID, studyReference.subjectID,
                    studyReference.studyUID, null, null, aimID, "DELETE AIM", "deleteDSO:" + deleteDSO);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            AIMUtil.deleteAIM(aimID, studyReference.projectID);
            epadDatabaseOperations.deleteAIM(username, studyReference, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                this.deleteSeries(new SeriesReference(studyReference.projectID, aim.subjectID, aim.studyUID,
                        aim.dsoSeriesUID), false);
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public int seriesAIMDelete(SeriesReference seriesReference, String aimID, String sessionID, boolean deleteDSO,
            String username) throws Exception {
        try {
            projectOperations.createEventLog(username, seriesReference.projectID, seriesReference.subjectID,
                    seriesReference.studyUID, seriesReference.seriesUID, null, aimID, "DELETE AIM",
                    "deleteDSO:" + deleteDSO);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            AIMUtil.deleteAIM(aimID, seriesReference.projectID);
            epadDatabaseOperations.deleteAIM(username, seriesReference, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0) {
                List<EPADAIM> otheraims = epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID);
                if (otheraims.size() == 0) {
                    String error = this.deleteSeries(new SeriesReference(seriesReference.projectID, aim.subjectID,
                            aim.studyUID, aim.dsoSeriesUID), false);
                    if (error != null && error.length() > 0)
                        log.warning("Error deleting DSO, seriesUID:" + aim.dsoSeriesUID);
                    epadDatabaseOperations.insertEpadEvent(username, "Error deleting DSO Series", aim.dsoSeriesUID,
                            "", aim.subjectID, aim.subjectID, aim.studyUID, seriesReference.projectID, error);
                } else {
                    log.info("DSO not deleted, seriesUID:" + aim.dsoSeriesUID);
                    epadDatabaseOperations.insertEpadEvent(username, "DSO Series not deleted", aim.dsoSeriesUID, "",
                            aim.subjectID, aim.subjectID, aim.studyUID, seriesReference.projectID,
                            "DSO referenced by another AIM in " + otheraims.get(0).projectID);
                }
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public int imageAIMDelete(ImageReference imageReference, String aimID, String sessionID, boolean deleteDSO,
            String username) throws Exception {
        try {
            projectOperations.createEventLog(username, imageReference.projectID, imageReference.subjectID,
                    imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID, aimID, "DELETE AIM",
                    "deleteDSO:" + deleteDSO);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            AIMUtil.deleteAIM(aimID, imageReference.projectID);
            epadDatabaseOperations.deleteAIM(username, imageReference, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                this.deleteSeries(new SeriesReference(imageReference.projectID, aim.subjectID, aim.studyUID,
                        aim.dsoSeriesUID), false);
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public int frameAIMDelete(FrameReference frameReference, String aimID, String sessionID, boolean deleteDSO,
            String username) throws Exception {
        try {
            projectOperations.createEventLog(username, frameReference.projectID, frameReference.subjectID,
                    frameReference.studyUID, frameReference.seriesUID, frameReference.imageUID, aimID, "DELETE AIM",
                    "deleteDSO:" + deleteDSO + ":" + frameReference.frameNumber);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            AIMUtil.deleteAIM(aimID, frameReference.projectID);
            epadDatabaseOperations.deleteAIM(username, frameReference, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                this.deleteSeries(new SeriesReference(frameReference.projectID, aim.subjectID, aim.studyUID,
                        aim.dsoSeriesUID), false);
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public int aimDelete(String aimID, String sessionID, boolean deleteDSO, String username) throws Exception {
        try {
            projectOperations.createEventLog(username, null, null, null, null, null, aimID, "DELETE AIM",
                    "deleteDSO:" + deleteDSO);
            EPADAIM aim = getAIMDescription(aimID, username, sessionID);
            if (!"admin".equals(username) && !aim.userName.equalsIgnoreCase(username)
                    && !aim.userName.equalsIgnoreCase("shared")
                    && !UserProjectService.isOwner(sessionID, username, aim.projectID)) {
                log.warning("No permissions to delete AIM:" + aimID + " for user " + username);
                throw new Exception("No permissions to delete AIM:" + aimID + " for user " + username);
            }
            if (AIMUtil.isPluginStillRunning(aimID))
                throw new Exception(aimID + " is still being processed by the plugin");
            AIMUtil.deleteAIM(aimID, aim.projectID);
            epadDatabaseOperations.deleteAIM(username, aimID);
            if (deleteDSO && aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0
                    && epadDatabaseOperations.getAIMsByDSOSeries(aim.dsoSeriesUID).size() == 0) {
                this.deleteSeries(new SeriesReference(aim.projectID, aim.subjectID, aim.studyUID, aim.dsoSeriesUID),
                        false);
            }
            return HttpServletResponse.SC_OK;
        } catch (Exception e) {
            log.warning("Error deleting AIM file ", e);
            throw e;
        }
    }

    @Override
    public EPADAIMList getProjectAIMDescriptions(ProjectReference projectReference, String username,
            String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(projectReference);
        for (int i = 0; i < aims.size(); i++) {
            if (!projectReference.projectID.equals(aims.get(i).projectID)) {
                aims.remove(i);
                i--;
                continue;
            }
            EPADAIM aim = aims.get(i);
            if (aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0) {
                Map<String, String> seriesMap = dcm4CheeDatabaseOperations.getSeriesData(aim.dsoSeriesUID);
                if (seriesMap.keySet().isEmpty()) {
                    aims.remove(i--);
                    if (aim.templateType != null && aim.templateType.equals("SEG")) {
                        try {
                            AIMUtil.deleteAIM(aim.aimID, aim.projectID);
                        } catch (Exception x) {
                        }
                        ;
                    }
                }
            }
            SeriesProcessingStatus status = epadDatabaseOperations.getSeriesProcessingStatus(aim.dsoSeriesUID);
            if (status != null)
                aim.dsoStatus = status.name();
        }
        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIMList getSubjectAIMDescriptions(SubjectReference subjectReference, String username,
            String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(subjectReference);
        List<EPADAIM> sharedAims = epadDatabaseOperations.getSharedAIMs(subjectReference.projectID,
                subjectReference.subjectID, null);
        for (EPADAIM aim : sharedAims) {
            aims.add(aim);
        }
        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIM getProjectAIMDescription(ProjectReference projectReference, String aimID, String username,
            String sessionID) {
        return epadDatabaseOperations.getAIM(projectReference, aimID);
    }

    @Override
    public EPADAIM getSubjectAIMDescription(SubjectReference subjectReference, String aimID, String username,
            String sessionID) {
        return epadDatabaseOperations.getAIM(subjectReference, aimID);
    }

    @Override
    public EPADAIM getStudyAIMDescription(StudyReference studyReference, String aimID, String username,
            String sessionID) {
        return epadDatabaseOperations.getAIM(studyReference, aimID);
    }

    @Override
    public EPADAIM getSeriesAIMDescription(SeriesReference seriesReference, String aimID, String username,
            String sessionID) {
        return epadDatabaseOperations.getAIM(seriesReference, aimID);
    }

    @Override
    public EPADAIM getImageAIMDescription(ImageReference imageReference, String aimID, String username,
            String sessionID) {
        return epadDatabaseOperations.getAIM(imageReference, aimID);
    }

    @Override
    public EPADAIM getFrameAIMDescription(FrameReference frameReference, String aimID, String username,
            String sessionID) {
        return epadDatabaseOperations.getAIM(frameReference, aimID);
    }

    @Override
    public EPADAIMList getStudyAIMDescriptions(StudyReference studyReference, String username, String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(studyReference);

        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIMList getSeriesAIMDescriptions(SeriesReference seriesReference, String username,
            String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(seriesReference);
        List<EPADAIM> sharedAims = epadDatabaseOperations.getSharedAIMs(seriesReference.projectID,
                seriesReference.subjectID, seriesReference.seriesUID);
        for (EPADAIM aim : sharedAims) {
            aims.add(aim);
        }
        for (int i = 0; i < aims.size(); i++) {
            EPADAIM aim = aims.get(i);
            if (aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0) {
                Map<String, String> seriesMap = dcm4CheeDatabaseOperations.getSeriesData(aim.dsoSeriesUID);
                if (seriesMap.keySet().isEmpty()) {
                    aims.remove(i--);
                }
            }
            SeriesProcessingStatus status = epadDatabaseOperations.getSeriesProcessingStatus(aim.dsoSeriesUID);
            if (status != null)
                aim.dsoStatus = status.name();
        }
        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIMList getSeriesAIMDescriptions(SeriesReference seriesReference, String username, String sessionID,
            boolean includeStudyAims) {
        EPADAIMList aims = this.getSeriesAIMDescriptions(seriesReference, username, sessionID);
        StudyReference studyReference = new StudyReference(seriesReference.projectID, seriesReference.subjectID,
                seriesReference.studyUID);
        EPADAIMList studyaims = this.getStudyAIMDescriptions(studyReference, username, sessionID);
        for (EPADAIM aim : aims.ResultSet.Result) {
            studyaims.addAIM(aim);
        }
        return studyaims;
    }

    @Override
    public EPADAIMList getImageAIMDescriptions(ImageReference imageReference, String username, String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(imageReference);

        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIMList getFrameAIMDescriptions(FrameReference frameReference, String username, String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(frameReference);

        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIMList getAIMDescriptions(String projectID, AIMSearchType aimSearchType, String searchValue,
            String username, String sessionID, int start, int count) {
        List<EPADAIM> aims = epadDatabaseOperations.getAIMs(projectID, aimSearchType, searchValue, start, count);
        for (int i = 0; i < aims.size(); i++) {
            EPADAIM aim = aims.get(i);
            if (aim.dsoSeriesUID != null && aim.dsoSeriesUID.length() > 0) {
                Map<String, String> seriesMap = dcm4CheeDatabaseOperations.getSeriesData(aim.dsoSeriesUID);
                if (seriesMap.keySet().isEmpty()) {
                    aims.remove(i--);
                    if (aim.templateType != null && aim.templateType.equals("SEG")) {
                        try {
                            AIMUtil.deleteAIM(aim.aimID, aim.projectID);
                        } catch (Exception x) {
                        }
                        ;
                    }
                }
            }
            SeriesProcessingStatus status = epadDatabaseOperations.getSeriesProcessingStatus(aim.dsoSeriesUID);
            if (status != null)
                aim.dsoStatus = status.name();
        }

        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIMList getAIMDescriptionsForUser(String username, String sessionID) {
        List<EPADAIM> aims = epadDatabaseOperations
                .getAIMsByQuery("UserLoginName = '" + username + "' order by PatientID asc, UpdateTime desc");

        return new EPADAIMList(aims);
    }

    @Override
    public EPADAIM getAIMDescription(String aimID, String username, String sessionID) {
        return epadDatabaseOperations.getAIM(aimID);
    }

    @Override
    public Collection<EPADSession> getCurrentSessions(String username) throws Exception {
        User user = projectOperations.getUser(username);
        if (!user.isAdmin())
            throw new Exception("No permissions for requested data");
        Map<String, EPADSession> sessions = EPADSessionOperations.getCurrentSessions();
        return sessions.values();
    }

    @Override
    public EPADUsageList getUsageSummary(String username) throws Exception {
        String sql = " createdtime =(select max(createdtime) from epadstatistics b where b.host = a.host) group by host order by host";
        List<EpadStatistics> stats = new EpadStatistics().getObjects(sql);
        EPADUsageList eul = new EPADUsageList();
        for (EpadStatistics stat : stats) {
            eul.addUsage(new EPADUsage(stat.getHost(), stat.getNumOfUsers(), stat.getNumOfProjects(),
                    stat.getNumOfPatients(), stat.getNumOfStudies(), stat.getNumOfSeries(), stat.getNumOfAims(),
                    stat.getNumOfDSOs(), stat.getNumOfPacs(), stat.getNumOfAutoQueries(), stat.getNumOfWorkLists(),
                    stat.getNumOfFiles(), stat.getNumOfTemplates(), stat.getNumOfPlugins(),
                    dateformat.format(stat.getCreatedTime())));
        }
        return eul;
    }

    @Override
    public EPADUsageList getMonthlyUsageSummary() throws Exception {
        List<EpadStatisticsMonthly> stats = new EpadStatisticsMonthly().getObjects("");
        EPADUsageList eul = new EPADUsageList();
        for (EpadStatisticsMonthly stat : stats) {
            eul.addUsage(new EPADUsage("", stat.getNumOfUsers(), stat.getNumOfProjects(), stat.getNumOfPatients(),
                    stat.getNumOfStudies(), stat.getNumOfSeries(), stat.getNumOfAims(), stat.getNumOfDSOs(),
                    stat.getNumOfPacs(), stat.getNumOfAutoQueries(), stat.getNumOfWorkLists(), stat.getNumOfFiles(),
                    stat.getNumOfTemplates(), stat.getNumOfPlugins(), dateformat.format(stat.getCreatedTime())));
        }
        return eul;
    }

    @Override
    public EPADUsageList getMonthlyUsageSummaryForMonth(int month) throws Exception {
        String sql = " month(createdtime)=" + month;
        List<EpadStatisticsMonthly> stats = new EpadStatisticsMonthly().getObjects(sql);
        EPADUsageList eul = new EPADUsageList();
        for (EpadStatisticsMonthly stat : stats) {
            eul.addUsage(new EPADUsage("", stat.getNumOfUsers(), stat.getNumOfProjects(), stat.getNumOfPatients(),
                    stat.getNumOfStudies(), stat.getNumOfSeries(), stat.getNumOfAims(), stat.getNumOfDSOs(),
                    stat.getNumOfPacs(), stat.getNumOfAutoQueries(), stat.getNumOfWorkLists(), stat.getNumOfFiles(),
                    stat.getNumOfTemplates(), stat.getNumOfPlugins(), dateformat.format(stat.getCreatedTime())));
        }
        return eul;
    }

    @Override
    public EPADTemplateUsageList getTemplateStatSummary() throws Exception {
        String sql = "createdtime >(((select max(createdtime) from epadstatistics_template b where b.host = a.host)- INTERVAL 1 HOUR))  group by host,templatecode order by host,templatecode";
        log.info("template stat query: " + sql);
        List<EpadStatisticsTemplate> stats = new EpadStatisticsTemplate().getObjects(sql);
        EPADTemplateUsageList eul = new EPADTemplateUsageList();
        for (EpadStatisticsTemplate stat : stats) {
            eul.addTemplateUsage(new EPADTemplateUsage(stat.getHost(), stat.getTemplateLevelType(),
                    stat.getTemplateName(), stat.getAuthors(), stat.getVersion(), stat.getTemplateDescription(),
                    stat.getTemplateType(), stat.getTemplateCode(), stat.getNumOfAims(), null,
                    dateformat.format(stat.getCreatedTime())));
        }
        return eul;
    }

    @Override
    public EPADTemplateUsageList getTemplateStatSummaryWithXML() throws Exception {
        String sql = "createdtime >(((select max(createdtime) from epadstatistics_template b where b.host = a.host)- INTERVAL 1 HOUR))  group by host,templatecode order by host,templatecode";
        log.info("template stat query: " + sql);
        List<EpadStatisticsTemplate> stats = new EpadStatisticsTemplate().getObjects(sql);
        EPADTemplateUsageList eul = new EPADTemplateUsageList();
        for (EpadStatisticsTemplate stat : stats) {
            eul.addTemplateUsage(new EPADTemplateUsage(stat.getHost(), stat.getTemplateLevelType(),
                    stat.getTemplateName(), stat.getAuthors(), stat.getVersion(), stat.getTemplateDescription(),
                    stat.getTemplateType(), stat.getTemplateCode(), stat.getNumOfAims(), stat.getTemplateText(),
                    dateformat.format(stat.getCreatedTime())));
        }
        return eul;
    }

    @Override
    public int getActiveCount(int days) throws Exception {
        String sql = "createdtime >(( NOW( ) - INTERVAL " + days
                + " DAY)) and createdtime =(select max(createdtime) from epadstatistics b where b.host = a.host) group by host order by host";
        log.info("active count query: " + sql);
        List<EpadStatistics> stats = new EpadStatistics().getObjects(sql);
        return stats.size();
    }

    @Override
    public EPADUsageList getUsage(String username, String hostname, boolean byMonth, boolean byYear, boolean all)
            throws Exception {
        String sql = "host like '" + hostname.replace('*', '%') + "%' order by host, createdtime desc";
        if (!all && !byMonth && !byYear)
            sql = "host like '" + hostname.replace('*', '%')
                    + "%' and createdtime =(select max(createdtime) from epadstatistics b where b.host = a.host)";
        List<EpadStatistics> stats = new EpadStatistics().getObjects(sql);
        EpadStatistics total = new EpadStatistics();
        EPADUsageList eul = new EPADUsageList();
        int prevDay = -1;
        Date lastDate = null;
        Set<String> counted = new HashSet<String>();
        for (EpadStatistics stat : stats) {
            if (byMonth) {
                Date date = stat.getCreatedTime();
                if (!isLastDayOfMonth(date)
                        || counted.contains(stat.getHost() + "_" + getDayOfYear(stat.getCreatedTime())))
                    continue;
            }
            if (byYear) {
                Date date = stat.getCreatedTime();
                if (!isLastDayOfYear(date)
                        || counted.contains(stat.getHost() + "_" + getDayOfYear(stat.getCreatedTime())))
                    continue;
            }
            counted.add(stat.getHost() + "_" + getDayOfYear(stat.getCreatedTime()));
            if (prevDay != -1 && prevDay != getDayOfYear(stat.getCreatedTime()) && (byMonth || byYear)
                    && hostname.equals("*")) {
                eul.addUsage(new EPADUsage("Total", total.getNumOfUsers(), total.getNumOfProjects(),
                        total.getNumOfPatients(), total.getNumOfStudies(), total.getNumOfSeries(),
                        total.getNumOfAims(), total.getNumOfDSOs(), total.getNumOfPacs(),
                        total.getNumOfAutoQueries(), total.getNumOfWorkLists(),
                        dateformat.format(stat.getCreatedTime())));
                total = new EpadStatistics();
            }
            eul.addUsage(new EPADUsage(stat.getHost(), stat.getNumOfUsers(), stat.getNumOfProjects(),
                    stat.getNumOfPatients(), stat.getNumOfStudies(), stat.getNumOfSeries(), stat.getNumOfAims(),
                    stat.getNumOfDSOs(), stat.getNumOfPacs(), stat.getNumOfAutoQueries(), stat.getNumOfWorkLists(),
                    dateformat.format(stat.getCreatedTime())));
            total.addStatistics(stat);
            prevDay = getDayOfYear(stat.getCreatedTime());
            lastDate = stat.getCreatedTime();
        }
        if ((!all || byMonth || byYear) && hostname.contains("*")) {
            eul.addUsage(new EPADUsage("Total", total.getNumOfUsers(), total.getNumOfProjects(),
                    total.getNumOfPatients(), total.getNumOfStudies(), total.getNumOfSeries(), total.getNumOfAims(),
                    total.getNumOfDSOs(), total.getNumOfPacs(), total.getNumOfAutoQueries(),
                    total.getNumOfWorkLists(), dateformat.format(lastDate)));
        }
        return eul;
    }

    boolean isLastDayOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int month = cal.get(Calendar.MONTH);
        cal.add(Calendar.DATE, 1);
        if (cal.get(Calendar.MONTH) != month)
            return true;
        else
            return false;
    }

    boolean isLastDayOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int year = cal.get(Calendar.YEAR);
        cal.add(Calendar.DATE, 1);
        if (cal.get(Calendar.YEAR) != year)
            return true;
        else
            return false;
    }

    int getDayOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_YEAR);
    }

    @Override
    public EPADEventLogList getEventLogs(String loggedInUserName, String username, int start, int count)
            throws Exception {
        User loggedInUser = projectOperations.getUser(loggedInUserName);
        if (!loggedInUser.isAdmin() && !loggedInUserName.equals(username))
            throw new Exception("No permissions for requested data");
        EPADEventLogList elist = new EPADEventLogList();
        List<EventLog> elogs = projectOperations.getUseEventLogs(username, start, count);
        //      if (count > 0 && elogs.size() > (start+count))
        //      {
        //         elogs = elogs.subList(start, start+count);
        //      }
        for (EventLog elog : elogs) {
            EPADEventLog log = new EPADEventLog(this.formatDateTime(elog.getCreatedTime()), elog.getUsername(),
                    elog.getProjectID(), elog.getSubjectUID(), elog.getStudyUID(), elog.getSeriesUID(),
                    elog.getImageUID(), elog.getAimID(), elog.getFunction(), elog.getParams());
            if (elog.getProjectID() != null && elog.getProjectID().length() > 0) {
                Project project = projectOperations.getProject(elog.getProjectID());
                if (project != null)
                    log.projectName = project.getName();
            }
            if (elog.getSubjectUID() != null && elog.getSubjectUID().length() > 0) {
                Subject subject = projectOperations.getSubject(elog.getSubjectUID());
                if (subject != null)
                    log.subjectName = subject.getName();
            }
            if (elog.getAimID() != null && elog.getAimID().length() > 0) {
                EPADAIM aim = epadDatabaseOperations.getAIM(elog.getAimID());
                if (aim != null)
                    log.aimName = aim.name;
            }
            if (elog.isError())
                log.errorMessage = elog.getParams();
            elist.addEPADEventLog(log);
        }
        return elist;
    }

    @Override
    public EPADObjectList getTaskStatuses(String loggedInUserName, String username) throws Exception {
        User loggedInUser = projectOperations.getUser(loggedInUserName);
        if (!loggedInUser.isAdmin() && !loggedInUserName.equals(username))
            throw new Exception("No permissions for requested data");
        EPADObjectList list = new EPADObjectList();
        Collection<TaskStatus> tasks = projectOperations.getUser(username).getCurrentTasks().values();
        List<TaskStatus> tss = new ArrayList<TaskStatus>();
        tss.addAll(tasks);
        Collections.sort(tss, new TSComparator());
        for (TaskStatus task : tss) {
            list.addObject(task);
        }
        return list;
    }

    public static Date getDate(String dateStr) {
        if (dateStr == null || dateStr.length() == 0)
            return new Date();
        try {
            return dateTimeFormat.parse(dateStr);
        } catch (Exception x) {
        }
        return null;
    }

    public class TSComparator implements Comparator<TaskStatus> {
        public int compare(TaskStatus o1, TaskStatus o2) {
            try {
                //            if (o2.completetime != null)
                //               return getDate(o2.completetime).compareTo(getDate(o1.completetime));
                //            else
                return getDate(o2.starttime).compareTo(getDate(o1.starttime));
            } catch (Exception x) {
            }
            return 0;
        }
    }

    @Override
    public EPADWorklistList getWorkListsForUser(String loggedInUserName, String username) throws Exception {
        List<WorkList> worklists = null;
        if (projectOperations.isAdmin(loggedInUserName) && username.equals("*")) {
            worklists = workListOperations.getAllWorkLists();
        } else {
            worklists = workListOperations.getWorkListsForUser(username);
            List<WorkList> worklist2 = workListOperations.getWorkListsByUser(username);
            for (WorkList wl : worklist2) {
                if (!worklists.contains(wl))
                    worklists.add(wl);
            }
        }
        EPADWorklistList wllist = new EPADWorklistList();
        for (WorkList wl : worklists) {
            List<Subject> subjects = workListOperations.getSubjectsForWorkList(wl.getWorkListID());
            List<Study> studies = workListOperations.getStudiesForWorkList(wl.getWorkListID());
            List<String> subjectIDs = new ArrayList<String>();
            List<String> studyUIDs = new ArrayList<String>();
            List<String> statuses = new ArrayList<String>();
            List<String> projectIDs = new ArrayList<String>();
            for (Subject subject : subjects) {
                subjectIDs.add(subject.getSubjectUID());
                projectIDs.add(subject.getProjectID());
                statuses.add(subject.getStatus());
            }
            for (Study study : studies) {
                studyUIDs.add(study.getStudyUID());
                projectIDs.add(study.getProjectID());
                statuses.add(study.getStatus());
            }
            User user = (User) projectOperations.getDBObject(User.class, wl.getUserId());
            wllist.addEPADWorklist(
                    new EPADWorklist(wl.getWorkListID(), user.getUsername(), wl.getName(), wl.getDescription(),
                            wl.getStatus(), formatDate(wl.getStartDate()), formatDate(wl.getCompleteDate()),
                            formatDate(wl.getDueDate()), projectIDs, studyUIDs, statuses));
        }
        return wllist;
    }

    @Override
    public EPADWorklistStudyList getWorkListStudies(String loggedInUserName, String username, String workListID)
            throws Exception {
        WorkList wl = workListOperations.getWorkList(workListID);
        if (wl == null)
            throw new Exception("Worklist " + workListID + " not found");
        User user = (User) projectOperations.getDBObject(User.class, wl.getUserId());
        //      Set<Subject> subjects = workListOperations.getSubjectsForWorkListWithStatus(wl.getWorkListID());
        //      List<String> subjectIDs = new ArrayList<String>();
        //      List<String> studyUIDs = new ArrayList<String>();
        //      List<String> subjectStatus = new ArrayList<String>();
        //      List<String> studyStatus = new ArrayList<String>();
        //      for (Subject subject: subjects)
        //      {
        //         subjectIDs.add(subject.getSubjectUID());
        //         subjectStatus.add(subject.getSubjectUID() + ":" + subject.getStatus());
        //      }
        List<WorkListToStudy> wstudies = workListOperations.getWorkListStudies(wl.getWorkListID());
        EPADWorklistStudyList wlsl = new EPADWorklistStudyList();
        for (WorkListToStudy wstudy : wstudies) {
            Study study = (Study) projectOperations.getDBObject(Study.class, wstudy.getStudyId());
            Subject subject = (Subject) projectOperations.getDBObject(Subject.class, study.getSubjectId());
            Project project = (Project) projectOperations.getDBObject(Project.class, wstudy.getProjectId());
            EPADWorklistStudy wls = new EPADWorklistStudy(workListID, username, project.getProjectId(),
                    subject.getSubjectUID(), study.getStudyUID(), wstudy.getStatus(),
                    formatDate(wstudy.getStartDate()), formatDate(wstudy.getCompleteDate()));
            wls.workListName = wl.getName();
            wls.sortOrder = wstudy.getSortOrder();
            wlsl.addEPADWorklistStudy(wls);
        }
        return wlsl;
    }

    @Override
    public EPADWorklistSubjectList getWorkListSubjects(String loggedInUserName, String username, String workListID)
            throws Exception {
        WorkList wl = workListOperations.getWorkList(workListID);
        if (wl == null)
            throw new Exception("Worklist " + workListID + " not found");
        User user = (User) projectOperations.getDBObject(User.class, wl.getUserId());
        List<WorkListToSubject> wsubjects = workListOperations.getWorkListSubjects(wl.getWorkListID());
        EPADWorklistSubjectList wlsl = new EPADWorklistSubjectList();
        for (WorkListToSubject wsubject : wsubjects) {
            Subject subject = (Subject) projectOperations.getDBObject(Subject.class, wsubject.getSubjectId());
            Project project = (Project) projectOperations.getDBObject(Project.class, wsubject.getProjectId());
            EPADWorklistSubject wls = new EPADWorklistSubject(workListID, username, project.getProjectId(),
                    subject.getSubjectUID(), subject.getName(), wsubject.getStatus(),
                    formatDate(wsubject.getStartDate()), formatDate(wsubject.getCompleteDate()));
            SubjectReference reference = new SubjectReference(null, subject.getSubjectUID());
            int count = epadDatabaseOperations.getNumberOfAIMs(username, reference);
            wls.workListName = wl.getName();
            wls.sortOrder = wsubject.getSortOrder();
            wls.numberOfAnnotations = count;
            wlsl.addEPADWorklistSubject(wls);
        }
        return wlsl;
    }

    @Override
    public EPADWorklist getWorkListByID(String loggedInUserName, String username, String workListID)
            throws Exception {
        WorkList wl = workListOperations.getWorkList(workListID);
        User user = (User) projectOperations.getDBObject(User.class, wl.getUserId());
        if (username != null && !username.equals(user.getUsername()))
            throw new Exception("Username for worklist " + workListID + " does not match " + username);
        List<Subject> subjects = workListOperations.getSubjectsForWorkList(wl.getWorkListID());
        List<Study> studies = workListOperations.getStudiesForWorkList(wl.getWorkListID());
        List<String> subjectIDs = new ArrayList<String>();
        List<String> studyUIDs = new ArrayList<String>();
        List<String> statuses = new ArrayList<String>();
        List<String> projectIDs = new ArrayList<String>();
        for (Subject subject : subjects) {
            subjectIDs.add(subject.getSubjectUID());
            projectIDs.add(subject.getProjectID());
            statuses.add(subject.getStatus());
        }
        for (Study study : studies) {
            studyUIDs.add(study.getStudyUID());
            projectIDs.add(study.getProjectID());
            statuses.add(study.getStatus());
        }

        return new EPADWorklist(wl.getWorkListID(), user.getUsername(), wl.getName(), wl.getDescription(),
                wl.getStatus(), formatDate(wl.getStartDate()), formatDate(wl.getCompleteDate()),
                formatDate(wl.getDueDate()), projectIDs, studyUIDs, statuses);
    }

    private EPADStudy dcm4cheeStudy2EpadStudy(String sessionID, String suppliedProjectID, String suppliedSubjectID,
            DCM4CHEEStudy dcm4CheeStudy, String username) {
        return dcm4cheeStudy2EpadStudy(sessionID, suppliedProjectID, suppliedSubjectID, dcm4CheeStudy, username,
                false);
    }

    private EPADStudy dcm4cheeStudy2EpadStudy(String sessionID, String suppliedProjectID, String suppliedSubjectID,
            DCM4CHEEStudy dcm4CheeStudy, String username, boolean includeAnnotationStatus) {
        String projectID = suppliedProjectID == null || suppliedProjectID.equals("")
                ? EPADConfig.xnatUploadProjectID
                : suppliedProjectID;
        String patientName = dcm4CheeStudy.patientName;
        String xnatPatientID = XNATUtil.subjectID2XNATSubjectLabel(dcm4CheeStudy.patientID);
        String subjectID = suppliedSubjectID.equals("") ? xnatPatientID : suppliedSubjectID;
        String studyUID = dcm4CheeStudy.studyUID;
        String insertDate = dcm4CheeStudy.dateAcquired; // studyDate
        String firstSeriesUID = dcm4CheeStudy.firstSeriesUID;
        String firstSeriesDateAcquired = dcm4CheeStudy.firstSeriesDateAcquired;
        String physicianName = dcm4CheeStudy.physicianName;
        String birthdate = dcm4CheeStudy.birthdate;
        String sex = dcm4CheeStudy.sex;
        String studyDescription = dcm4CheeStudy.studyDescription;
        String studyAccessionNumber = dcm4CheeStudy.studyAccessionNumber;
        String createdTime = dcm4CheeStudy.createdTime;
        Set<String> examTypes = getExamTypesForStudy(studyUID);
        int numberOfSeries = dcm4CheeStudy.seriesCount;
        int numberOfImages = dcm4CheeStudy.imagesCount;
        Set<String> seriesUIDs = dcm4CheeDatabaseOperations.getAllSeriesUIDsInStudy(studyUID);
        StudyProcessingStatus studyProcessingStatus = getStudyProcessingStatus(studyUID);
        //      //int numberOfAnnotations = (seriesUIDs.size() <= 0) ? 0 : AIMQueries.getNumberOfAIMAnnotationsForSeriesSet(seriesUIDs, username);
        //      EPADAIMList aims = getStudyAIMDescriptions(new StudyReference(suppliedProjectID, null, studyUID), null, sessionID);
        //      //log.info("Number of study aims:" + aims.ResultSet.totalRecords + " insertDate:" + insertDate + " createdTime:" + createdTime);
        //      int   numberOfAnnotations = getNumberOfAccessibleAims(sessionID, suppliedProjectID, aims, username);
        //ml for speeding up annotation count
        int numberOfAnnotations = getStudyAimCount(sessionID, studyUID, suppliedProjectID, username);

        AnnotationStatus annotationStatus = null;
        Map<String, AnnotationStatus> userStatusList = null;

        if (includeAnnotationStatus) {
            userStatusList = new HashMap<>();
            annotationStatus = getAnnotationStatusStudy(projectID, subjectID, studyUID, username, userStatusList,
                    numberOfSeries);
            //set userStatusList to null so it doesn't display
            if (userStatusList.size() == 0)
                userStatusList = null;
        }

        return new EPADStudy(projectID, subjectID, patientName, studyUID, insertDate, firstSeriesUID,
                firstSeriesDateAcquired, physicianName, birthdate, sex, studyProcessingStatus, examTypes,
                studyDescription, studyAccessionNumber, numberOfSeries, numberOfImages, numberOfAnnotations,
                createdTime, annotationStatus, userStatusList);
    }

    private EPADSeries dcm4cheeSeries2EpadSeries(String sessionID, String suppliedProjectID,
            String suppliedSubjectID, DCM4CHEESeries dcm4CheeSeries, String username) {
        return dcm4cheeSeries2EpadSeries(sessionID, suppliedProjectID, suppliedSubjectID, dcm4CheeSeries, username,
                false);

    }

    private EPADSeries dcm4cheeSeries2EpadSeries(String sessionID, String suppliedProjectID,
            String suppliedSubjectID, DCM4CHEESeries dcm4CheeSeries, String username,
            boolean includeAnnotationStatus) {
        String projectID = suppliedProjectID == null || suppliedProjectID.equals("")
                ? EPADConfig.xnatUploadProjectID
                : suppliedProjectID;
        String patientName = trimTrailing(dcm4CheeSeries.patientName);
        String xnatPatientID = XNATUtil.subjectID2XNATSubjectLabel(dcm4CheeSeries.patientID);
        String subjectID = suppliedSubjectID.equals("") ? xnatPatientID : suppliedSubjectID;
        String studyUID = dcm4CheeSeries.studyUID;
        String seriesUID = dcm4CheeSeries.seriesUID;
        String seriesDate = dcm4CheeSeries.seriesDate;
        String seriesDescription = dcm4CheeSeries.seriesDescription;
        String examType = dcm4CheeSeries.examType;
        String bodyPart = dcm4CheeSeries.bodyPart;
        String accessionNumber = dcm4CheeSeries.accessionNumber;
        String institution = dcm4CheeSeries.institution;
        String stationName = dcm4CheeSeries.stationName;
        String department = dcm4CheeSeries.department;
        int numberOfImages = dcm4CheeSeries.imagesInSeries;
        int numberOfSeriesRelatedInstances = dcm4CheeSeries.numberOfSeriesRelatedInstances;
        String firstImageUIDInSeries = (numberOfSeriesRelatedInstances != 1) ? ""
                : dcm4CheeDatabaseOperations.getFirstImageUIDInSeries(seriesUID);

        //int numberOfAnnotations = AIMQueries.getNumberOfAIMAnnotationsForSeries(seriesUID, username);
        EPADAIMList aims = getSeriesAIMDescriptions(new SeriesReference(null, null, null, seriesUID), username,
                sessionID);
        int numberOfAnnotations = getNumberOfAccessibleAims(sessionID, suppliedProjectID, aims, username);
        List<EPADAIM> sharedAims = epadDatabaseOperations.getSharedAIMs(projectID, null, seriesUID);
        numberOfAnnotations = numberOfAnnotations + sharedAims.size();
        SeriesProcessingStatus seriesProcessingStatus = epadDatabaseOperations.getSeriesProcessingStatus(seriesUID);
        String createdTime = dcm4CheeSeries.createdTime != null ? dcm4CheeSeries.createdTime.toString() : "";

        AnnotationStatus annotationStatus = null;
        Map<String, AnnotationStatus> userStatusList = null;

        if (includeAnnotationStatus) {
            userStatusList = new HashMap<>();
            annotationStatus = getAnnotationStatusSeries(projectID, subjectID, studyUID, seriesUID, username,
                    userStatusList);
            //set userStatusList to null so it doesn't display
            if (userStatusList.size() == 0)
                userStatusList = null;
        }
        return new EPADSeries(projectID, subjectID, patientName, studyUID, seriesUID, seriesDate, seriesDescription,
                examType, bodyPart, accessionNumber, numberOfImages, numberOfSeriesRelatedInstances,
                numberOfAnnotations, institution, stationName, department, seriesProcessingStatus, createdTime,
                firstImageUIDInSeries, dcm4CheeSeries.isDSO, annotationStatus, userStatusList);
    }

    public AnnotationStatus getAnnotationStatusProject(String projectUID, String username,
            Map<String, AnnotationStatus> userStatusList, String sessionID, EPADSearchFilter searchFilter) {
        //check if the project has its own done status
        //if not check for each subject
        boolean isUserPrivileged = isUserPrivileged(projectUID, username);
        try {

            EPADSubjectList subjects = getSubjectDescriptions(projectUID, username, sessionID, searchFilter, 1,
                    5000, null, false, true);
            log.info("Number of subjects " + subjects.ResultSet.totalRecords);
            //artem's fix for empty project
            if (subjects.ResultSet.totalRecords == 0)
                return AnnotationStatus.NOT_STARTED;
            int doneCount = 0;
            int inProgressCount = 0;
            //to calculate the cumulative user list,  we need a map of user to an array containing [donecount and in_progresscount]
            Map<String, int[]> statsMap = new HashMap<>();
            for (EPADSubject su : subjects.ResultSet.Result) {
                log.info("subject " + su.subjectID);
                log.info("annotation status " + su.annotationStatus);
                if (su.annotationStatus.equals(AnnotationStatus.DONE)) {
                    doneCount++;
                }
                if (su.annotationStatus.equals(AnnotationStatus.IN_PROGRESS)) {
                    inProgressCount++;
                }
                if (isUserPrivileged) {
                    //cumulate the users' status over studies
                    if (su.userStatusList != null) {
                        for (Entry<String, AnnotationStatus> e : su.userStatusList.entrySet()) {
                            int[] value = statsMap.get(e.getKey());
                            if (value == null) {
                                value = new int[] { 0, 0 };
                            }

                            if (e.getValue().equals(AnnotationStatus.DONE)) {
                                value[0]++;

                            } else if (e.getValue().equals(AnnotationStatus.IN_PROGRESS)) {
                                value[1]++;

                            }
                            statsMap.put(e.getKey(), value);

                        }
                    }
                    //fix for subjects with no studies
                    else if (su.annotationStatus.equals(AnnotationStatus.DONE)) {
                        for (Entry<String, int[]> e : statsMap.entrySet()) {
                            int[] value = e.getValue();
                            if (value == null) {
                                value = new int[] { 0, 0 };
                            }

                            value[0]++;
                            statsMap.put(e.getKey(), value);

                        }

                    }
                }

            }
            //fill the user status list if priviliged
            if (isUserPrivileged) {
                for (Entry<String, int[]> e : statsMap.entrySet()) {
                    int[] statForUser = e.getValue();
                    //if done count equals to study count, user is done
                    if (statForUser[0] == subjects.ResultSet.Result.size())
                        userStatusList.put(e.getKey(), AnnotationStatus.DONE);
                    else if (statForUser[0] + statForUser[1] > 0)
                        userStatusList.put(e.getKey(), AnnotationStatus.IN_PROGRESS);
                    else
                        userStatusList.put(e.getKey(), AnnotationStatus.NOT_STARTED);
                }

            }
            log.info("Subjects Done =" + doneCount + " in progress=" + inProgressCount);
            if (subjects.ResultSet.Result.size() == doneCount)
                return AnnotationStatus.DONE;
            else if (doneCount + inProgressCount > 0)
                return AnnotationStatus.IN_PROGRESS;

        } catch (Exception e) {
            log.info("Could not retrieve subjects for project " + projectUID + " " + e.getMessage());
            return AnnotationStatus.ERROR;
        }
        return AnnotationStatus.NOT_STARTED;

    }

    public AnnotationStatus getAnnotationStatusSubject(String projectUID, String subjectUID, String username,
            Map<String, AnnotationStatus> userStatusList, String sessionID, EPADSearchFilter searchFilter) {
        boolean isUserPrivileged = isUserPrivileged(projectUID, username);
        try {
            //to calculate the cumulative user list,  we need a map of user to an array containing [donecount and in_progresscount]
            Map<String, int[]> statsMap = new HashMap<>();

            if (isUserPrivileged) {
                //if the user is priviliged fill the user list
                EPADUserList users = getUserDescriptions(username, new ProjectReference(projectUID), sessionID);

                for (EPADUser u : users.ResultSet.Result) {
                    int[] value = new int[] { 0, 0 };
                    statsMap.put(u.username, value);

                }

            }
            //         else {
            //            AnnotationStatus as=projectOperations.getAnnotationStatusForUserBySubject(projectUID, subjectUID, username);
            //            if (as!=AnnotationStatus.ERROR)    
            //               return as;
            //         }

            EPADStudyList studies = getStudyDescriptions(new SubjectReference(projectUID, subjectUID), username,
                    sessionID, searchFilter, true);
            int doneCount = 0;
            int inProgressCount = 0;
            if (studies.ResultSet.totalRecords == 0)
                return AnnotationStatus.NOT_STARTED;
            for (EPADStudy st : studies.ResultSet.Result) {
                log.info("study " + st.studyUID);
                log.info("annotation status " + st.annotationStatus);

                if (isUserPrivileged) {
                    //cumulate the users' status over studies
                    if (st.userStatusList != null) {
                        for (Entry<String, AnnotationStatus> e : st.userStatusList.entrySet()) {
                            int[] value = statsMap.get(e.getKey());
                            if (value == null) {
                                value = new int[] { 0, 0 };
                            }
                            if (e.getValue().equals(AnnotationStatus.DONE)) {
                                value[0]++;

                            } else if (e.getValue().equals(AnnotationStatus.IN_PROGRESS)) {
                                value[1]++;

                            }
                            statsMap.put(e.getKey(), value);

                        }
                    }

                    //fix for studies with no series
                    else if (st.annotationStatus.equals(AnnotationStatus.NOT_STARTED)) {
                        for (Entry<String, int[]> e : statsMap.entrySet()) {
                            int[] value = e.getValue();
                            if (value == null) {
                                value = new int[] { 0, 0 };
                            }

                            value[0]++;
                            statsMap.put(e.getKey(), value);

                        }

                    }
                } else {
                    if (st.annotationStatus.equals(AnnotationStatus.DONE)) {
                        doneCount++;
                    }
                    if (st.annotationStatus.equals(AnnotationStatus.IN_PROGRESS)) {
                        inProgressCount++;
                    }
                }

            }

            //cumulate studies      
            if (isUserPrivileged) {
                for (Entry<String, int[]> e : statsMap.entrySet()) {
                    int[] statForUser = e.getValue();
                    //if done count equals to study count, user is done
                    if (statForUser[0] == studies.ResultSet.Result.size())
                        userStatusList.put(e.getKey(), AnnotationStatus.DONE);
                    else if (statForUser[0] + statForUser[1] > 0)
                        userStatusList.put(e.getKey(), AnnotationStatus.IN_PROGRESS);
                    else
                        userStatusList.put(e.getKey(), AnnotationStatus.NOT_STARTED);
                }
                //            //check subject status table and override the cumulated from studies
                //            for (Entry<String, AnnotationStatus> e : userStatusList.entrySet()) {
                //               AnnotationStatus as=projectOperations.getAnnotationStatusForUserBySubject(projectUID, subjectUID, e.getKey());
                //               if (as!=AnnotationStatus.ERROR)    
                //                  e.setValue(as);
                //               log.info("subject set "+ subjectUID + "  "+ as);
                //            }
                //            
                //check the user list to cumulate
                for (Entry<String, AnnotationStatus> e : userStatusList.entrySet()) {
                    if (e.getValue().equals(AnnotationStatus.DONE))
                        doneCount++;
                    if (e.getValue().equals(AnnotationStatus.IN_PROGRESS))
                        inProgressCount++;
                }
                if (userStatusList.size() == 0)
                    return AnnotationStatus.NOT_STARTED;
                else if (userStatusList.size() == doneCount)
                    return AnnotationStatus.DONE;
                else if (doneCount + inProgressCount > 0)
                    return AnnotationStatus.IN_PROGRESS;

            } else {

                if (studies.ResultSet.Result.size() == doneCount)
                    return AnnotationStatus.DONE;
                else if (doneCount + inProgressCount > 0)
                    return AnnotationStatus.IN_PROGRESS;
            }

        } catch (Exception e) {
            log.info("Could not retrieve studies for subject " + subjectUID + " " + e.getMessage());
            return AnnotationStatus.ERROR;
        }
        return AnnotationStatus.NOT_STARTED;
    }

    public AnnotationStatus getAnnotationStatusStudy(String projectUID, String subjectUID, String studyUID,
            String username, Map<String, AnnotationStatus> userStatusList, int numberOfSeries) {
        //check if the study has its own done status
        //if not check series
        return getAnnotationStatus(projectUID, subjectUID, studyUID, null, username, userStatusList, numberOfSeries,
                isUserPrivileged(projectUID, username));

    }

    public AnnotationStatus getAnnotationStatusSeries(String projectUID, String subjectUID, String studyUID,
            String series_uid, String username, Map<String, AnnotationStatus> userStatusList) {
        return getAnnotationStatus(projectUID, subjectUID, studyUID, series_uid, username, userStatusList, 1,
                isUserPrivileged(projectUID, username));
    }

    public boolean isUserPrivileged(String projectUID, String username) {
        User user = null;
        try {
            user = projectOperations.getUser(username);
        } catch (Exception e) {
            log.info("User couldn't be retrieved for username " + username + " " + e.getMessage());
            return false;
        }
        boolean isOwner = false;
        try {
            isOwner = projectOperations.isOwner(username, projectUID);
        } catch (Exception e) {
            log.info("Is owner status couldn't be checked for username " + username + " and project " + projectUID
                    + " " + e.getMessage());
            return false;
        }
        //if the user os admin or the owner of the project, get cumulative. 
        if (username.equals("admin") || (user != null && (user.isAdmin() || isOwner))) {
            return true;
        }
        return false;
    }

    public AnnotationStatus getAnnotationStatus(String projectUID, String subjectUID, String studyUID,
            String series_uid, String username, Map<String, AnnotationStatus> userStatusList, int numberOfSeries,
            boolean isUserPrivileged) {
        //if the user is admin or the owner of the project, get cumulative. 
        if (isUserPrivileged) {
            fillAnnotationStatusList(projectUID, subjectUID, studyUID, series_uid, username, userStatusList,
                    numberOfSeries);
            //no series fix, do not bother calculating
            if (numberOfSeries == 0)
                return AnnotationStatus.NOT_STARTED;

            //go through the user list to cumulate
            int doneCount = 0;
            int inProgressCount = 0;
            for (Entry<String, AnnotationStatus> e : userStatusList.entrySet()) {
                if (e.getValue().equals(AnnotationStatus.DONE))
                    doneCount++;
                if (e.getValue().equals(AnnotationStatus.IN_PROGRESS))
                    inProgressCount++;
            }
            if (userStatusList.size() == 0)
                return AnnotationStatus.NOT_STARTED;
            else if (userStatusList.size() == doneCount)
                return AnnotationStatus.DONE;
            else if (doneCount + inProgressCount > 0)
                return AnnotationStatus.IN_PROGRESS;

            //use annotation and user counts to decide
            //         long userCount=0;
            //         int annotationDoneUserCount;

            //         try {
            //            userCount=projectOperations.getUserCountProject(projectUID);
            //            annotationDoneUserCount = projectOperations.getAnnotationStatusUserCount(projectUID, subjectUID, studyUID, series_uid,AnnotationStatus.DONE);
            //         }catch (Exception e) {
            //            log.info("User count couldn't be retrieved for project "+projectUID+ " " +e.getMessage());
            //            return AnnotationStatus.NOT_STARTED;
            //         }
            //         if (annotationDoneUserCount == 0) {
            //            int inProgressCount = projectOperations.getAnnotationStatusUserCount(projectUID, subjectUID, studyUID, series_uid,AnnotationStatus.IN_PROGRESS);
            //            if (inProgressCount == 0)
            //               return AnnotationStatus.NOT_STARTED;
            //            else
            //               return AnnotationStatus.IN_PROGRESS;
            //         }
            //         else if (userCount*numberOfSeries == annotationDoneUserCount) 
            //            return AnnotationStatus.DONE;
            //         else if (userCount*numberOfSeries > annotationDoneUserCount) 
            //            return AnnotationStatus.IN_PROGRESS;

            return AnnotationStatus.NOT_STARTED;
        }

        //Else get his own status
        return projectOperations.getAnnotationStatusForUser(projectUID, subjectUID, studyUID, series_uid, username,
                numberOfSeries);

    }

    public void fillAnnotationStatusList(String projectUID, String subjectUID, String studyUID, String series_uid,
            String username, Map<String, AnnotationStatus> userStatusList, int numberOfSeries) {
        try {
            List<User> users = projectOperations.getUsersForProject(projectUID);
            for (User u : users) {
                log.info("putting user " + u.getUsername() + " status "
                        + projectOperations.getAnnotationStatusForUser(projectUID, subjectUID, studyUID, series_uid,
                                u.getUsername(), numberOfSeries));

                userStatusList.put(u.getUsername(), projectOperations.getAnnotationStatusForUser(projectUID,
                        subjectUID, studyUID, series_uid, u.getUsername(), numberOfSeries));
            }
        } catch (Exception e1) {
            log.info("Couldn't get users for the project " + projectUID + e1.getMessage());
        }

    }

    private static String trimTrailing(String xnatName) {
        while (xnatName.endsWith("^"))
            xnatName = xnatName.substring(0, xnatName.length() - 1);
        String name = xnatName.trim();
        return name;
    }

    private StudyProcessingStatus getStudyProcessingStatus(String studyUID) {
        boolean seriesNotStarted = false;
        boolean seriesWithNoDICOM = false;
        boolean seriesInPipeline = false;
        boolean seriesWithError = false;

        Set<String> seriesUIDs = dcm4CheeDatabaseOperations.getAllSeriesUIDsInStudy(studyUID);

        for (String seriesUID : seriesUIDs) {
            SeriesProcessingStatus seriesProcessingStatus = epadDatabaseOperations
                    .getSeriesProcessingStatus(seriesUID);
            if (seriesProcessingStatus == null)
                seriesNotStarted = true;
            if (seriesProcessingStatus == SeriesProcessingStatus.NO_DICOM)
                seriesWithNoDICOM = true;
            if (seriesProcessingStatus == SeriesProcessingStatus.ERROR)
                seriesWithError = true;
            if (seriesProcessingStatus == SeriesProcessingStatus.IN_PIPELINE)
                seriesInPipeline = true;
        }

        if (seriesNotStarted)
            return StudyProcessingStatus.STUDY_STATUS_NOT_STARTED;
        if (seriesWithError)
            return StudyProcessingStatus.STUDY_STATUS_ERROR_MISSING_PNG;
        else if (seriesWithNoDICOM)
            return StudyProcessingStatus.STUDY_STATUS_ERROR_MISSING_DICOM;
        else if (seriesInPipeline)
            return StudyProcessingStatus.STUDY_STATUS_PROCESSING;
        else
            return StudyProcessingStatus.STUDY_STATUS_COMPLETED;
    }

    private EPADProject xnatProject2EPADProject(String sessionID, String username, XNATProject xnatProject,
            EPADSearchFilter searchFilter, boolean annotationCount) {
        String projectName = xnatProject.name;
        if (!searchFilter.shouldFilterProject(projectName)) {
            String projectID = xnatProject.ID;

            String secondaryID = xnatProject.secondary_ID;
            String piLastName = xnatProject.pi_lastname;
            String description = xnatProject.description;
            String piFirstName = xnatProject.pi_firstname;
            String uri = xnatProject.URI;
            Set<String> patientIDs = XNATQueries.getSubjectIDsForProject(sessionID, projectID);
            int numberOfPatients = patientIDs.size();
            //         int numberOfAnnotations = AIMQueries.getNumberOfAIMAnnotationsForPatients(sessionID, username, patientIDs);
            Set<String> studyUIDs = XNATQueries.getAllStudyUIDsForProject(projectID, sessionID);
            int numberOfAnnotations = 0;
            if (annotationCount) {
                for (String studyUID : studyUIDs) {
                    //ml for speeding up annotation count
                    numberOfAnnotations = getStudyAimCount(sessionID, studyUID.replace('_', '.'), projectID,
                            username);
                    //               EPADAIMList aims = getStudyAIMDescriptions(new StudyReference(null, null, studyUID.replace('_', '.')), username, sessionID);
                    //               numberOfAnnotations = numberOfAnnotations + getNumberOfAccessibleAims(sessionID, projectID, aims, username);
                }
            }
            if (!searchFilter.shouldFilterProject(projectName, numberOfAnnotations)) {
                int numberOfStudies = Dcm4CheeQueries.getNumberOfStudiesForPatients(patientIDs);
                XNATUserList xnatUsers = XNATQueries.getUsersForProject(projectID);
                Set<String> usernames = xnatUsers.getLoginNames();
                Map<String, String> userRoles = xnatUsers.getRoles();
                if (!userRoles.keySet().contains(username))
                    userRoles.put(username, "Collaborator");
                return new EPADProject(secondaryID, piLastName, description, projectName, projectID, piFirstName,
                        uri, numberOfPatients, numberOfStudies, numberOfAnnotations, patientIDs, usernames,
                        userRoles);
            } else
                return null;
        } else
            return null;
    }

    private EPADProject project2EPADProject(String sessionID, String username, Project project,
            EPADSearchFilter searchFilter, boolean annotationCount) throws Exception {
        return project2EPADProject(sessionID, username, project, searchFilter, annotationCount, false);
    }

    private EPADProject project2EPADProject(String sessionID, String username, Project project,
            EPADSearchFilter searchFilter, boolean annotationCount, boolean includeAnnotationStatus)
            throws Exception {
        if (project == null)
            return null;
        String projectName = project.getName();
        if (!searchFilter.shouldFilterProject(projectName)) {
            String projectID = project.getProjectId();
            String description = project.getDescription();
            Set<String> patientIDs = new HashSet<String>();
            long starttime = System.currentTimeMillis();
            List<Subject> subjects = projectOperations.getSubjectsForProject(projectID);
            for (Subject subject : subjects)
                patientIDs.add(subject.getSubjectUID());
            long subjecttime = System.currentTimeMillis();
            int numberOfPatients = patientIDs.size();
            if (project.getProjectId().equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))) {
                numberOfPatients = projectOperations.getUnassignSubjects().size();
            }
            int numberOfStudies = 0;
            int numberOfAnnotations = 0;
            long studytime = System.currentTimeMillis();
            if (annotationCount && subjects.size() < 300) {
                Set<String> studyUIDs = new HashSet<String>();
                List<Study> studies = projectOperations.getAllStudiesForProject(projectID);
                for (Study study : studies)
                    studyUIDs.add(study.getStudyUID());
                studytime = System.currentTimeMillis();
                numberOfStudies = studies.size();
                for (String studyUID : studyUIDs) {
                    //ml for speeding up annotation count
                    numberOfAnnotations += getStudyAimCount(sessionID, studyUID, projectID, username);
                    //               EPADAIMList aims = getStudyAIMDescriptions(new StudyReference(null, null, studyUID), username, sessionID);
                    //               numberOfAnnotations = numberOfAnnotations + getNumberOfAccessibleAims(sessionID, projectID, aims, username);
                }
                List<EPADAIM> sharedAims = epadDatabaseOperations.getSharedAIMs(projectID, null, null);
                numberOfAnnotations = numberOfAnnotations + sharedAims.size();
            }
            long aimtime = System.currentTimeMillis();
            if (!searchFilter.shouldFilterProject(projectName, numberOfAnnotations)) {
                List<User> users = projectOperations.getUsersForProject(projectID);
                Set<String> usernames = new HashSet<String>();
                for (User user : users)
                    usernames.add(user.getUsername());
                long usertime = System.currentTimeMillis();
                Map<String, String> userRoles = new HashMap<String, String>(); // TODO
                //Map<String,String> userRoles = xnatUsers.getRoles();
                //if (!userRoles.keySet().contains(username))
                //   userRoles.put(username, "Collaborator");

                //log.info("Time for conv, subj:" + (subjecttime-starttime) + ", study:" + (studytime-subjecttime) + " aim:" + (aimtime-studytime) + " user:" + (usertime-aimtime) + " msecs");

                AnnotationStatus annotationStatus = null;
                Map<String, AnnotationStatus> userStatusList = null;
                if (includeAnnotationStatus) {
                    userStatusList = new HashMap<>();
                    annotationStatus = getAnnotationStatusProject(projectID, username, userStatusList, sessionID,
                            searchFilter);
                    //set userStatusList to null so it doesn't display
                    if (userStatusList.size() == 0)
                        userStatusList = null;
                }

                EPADProject ep = new EPADProject("", "", description, projectName, projectID, "", "",
                        numberOfPatients, numberOfStudies, numberOfAnnotations, patientIDs, usernames, userRoles,
                        annotationStatus, userStatusList, project.getType());
                ep.defaultTemplate = project.getDefaultTemplate();
                return ep;
            } else
                return null;
        } else
            return null;
    }

    public int getStudyAimCount(String sessionID, String studyUID, String projectID, String username) {
        //      EPADAIMList aims = getStudyAIMDescriptions(new StudyReference(null, null, studyUID), username, sessionID);
        //      return getNumberOfAccessibleAims(sessionID, projectID, aims, username);
        return epadDatabaseOperations.getAIMCount(projectID, studyUID, username);

    }

    private int getNumberOfAccessibleAims(String sessionID, String suppliedProjectID, EPADAIMList aimlist,
            String username) {
        Set<String> projectIDs = aimlist.getProjectIds();
        int count = 0;
        for (String projectID : projectIDs) {
            //if (!suppliedProjectID.equals(projectID) && !projectID.equals(EPADConfig.xnatUploadProjectID) && !projectID.equals("")) continue;
            if (suppliedProjectID == null || !suppliedProjectID.equals(projectID))
                continue;
            try {

                boolean isCollaborator = UserProjectService.isCollaborator(sessionID, username, projectID);
                Set<EPADAIM> aims = aimlist.getAIMsForProject(projectID);
                for (EPADAIM aim : aims) {
                    if (!isCollaborator || aim.userName.equalsIgnoreCase(username)
                            || aim.userName.equalsIgnoreCase("shared")) {
                        count++;
                    }
                }
            } catch (Exception x) {
            }
        }

        return count;
    }

    private EPADSubject xnatSubject2EPADSubject(String sessionID, String username, XNATSubject xnatSubject,
            EPADSearchFilter searchFilter) {
        EpadOperations epadQueries = DefaultEpadOperations.getInstance();

        String patientID = xnatSubject.label;
        String patientName = xnatSubject.src;
        if (!searchFilter.shouldFilterSubject(patientID, patientName)) {
            String projectID = xnatSubject.project;
            String xnatSubjectID = xnatSubject.ID;
            String uri = xnatSubject.URI;
            String insertUser = xnatSubject.insert_user;
            String insertDate = xnatSubject.insert_date;
            //         int numberOfAnnotations = AIMQueries.getNumberOfAIMAnnotationsForPatient(patientID, username);
            //Set<String> studyUIDs = XNATQueries.getStudyUIDsForSubject(sessionID, projectID, xnatSubjectID);
            int numberOfAnnotations = 0;
            //for  (String studyUID: studyUIDs)
            {
                // Skip this, cause it is too slow and not that important
                //EPADAIMList aims = getStudyAIMDescriptions(new StudyReference(null, null, studyUID), username, sessionID);
                //numberOfAnnotations = numberOfAnnotations + getNumberOfAccessibleAims(sessionID, aims, username);
            }
            if (!searchFilter.shouldFilterSubject(patientID, patientName, numberOfAnnotations)) {
                Set<String> examTypes = epadQueries.getExamTypesForSubject(patientID);
                if (!searchFilter.shouldFilterSubject(patientID, patientName, examTypes, numberOfAnnotations)) {
                    int numberOfStudies = Dcm4CheeQueries.getNumberOfStudiesForPatient(patientID);

                    return new EPADSubject(projectID, patientID, patientName, insertUser, xnatSubjectID, insertDate,
                            uri, numberOfStudies, numberOfAnnotations, examTypes);
                } else
                    return null;
            } else
                return null;
        } else
            return null;
    }

    static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    private String formatDate(Date date) {
        if (date == null)
            return "";
        else
            return dateFormat.format(date);
    }

    static SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss");

    private String formatDateTime(Date date) {
        if (date == null)
            return "";
        else
            return dateTimeFormat.format(date);
    }

    private EPADSubject subject2EPADSubject(String sessionID, String username, Subject subject, String projectID,
            EPADSearchFilter searchFilter, boolean annotationCount) throws Exception {
        return subject2EPADSubject(sessionID, username, subject, projectID, searchFilter, annotationCount, false);
    }

    private EPADSubject subject2EPADSubject(String sessionID, String username, Subject subject, String projectID,
            EPADSearchFilter searchFilter, boolean annotationCount, boolean includeAnnotationStatus)
            throws Exception {
        EpadOperations epadQueries = DefaultEpadOperations.getInstance();

        String patientID = subject.getSubjectUID();
        String patientName = subject.getName();
        int numberOfStudies = 0;
        if (!searchFilter.shouldFilterSubject(patientID, patientName)) {
            String xnatSubjectID = "";
            String uri = "";
            String insertUser = subject.getCreator();
            String insertDate = dateFormat.format(subject.getCreatedTime());

            int numberOfAnnotations = 0;
            if (annotationCount
                    && !"true".equalsIgnoreCase(EPADConfig.getParamValue("SkipPatientAnnotationCount", "false"))) {
                List<Study> studies = null;
                //ml fix for downloading multiple subjects
                if (projectID == null) {
                    studies = projectOperations.getStudiesForSubject(patientID);
                } else {
                    studies = projectOperations.getStudiesForProjectAndSubject(projectID, patientID);
                }
                numberOfStudies = studies.size();
                for (Study study : studies) {
                    //ml
                    numberOfAnnotations += getStudyAimCount(sessionID, study.getStudyUID(), projectID, username);
                    // Skip this, cause it is too slow and not that important
                    //               EPADAIMList aims = getStudyAIMDescriptions(new StudyReference(null, null, study.getStudyUID()), username, sessionID);
                    //               numberOfAnnotations = numberOfAnnotations + getNumberOfAccessibleAims(sessionID, projectID, aims, username);
                }
                List<EPADAIM> sharedAims = epadDatabaseOperations.getSharedAIMs(projectID, patientID, null);
                numberOfAnnotations = numberOfAnnotations + sharedAims.size();
            }
            if (!searchFilter.shouldFilterSubject(patientID, patientName, numberOfAnnotations)) {
                Set<String> examTypes = epadQueries.getExamTypesForSubject(patientID);
                if (!searchFilter.shouldFilterSubject(patientID, patientName, examTypes, numberOfAnnotations)) {
                    if (numberOfStudies == 0)
                        numberOfStudies = Dcm4CheeQueries.getNumberOfStudiesForPatient(patientID);

                    AnnotationStatus annotationStatus = null;
                    Map<String, AnnotationStatus> userStatusList = null;
                    if (includeAnnotationStatus) {
                        userStatusList = new HashMap<>();
                        annotationStatus = getAnnotationStatusSubject(projectID, patientID, username,
                                userStatusList, sessionID, searchFilter);
                        //set userStatusList to null so it doesn't display
                        if (userStatusList.size() == 0)
                            userStatusList = null;
                    }
                    return new EPADSubject(projectID, patientID, patientName, insertUser, xnatSubjectID, insertDate,
                            uri, numberOfStudies, numberOfAnnotations, examTypes, annotationStatus, userStatusList);
                } else
                    return null;
            } else
                return null;
        } else
            return null;
    }

    private String getPNGPath(String studyUID, String seriesUID, String imageUID) { // TODO Look at this. Not very robust.
        String pngLocation = epadDatabaseOperations.getPNGLocation(studyUID, seriesUID, imageUID);
        if (pngLocation == null)
            return null;
        String pngPath = pngLocation.substring(EPADConfig.getEPADWebServerPNGDir().length());

        return pngPath;
    }

    private String getPNGMaskPath(String studyUID, String seriesUID, String imageUID, int frameNumber) {
        return "studies/" + studyUID + "/series/" + seriesUID + "/images/" + imageUID + "/masks/" + frameNumber
                + ".png";
    }

    private String getPNGMaskPath(String studyUID, String seriesUID, String imageUID, int frameNumber,
            String segmentNumber) {
        return "studies/" + studyUID + "/series/" + seriesUID + "/images/" + imageUID + "/masks/" + frameNumber
                + "_" + segmentNumber + ".png";
    }

    private String getPNGContourPath(String studyUID, String seriesUID, String imageUID, int frameNumber) {
        return "studies/" + studyUID + "/series/" + seriesUID + "/images/" + imageUID + "/contours/" + frameNumber
                + ".png";
    }

    private String getWADOPath(String studyUID, String seriesUID, String imageUID) {
        return "?requestType=WADO&studyUID=" + studyUID + "&seriesUID=" + seriesUID + "&objectUID=" + imageUID;
    }

    private EPADImage createEPADImage(SeriesReference seriesReference,
            DCM4CHEEImageDescription dcm4cheeImageDescription, DICOMElementList dicomElements,
            DICOMElementList defaultDICOMElements) {
        return createEPADImage(seriesReference.projectID, seriesReference.subjectID, seriesReference.studyUID,
                seriesReference.seriesUID, dcm4cheeImageDescription.imageUID, dcm4cheeImageDescription,
                dicomElements, defaultDICOMElements);
    }

    private EPADImage createEPADImage(ImageReference imageReference,
            DCM4CHEEImageDescription dcm4CheeImageDescription, DICOMElementList dicomElements,
            DICOMElementList defaultDICOMElements) {
        return createEPADImage(imageReference.projectID, imageReference.subjectID, imageReference.studyUID,
                imageReference.seriesUID, imageReference.imageUID, dcm4CheeImageDescription, dicomElements,
                defaultDICOMElements);
    }

    private EPADImage createEPADImage(String projectID, String subjectID, String studyUID, String seriesUID,
            String imageUID, DCM4CHEEImageDescription dcm4cheeImageDescription, DICOMElementList dicomElements,
            DICOMElementList defaultDICOMElements) {
        String classUID = dcm4cheeImageDescription.classUID;
        int instanceNumber = dcm4cheeImageDescription.instanceNumber;
        String sliceLocation = dcm4cheeImageDescription.sliceLocation;
        String imageDate = dcm4cheeImageDescription.contentTime;
        String insertDate = dcm4cheeImageDescription.createdTime;
        String rescaleIntercept = dcm4cheeImageDescription.rescaleIntercept;
        String rescaleSlope = dcm4cheeImageDescription.rescaleSlope;
        int numberOfFrames = getNumberOfFrames(imageUID, defaultDICOMElements);
        boolean isDSO = isDSO(dcm4cheeImageDescription);
        String losslessImage = getPNGPath(studyUID, seriesUID, imageUID);
        if (losslessImage == null) {
            //String dicomFilePath = getDICOMFilePath(dcm4cheeImageDescription.);
            //File inputDICOMFile = new File(dicomFilePath);
            //if (!isDSO)
        }
        String lossyImage = getWADOPath(studyUID, seriesUID, imageUID);
        //      log.info("rescale slope:"+rescaleSlope+" and intercept:"+rescaleIntercept);
        if (rescaleIntercept == null && rescaleSlope == null) {
            log.info("rescale slope and intercept empty!");
            if (dicomElements != null) { //the first image, try dicom elements
                log.info("using dicomelements");
                for (int i = 0; i < dicomElements.ResultSet.totalRecords; i++) {
                    if (dicomElements.ResultSet.Result.get(i).tagCode.equals("(0028,1052)")) {
                        rescaleIntercept = dicomElements.ResultSet.Result.get(i).value.trim();
                    }
                    if (dicomElements.ResultSet.Result.get(i).tagCode.equals("(0028,1053)")) {
                        rescaleSlope = dicomElements.ResultSet.Result.get(i).value.trim();
                    }
                }
                log.info("rescale slope:" + rescaleSlope + " and intercept:" + rescaleIntercept);
            }
            if (rescaleIntercept == null && rescaleSlope == null) { //still empty, query
                log.info("rescale slope and intercept still empty!");
                DICOMElementList dicomTags = getDICOMElements(studyUID, seriesUID, imageUID);
                for (int i = 0; i < dicomTags.ResultSet.totalRecords; i++) {
                    if (dicomTags.ResultSet.Result.get(i).tagCode.equals("(0028,1052)")) {
                        rescaleIntercept = dicomTags.ResultSet.Result.get(i).value.trim();
                    }
                    if (dicomTags.ResultSet.Result.get(i).tagCode.equals("(0028,1053)")) {
                        rescaleSlope = dicomTags.ResultSet.Result.get(i).value.trim();
                    }
                }
                log.info("rescale slope:" + rescaleSlope + " and intercept:" + rescaleIntercept);
            }

        }

        //log.debug("losslessimage:" + losslessImage);
        return new EPADImage(projectID, subjectID, studyUID, seriesUID, imageUID, classUID, insertDate, imageDate,
                sliceLocation, instanceNumber, losslessImage, lossyImage, dicomElements, defaultDICOMElements,
                numberOfFrames, isDSO, rescaleIntercept, rescaleSlope);
    }

    private int getNumberOfFrames(String imageUID, DICOMElementList dicomElements) {
        for (DICOMElement dicomElement : dicomElements.ResultSet.Result) {
            if (dicomElement.tagCode.equalsIgnoreCase(PixelMedUtils.NumberOfFramesCode)) {
                try {
                    return Integer.parseInt(dicomElement.value);
                } catch (NumberFormatException e) {
                    log.warning("Invalid number of frames value " + dicomElement.value + " for image " + imageUID);
                    return 0;
                }
            }
        }
        //log.warning("Could not find number of frames value  in DICOM headers for image " + imageUID);
        return 0;
    }

    private int getNumberOfSegments(DICOMElementList dicomElements) {
        int segments = 0;
        for (DICOMElement dicomElement : dicomElements.ResultSet.Result) {
            if (dicomElement.tagCode.equalsIgnoreCase(PixelMedUtils.SegmentNumberCode)) {
                segments++;
            }
        }
        return segments;
    }

    private DICOMElementList getDICOMElements(ImageReference imageReference) {
        return getDICOMElements(imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID);
    }

    private DICOMElementList getDICOMElements(ImageReference imageReference, SegmentedProperty catTypeProp) {
        return getDICOMElements(imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID,
                catTypeProp);
    }

    @Override
    public DICOMElementList getDICOMElements(String studyUID, String seriesUID, String imageUID) {
        DICOMElementList dicomElementList = Dcm4CheeQueries.getDICOMElementsFromWADO(studyUID, seriesUID, imageUID);

        if (dicomElementList == null)
            log.warning("Could not get DICOM header for image " + imageUID + " in series " + seriesUID);

        return dicomElementList;
    }

    private DICOMElementList getDICOMElements(String studyUID, String seriesUID, String imageUID,
            SegmentedProperty catTypeProp) {
        DICOMElementList dicomElementList = Dcm4CheeQueries.getDICOMElementsFromWADO(studyUID, seriesUID, imageUID,
                catTypeProp);

        if (dicomElementList == null)
            log.warning("Could not get DICOM header for image " + imageUID + " in series " + seriesUID);

        return dicomElementList;
    }

    private DICOMElementList getDefaultDICOMElements(ImageReference imageReference,
            DICOMElementList suppliedDICOMElements) {
        return getDefaultDICOMElements(imageReference.studyUID, imageReference.seriesUID, imageReference.imageUID,
                suppliedDICOMElements, 0);
    }

    @Override
    public String getDICOMElement(DICOMElementList dicomElements, String tagName) {
        List<DICOMElement> defaultDicomElements = new ArrayList<>();
        Map<String, List<DICOMElement>> dicomElementMap = generateDICOMElementMap(dicomElements);
        if (dicomElementMap.containsKey(tagName))
            return dicomElementMap.get(tagName).get(0).value;
        else
            return null;
    }

    private DICOMElementList getDefaultDICOMElements(String studyUID, String seriesUID, String imageUID,
            DICOMElementList suppliedDicomElements, int instanceNo) {
        return getDefaultDICOMElements(studyUID, seriesUID, imageUID, suppliedDicomElements, instanceNo, false);
    }

    private DICOMElementList getDefaultDICOMElements(String studyUID, String seriesUID, String imageUID,
            DICOMElementList suppliedDicomElements, int instanceNo, boolean useMax) {
        String override = epadDatabaseOperations.getSeriesDefaultTags(seriesUID);
        if (override == null)
            override = "";
        String[] tags = override.split(";");
        String modality = "";
        String bodyPart = "";
        Map<String, String> overriddenTags = new HashMap<String, String>();
        for (String tag : tags) {
            String[] tagValue = tag.split("=");
            if (tagValue.length != 2)
                continue;
            String insNo = null;
            if (tagValue[0].contains(",")) {
                insNo = tagValue[0].substring(tagValue[0].indexOf(",") + 1);
                tagValue[0] = tagValue[0].substring(0, tagValue[0].indexOf(","));
            }
            if (insNo == null || insNo.trim().equals(String.valueOf(instanceNo)))
                overriddenTags.put(tagValue[0].trim(), tagValue[1].trim());
        }
        List<DICOMElement> defaultDicomElements = new ArrayList<>();
        Map<String, List<DICOMElement>> suppliedDICOMElementMap = generateDICOMElementMap(suppliedDicomElements);

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.PatientNameCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.PatientNameCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.PatientNameCode, PixelMedUtils.PatientNameTagName, ""));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.ModalityCode)) {
            modality = suppliedDICOMElementMap.get(PixelMedUtils.ModalityCode).get(0).value;
            if (modality.equals("US"))
                useMax = true;
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.ModalityCode).get(0));
        } else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.ModalityCode, PixelMedUtils.ModalityTagName, ""));
        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.BodyPartExamined)) {
            bodyPart = suppliedDICOMElementMap.get(PixelMedUtils.BodyPartExamined).get(0).value;
        }

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.SeriesDescriptionCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.SeriesDescriptionCode).get(0));
        else
            defaultDicomElements.add(new DICOMElement(PixelMedUtils.SeriesDescriptionCode,
                    PixelMedUtils.SeriesDescriptionTagName, ""));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.PatientBirthDateCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.PatientBirthDateCode).get(0));
        else
            defaultDicomElements.add(new DICOMElement(PixelMedUtils.PatientBirthDateCode,
                    PixelMedUtils.PatientBirthDateTagName, "1900-01-01T00:00:00"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.SliceThicknessCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.SliceThicknessCode).get(0));
        else
            defaultDicomElements.add(
                    new DICOMElement(PixelMedUtils.SliceThicknessCode, PixelMedUtils.SliceThicknessTagName, "0"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.SliceLocationCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.SliceLocationCode).get(0));
        else
            defaultDicomElements.add(
                    new DICOMElement(PixelMedUtils.SliceLocationCode, PixelMedUtils.SliceLocationTagName, "0"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.PatientSexCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.PatientSexCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.PatientSexCode, PixelMedUtils.PatientSexTagName, ""));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.ManufacturerCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.ManufacturerCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.ManufacturerCode, PixelMedUtils.ManufacturerTagName, ""));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.ModelNameCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.ModelNameCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.ModelNameCode, PixelMedUtils.ModelNameTagName, ""));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.SoftwareVersionCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.SoftwareVersionCode).get(0));
        else
            defaultDicomElements.add(
                    new DICOMElement(PixelMedUtils.SoftwareVersionCode, PixelMedUtils.SoftwareVersionTagName, ""));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.PixelSpacingCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.PixelSpacingCode).get(0));
        else
            defaultDicomElements.add(
                    new DICOMElement(PixelMedUtils.PixelSpacingCode, PixelMedUtils.PixelSpacingTagName, "1\\1"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.RescaleInterceptCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.RescaleInterceptCode).get(0));
        else
            defaultDicomElements.add(new DICOMElement(PixelMedUtils.RescaleInterceptCode,
                    PixelMedUtils.RescaleInterceptTagName, "0"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.RescaleSlopeCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.RescaleSlopeCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.RescaleSlopeCode, PixelMedUtils.RescaleSlopeTagName, "1"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.StudyDateCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.StudyDateCode).get(0));
        else
            defaultDicomElements.add(new DICOMElement(PixelMedUtils.StudyDateCode, PixelMedUtils.StudyDateTagName,
                    "1900-01-01T00:00:00"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.StudyTimeCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.StudyTimeCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.StudyTimeCode, PixelMedUtils.StudyTimeTagName, "00:00:00"));

        String rows = "512";
        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.RowsCode)) {
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.RowsCode).get(0));
            //if (suppliedDICOMElementMap.get(PixelMedUtils.RowsCode).size() > 1)
            //   defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.RowsCode).get(1));
            rows = suppliedDICOMElementMap.get(PixelMedUtils.RowsCode).get(0).value;
        } else
            defaultDicomElements.add(new DICOMElement(PixelMedUtils.RowsCode, PixelMedUtils.RowsTagName, "512"));

        String cols = "512";
        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.ColumnsCode)) {
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.ColumnsCode).get(0));
            //if (suppliedDICOMElementMap.get(PixelMedUtils.ColumnsCode).size() > 1)
            //   defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.ColumnsCode).get(1));
            cols = suppliedDICOMElementMap.get(PixelMedUtils.ColumnsCode).get(0).value;
        } else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.ColumnsCode, PixelMedUtils.ColumnsTagName, "512"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.BitsStoredCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.BitsStoredCode).get(0));
        else
            defaultDicomElements
                    .add(new DICOMElement(PixelMedUtils.BitsStoredCode, PixelMedUtils.BitsStoredTagName, "16"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.PixelRepresentationCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.PixelRepresentationCode).get(0));
        else
            defaultDicomElements.add(new DICOMElement(PixelMedUtils.PixelRepresentationCode,
                    PixelMedUtils.PixelRepresentationTagName, "0"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.NumberOfFramesCode))
            defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.NumberOfFramesCode).get(0));
        else
            defaultDicomElements.add(
                    new DICOMElement(PixelMedUtils.NumberOfFramesCode, PixelMedUtils.NumberOfFramesTagName, "0"));

        if (suppliedDICOMElementMap.containsKey(PixelMedUtils.WindowWidthCode)
                && suppliedDICOMElementMap.containsKey(PixelMedUtils.WindowCenterCode)) {
            if ("0".equals(suppliedDICOMElementMap.get(PixelMedUtils.WindowWidthCode).get(0).value)) {
                if (overriddenTags.containsKey(PixelMedUtils.WindowWidthTagName))
                    defaultDicomElements
                            .add(new DICOMElement(PixelMedUtils.WindowWidthCode, PixelMedUtils.WindowWidthTagName,
                                    overriddenTags.get(PixelMedUtils.WindowWidthTagName)));
                if (overriddenTags.containsKey(PixelMedUtils.WindowCenterTagName))
                    defaultDicomElements
                            .add(new DICOMElement(PixelMedUtils.WindowCenterCode, PixelMedUtils.WindowCenterTagName,
                                    overriddenTags.get(PixelMedUtils.WindowCenterTagName)));
                else
                    defaultDicomElements.addAll(getCalculatedWindowingDICOMElements(studyUID, seriesUID, imageUID,
                            useMax, modality, bodyPart));
            } else {
                defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.WindowWidthCode).get(0));
                defaultDicomElements.add(suppliedDICOMElementMap.get(PixelMedUtils.WindowCenterCode).get(0));
            }
        } else {
            if (overriddenTags.containsKey(PixelMedUtils.WindowWidthTagName))
                defaultDicomElements.add(new DICOMElement(PixelMedUtils.WindowWidthCode,
                        PixelMedUtils.WindowWidthTagName, overriddenTags.get(PixelMedUtils.WindowWidthTagName)));
            if (overriddenTags.containsKey(PixelMedUtils.WindowCenterTagName))
                defaultDicomElements.add(new DICOMElement(PixelMedUtils.WindowCenterCode,
                        PixelMedUtils.WindowCenterTagName, overriddenTags.get(PixelMedUtils.WindowCenterTagName)));
            else
                defaultDicomElements.addAll(getCalculatedWindowingDICOMElements(studyUID, seriesUID, imageUID,
                        useMax, modality, bodyPart));
        }
        return new DICOMElementList(defaultDicomElements);
    }

    private DICOMElementList replaceSliceSpecificElements(String studyUID, String seriesUID, String imageUID,
            DICOMElementList suppliedDicomElements) {
        List<DICOMElement> defaultDicomElements = new ArrayList<>();
        File tagFile = new File(EPADConfig.getEPADWebServerDicomTagDir()
                + getPNGPath(studyUID, seriesUID, imageUID).replace(".png", ".tag"));
        if (!tagFile.exists()) {
            log.info("No tag file found:" + tagFile.getAbsolutePath());
            return suppliedDicomElements;
        }
        try {
            String contents = EPADFileUtils.readFileAsString(tagFile);
            String[] tags = contents.split("\n");
            Map<String, String> tagMap = new HashMap<String, String>();
            for (String tag : tags) {
                int paren1 = tag.indexOf("(");
                if (paren1 == -1)
                    continue;
                int paren2 = tag.indexOf(")");
                if (paren2 == -1)
                    continue;
                int square1 = tag.indexOf("[");
                if (square1 == -1)
                    continue;
                int square2 = tag.indexOf("]");
                if (square2 == -1)
                    continue;
                String tagCode = tag.substring(paren1, paren2 + 1);
                String tagValue = tag.substring(square1 + 1, square2);
                log.debug("tagCode:" + tagCode + " tagValue:" + tagValue);
                tagMap.put(tagCode, tagValue);
            }
            for (int i = 0; i < suppliedDicomElements.ResultSet.totalRecords; i++) {
                DICOMElement dicomElement = suppliedDicomElements.ResultSet.Result.get(i);
                if (dicomElement.tagCode.equals(PixelMedUtils.SliceThicknessCode)
                        && tagMap.containsKey(PixelMedUtils.SliceThicknessCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.SliceThicknessCode,
                            PixelMedUtils.SliceThicknessTagName, tagMap.get(PixelMedUtils.SliceThicknessCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.SliceLocationCode)
                        && tagMap.containsKey(PixelMedUtils.SliceLocationCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.SliceLocationCode,
                            PixelMedUtils.SliceLocationTagName, tagMap.get(PixelMedUtils.SliceLocationCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.PixelSpacingCode)
                        && tagMap.containsKey(PixelMedUtils.PixelSpacingCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.PixelSpacingCode,
                            PixelMedUtils.PixelSpacingTagName, tagMap.get(PixelMedUtils.SliceLocationCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.RescaleInterceptCode)
                        && tagMap.containsKey(PixelMedUtils.RescaleInterceptCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.RescaleInterceptCode,
                            PixelMedUtils.RescaleInterceptTagName, tagMap.get(PixelMedUtils.RescaleInterceptCode)));
                    log.info("rescale-int " + tagMap.get(PixelMedUtils.RescaleInterceptCode)); //ml
                } else if (dicomElement.tagCode.equals(PixelMedUtils.RescaleSlopeCode)
                        && tagMap.containsKey(PixelMedUtils.RescaleSlopeCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.RescaleSlopeCode,
                            PixelMedUtils.RescaleSlopeTagName, tagMap.get(PixelMedUtils.RescaleSlopeCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.RescaleSlopeCode)
                        && tagMap.containsKey(PixelMedUtils.RescaleSlopeCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.RescaleSlopeCode,
                            PixelMedUtils.RescaleSlopeTagName, tagMap.get(PixelMedUtils.RescaleSlopeCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.RowsCode)
                        && tagMap.containsKey(PixelMedUtils.RowsCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.RowsCode, PixelMedUtils.RowsTagName,
                            tagMap.get(PixelMedUtils.RowsCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.ColumnsCode)
                        && tagMap.containsKey(PixelMedUtils.ColumnsCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.ColumnsCode,
                            PixelMedUtils.ColumnsTagName, tagMap.get(PixelMedUtils.ColumnsCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.BitsStoredCode)
                        && tagMap.containsKey(PixelMedUtils.BitsStoredCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.BitsStoredCode,
                            PixelMedUtils.BitsStoredTagName, tagMap.get(PixelMedUtils.BitsStoredCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.PixelRepresentationCode)
                        && tagMap.containsKey(PixelMedUtils.PixelRepresentationCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.PixelRepresentationCode,
                            PixelMedUtils.PixelRepresentationTagName,
                            tagMap.get(PixelMedUtils.PixelRepresentationCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.NumberOfFramesCode)
                        && tagMap.containsKey(PixelMedUtils.NumberOfFramesCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.NumberOfFramesCode,
                            PixelMedUtils.NumberOfFramesTagName, tagMap.get(PixelMedUtils.NumberOfFramesCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.WindowWidthCode)
                        && tagMap.containsKey(PixelMedUtils.WindowWidthCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.WindowWidthCode,
                            PixelMedUtils.WindowWidthTagName, tagMap.get(PixelMedUtils.WindowWidthCode)));
                } else if (dicomElement.tagCode.equals(PixelMedUtils.WindowCenterCode)
                        && tagMap.containsKey(PixelMedUtils.WindowCenterCode)) {
                    defaultDicomElements.add(new DICOMElement(PixelMedUtils.WindowCenterCode,
                            PixelMedUtils.WindowCenterTagName, tagMap.get(PixelMedUtils.WindowCenterCode)));
                } else
                    defaultDicomElements.add(dicomElement);

            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return new DICOMElementList(defaultDicomElements);
    }

    private Map<String, List<DICOMElement>> generateDICOMElementMap(DICOMElementList dicomElementList) {
        Map<String, List<DICOMElement>> result = new HashMap<>();

        for (DICOMElement dicomElement : dicomElementList.ResultSet.Result) {
            if (result.get(dicomElement.tagCode) != null)
                result.get(dicomElement.tagCode).add(dicomElement);
            else {
                List<DICOMElement> dicomElements = new ArrayList<>();
                dicomElements.add(dicomElement);
                result.put(dicomElement.tagCode, dicomElements);
            }
        }
        return result;
    }

    static Map<String, String> defaultWindow = new HashMap<String, String>();
    static {
        defaultWindow.put("CT-ABDOMEN", "350,40");
        defaultWindow.put("CT-PELVIS", "350,40");
        defaultWindow.put("CT-OVARY", "350,40");
        defaultWindow.put("CT-BONE", "2500,480");
        defaultWindow.put("CT-BRAIN", "80,40");
        defaultWindow.put("CT-CTA (3D-MIP)", "650,50");
        defaultWindow.put("CT-KIDNEY", "700,50");
        defaultWindow.put("CT-LIVER", "120,70");
        defaultWindow.put("CT-LUNG", "1500,-500");
        defaultWindow.put("CT-MEDIASTINUM,CHEST", "4000,40");
        defaultWindow.put("CT-MYELOGRAM", "880,110");
        defaultWindow.put("CT-NECK", "350,20");
        defaultWindow.put("CT-SINUS", "2000,100");
        defaultWindow.put("CT-STROKE", "50,40");
        defaultWindow.put("CT-SUBDURAL", "350,90");
        defaultWindow.put("MR-BRAIN", "1200,800");
        defaultWindow.put("MR-T1", "480,225");
        defaultWindow.put("MR-T2", "350,300");
        defaultWindow.put("MR-FLAIR", "800,170");
        defaultWindow.put("MR-PD", "1900,950");
        defaultWindow.put("US-LOW CONTRAST", "190,80");
        defaultWindow.put("US-MED CONTRAST", "160,70");
        defaultWindow.put("US-HIGH CONTRAST", "120,60");
        defaultWindow.put("XA-CARDIAC (10 BIT)", "1024,512");
        defaultWindow.put("XA-CARDIAC (12 BIT)", "4096,2048");
        defaultWindow.put("XA-CARDIAC (8 BIT)", "255,127");
    };

    private List<DICOMElement> getCalculatedWindowingDICOMElements(String studyUID, String seriesUID,
            String imageUID, boolean useMax, String modality, String bodyPart) {
        List<DICOMElement> dicomElements = new ArrayList<>();
        long windowWidth = 400;
        long windowCenter = 0;
        String dicomImageFilePath = null;

        try {
            File temporaryDicomFile = File.createTempFile(imageUID, ".dcm");
            DCM4CHEEUtil.downloadDICOMFileFromWADO(studyUID, seriesUID, imageUID, temporaryDicomFile);

            dicomImageFilePath = temporaryDicomFile.getAbsolutePath();
            Opener opener = new Opener();
            ImagePlus image = null;
            try {
                image = opener.openImage(dicomImageFilePath);
            } catch (Error x) {
                log.warning("ImageJ error opening image");
            } catch (Throwable x) {
                log.warning("ImageJ error opening image");
            }

            if (image != null) {
                // This method to get Window parameters in overriden below (need to test which one is correct)
                double min = image.getDisplayRangeMin();
                double max = image.getDisplayRangeMax();
                Calibration cal = image.getCalibration();
                double minValue = cal.getCValue(min);
                double maxValue = cal.getCValue(max);
                windowWidth = Math.round(maxValue - minValue);
                if (windowWidth == 0) {
                    windowWidth = 400;
                }
                windowCenter = Math.round(minValue + windowWidth / 2.0);
                ImageProcessor ip = image.getProcessor();
                log.info("Image, min:" + minValue + " max:" + maxValue + " width:" + windowWidth + " center:"
                        + windowCenter);
                if (ip != null)
                    log.info("Processor min:" + ip.getMinThreshold() + " minh:" + ip.getHistogramMin() + " max:"
                            + ip.getMax() + " calmin:" + cal.getCValue(ip.getMin()) + " calmx:"
                            + cal.getCValue(ip.getMax()));
                // New method to get window parameters
                ImageStatistics is = image.getStatistics();
                if (is != null) {
                    min = is.min;
                    max = is.max;
                    log.info("Statistics, min:" + min + " max:" + max + " all:" + is);
                    long width = Math.round(max - min);
                    long center = Math.round(min + width / 2.0);
                    if (width > 0) {
                        windowWidth = width;
                        windowCenter = center;
                    }
                }
                if (cal.isSigned16Bit() && max < 5000) // Signed values can be negative/positive
                    windowCenter = 0;
                log.info("Calculated, windowWidth:" + windowWidth + " windowCenter:" + windowCenter);
                if (useMax && windowWidth != 255 && windowCenter != 128) { //temporary test
                    windowCenter = 16384;
                    windowWidth = 32768;
                }
                String key = modality + "-" + bodyPart;
                if (defaultWindow.get(key.toUpperCase()) != null) {
                    String[] win = defaultWindow.get(key.toUpperCase()).split(",");
                    windowCenter = getInt(win[1]);
                    windowWidth = getInt(win[0]);
                }

                log.info("Image " + imageUID + " in series " + seriesUID + " has a calculated window width of "
                        + windowWidth + " and window center of " + windowCenter + " signed:" + cal.isSigned16Bit());
                temporaryDicomFile.delete();
            } else {
                log.warning("ImageJ failed to load DICOM file for image " + imageUID + " in series " + seriesUID
                        + " path: " + dicomImageFilePath + " to calculate windowing");
                if (useMax) {
                    windowCenter = 16384;
                    windowWidth = 32768;
                }
            }
        } catch (Exception e) {
            log.warning("Error getting DICOM file from dcm4chee for image " + imageUID + " in series " + seriesUID,
                    e);
        }

        dicomElements.add(new DICOMElement(PixelMedUtils.WindowWidthCode, PixelMedUtils.WindowWidthTagName,
                "" + windowWidth));
        dicomElements.add(new DICOMElement(PixelMedUtils.WindowCenterCode, PixelMedUtils.WindowCenterTagName,
                "" + windowCenter));

        return dicomElements;
    }

    @Override
    public EPADUserList getUserDescriptions(String username, String sessionID, boolean returnUsage)
            throws Exception {
        EPADUserList userlist = new EPADUserList();
        List<User> users = projectOperations.getAllUsers();
        for (User user : users) {
            Set<String> permissions = new HashSet<String>();
            String[] perms = user.getPermissions().split(",");
            for (String perm : perms)
                permissions.add(perm);
            Set<String> projects = null;
            List<String> projectToRole = null;
            if (user.getProjectToRole() != null) {
                projects = user.getProjectToRole().keySet();
                projectToRole = new ArrayList<String>();
                if (projects != null) {
                    for (String project : projects) {
                        projectToRole.add(project + ":" + user.getProjectToRole().get(project));
                    }
                }
            }
            if (projectOperations.isAdmin(username) || username.equals(user.getUsername())
                    || username.equals(user.getCreator())) {
                EPADUser epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(),
                        user.getLastName(), user.getEmail(), user.isEnabled(), user.isAdmin(),
                        user.isPasswordExpired(), "", permissions, projects, projectToRole);
                epadUser.colorpreference = user.getColorpreference();
                epadUser.creator = user.getCreator();
                if (returnUsage) {
                    EpadStatistics userStats = projectOperations.getUserStatistics(username, user.getUsername(),
                            false);
                    if (userStats != null)
                        epadUser.usage = new EPADUsage(userStats.getHost(), userStats.getNumOfUsers(),
                                userStats.getNumOfProjects(), userStats.getNumOfPatients(),
                                userStats.getNumOfStudies(), userStats.getNumOfSeries(), userStats.getNumOfAims(),
                                userStats.getNumOfDSOs(), userStats.getNumOfPacs(), userStats.getNumOfAutoQueries(),
                                userStats.getNumOfWorkLists(), userStats.getNumOfFiles(),
                                userStats.getNumOfTemplates(), userStats.getNumOfPlugins(),
                                dateformat.format(new Date()));
                }
                userlist.addEPADUser(epadUser);
            } else {
                EPADUser epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(),
                        user.getLastName(), "******", user.isEnabled(), user.isAdmin(), user.isPasswordExpired(),
                        "", permissions, projects, projectToRole);
                epadUser.colorpreference = user.getColorpreference();
                if (returnUsage) {
                    EpadStatistics userStats = projectOperations.getUserStatistics(username, user.getUsername(),
                            false);
                    if (userStats != null)
                        epadUser.usage = new EPADUsage(userStats.getHost(), userStats.getNumOfUsers(),
                                userStats.getNumOfProjects(), userStats.getNumOfPatients(),
                                userStats.getNumOfStudies(), userStats.getNumOfSeries(), userStats.getNumOfAims(),
                                userStats.getNumOfDSOs(), userStats.getNumOfPacs(), userStats.getNumOfAutoQueries(),
                                userStats.getNumOfWorkLists(), userStats.getNumOfFiles(),
                                userStats.getNumOfTemplates(), userStats.getNumOfPlugins(),
                                dateformat.format(new Date()));
                }
                userlist.addEPADUser(epadUser);
            }
        }
        return userlist;
    }

    @Override
    public EPADUser getUserDescription(String loggedInusername, String username, String sessionID,
            boolean returnUsage) throws Exception {
        User user = projectOperations.getUser(username);
        if (user == null) {
            user = projectOperations.getUserByEmail(username);
            if (user == null)
                return null;
        }
        Set<String> permissions = new HashSet<String>();
        String[] perms = user.getPermissions().split(",");
        for (String perm : perms)
            permissions.add(perm);
        Set<String> projects = null;
        List<String> projectToRole = null;
        if (user.getProjectToRole() != null) {
            projects = user.getProjectToRole().keySet();
            projectToRole = new ArrayList<String>();
            if (projects != null) {
                for (String project : projects) {
                    projectToRole.add(project + ":" + user.getProjectToRole().get(project));
                }
            }
        }
        EPADUser epadUser = null;
        if (projectOperations.isAdmin(loggedInusername) || loggedInusername.equals(user.getUsername())
                || loggedInusername.equals(user.getCreator())) {
            epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(), user.getLastName(),
                    user.getEmail(), user.isEnabled(), user.isAdmin(), user.isPasswordExpired(), "", permissions,
                    projects, projectToRole);
            epadUser.colorpreference = user.getColorpreference();
            epadUser.creator = user.getCreator();
            if (returnUsage) {
                EpadStatistics userStats = projectOperations.getUserStatistics(username, user.getUsername(), false);
                if (userStats != null)
                    epadUser.usage = new EPADUsage(userStats.getHost(), userStats.getNumOfUsers(),
                            userStats.getNumOfProjects(), userStats.getNumOfPatients(), userStats.getNumOfStudies(),
                            userStats.getNumOfSeries(), userStats.getNumOfAims(), userStats.getNumOfDSOs(),
                            userStats.getNumOfPacs(), userStats.getNumOfAutoQueries(),
                            userStats.getNumOfWorkLists(), userStats.getNumOfFiles(), userStats.getNumOfTemplates(),
                            userStats.getNumOfPlugins(), dateformat.format(new Date()));
            }
        } else {
            epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(), user.getLastName(),
                    "******", user.isEnabled(), user.isAdmin(), user.isPasswordExpired(), "", permissions, projects,
                    projectToRole);
            epadUser.colorpreference = user.getColorpreference();
            if (returnUsage) {
                EpadStatistics userStats = projectOperations.getUserStatistics(username, user.getUsername(), false);
                if (userStats != null)
                    epadUser.usage = new EPADUsage(userStats.getHost(), userStats.getNumOfUsers(),
                            userStats.getNumOfProjects(), userStats.getNumOfPatients(), userStats.getNumOfStudies(),
                            userStats.getNumOfSeries(), userStats.getNumOfAims(), userStats.getNumOfDSOs(),
                            userStats.getNumOfPacs(), userStats.getNumOfAutoQueries(),
                            userStats.getNumOfWorkLists(), userStats.getNumOfFiles(), userStats.getNumOfTemplates(),
                            userStats.getNumOfPlugins(), dateformat.format(new Date()));
            }
        }
        return epadUser;

    }

    @Override
    public void createOrModifyUser(String loggedInUserName, String username, String firstname, String lastname,
            String email, String password, String oldpassword, String colorpreference, String[] addPermissions,
            String[] removePermissions) throws Exception {
        User user = projectOperations.getUser(username);
        User loggedInUser = projectOperations.getUser(loggedInUserName);
        if (!loggedInUser.isAdmin() && (user == null || !loggedInUserName.equals(username))
                && !loggedInUser.hasPermission(User.CreateUserPermission))
            throw new Exception("User " + loggedInUserName + " does not have privilege to create/modify users");

        List<String> addPerms = new ArrayList<String>();
        List<String> removePerms = new ArrayList<String>();
        if (addPermissions != null) {
            for (String perm : addPermissions) {
                perm = perm.trim();
                if (perm.indexOf(",") != -1) {
                    String[] perms = perm.split(",");
                    for (String p : perms) {
                        p = p.trim();
                        if (p.length() > 0)
                            addPerms.add(p);
                    }
                } else {
                    if (perm.length() > 0)
                        addPerms.add(perm);
                }
            }
        }
        if (removePermissions != null) {
            for (String perm : removePermissions) {
                perm = perm.trim();
                if (perm.indexOf(",") != -1) {
                    String[] perms = perm.split(",");
                    for (String p : perms) {
                        p = p.trim();
                        if (p.length() > 0)
                            removePerms.add(p);
                    }
                } else {
                    if (perm.length() > 0)
                        removePerms.add(perm);
                }
            }
        }
        if (user == null) {
            projectOperations.createUser(loggedInUserName, username, firstname, lastname, email, password,
                    colorpreference, addPerms, removePerms);
        } else {
            projectOperations.updateUser(loggedInUserName, username, firstname, lastname, email, password,
                    oldpassword, colorpreference, addPerms, removePerms);
        }

    }

    @Override
    public void setAdmin(String loggedInUser, String username) throws Exception {
        projectOperations.setAdmin(loggedInUser, username);
    }

    @Override
    public void resetAdmin(String loggedInUser, String username) throws Exception {
        projectOperations.resetAdmin(loggedInUser, username);
    }

    @Override
    public void enableUser(String loggedInUser, String username) throws Exception {
        projectOperations.enableUser(loggedInUser, username);
    }

    @Override
    public void disableUser(String loggedInUser, String username) throws Exception {
        projectOperations.disableUser(loggedInUser, username);
    }

    @Override
    public void deleteUser(String loggedInUser, String username) throws Exception {
        try {
            projectOperations.deleteUser(loggedInUser, username);
        } catch (Exception x) {
            log.warning("Error deleting user:" + username, x);
            throw new Exception(x.getMessage());
        }
    }

    @Override
    public EPADUserList getUserDescriptions(String username, ProjectReference projectReference, String sessionID)
            throws Exception {
        EPADUserList userlist = new EPADUserList();
        List<User> users = projectOperations.getUsersWithRoleForProject(projectReference.projectID);
        for (User user : users) {
            Set<String> permissions = new HashSet<String>();
            String[] perms = user.getPermissions().split(",");
            for (String perm : perms)
                permissions.add(perm);
            if (projectOperations.isAdmin(username) || username.equals(user.getUsername())
                    || username.equals(user.getCreator())) {
                EPADUser epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(),
                        user.getLastName(), user.getEmail(), user.isEnabled(), user.isAdmin(),
                        user.isPasswordExpired(), user.getRole(), permissions);
                epadUser.colorpreference = user.getColorpreference();
                epadUser.creator = user.getCreator();
                userlist.addEPADUser(epadUser);
            } else {
                EPADUser epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(),
                        user.getLastName(), "******", user.isEnabled(), user.isAdmin(), user.isPasswordExpired(),
                        user.getRole(), permissions);
                epadUser.colorpreference = user.getColorpreference();
                userlist.addEPADUser(epadUser);
            }
        }
        return userlist;
    }

    @Override
    public void addUserToProject(String loggedInusername, ProjectReference projectReference, String username,
            String roleName, String defaultTemplate, String sessionID) throws Exception {
        User user = projectOperations.getUser(username);
        if (!projectOperations.isOwner(loggedInusername, projectReference.projectID) && !user.isAdmin()
                && !projectOperations.hasAccessToProject(username, projectReference.projectID))
            throw new Exception("User " + loggedInusername + " is not the owner of " + projectReference.projectID);
        if (roleName != null && !projectOperations.isOwner(loggedInusername, projectReference.projectID)
                && !user.isAdmin())
            throw new Exception("User " + loggedInusername + " is not the owner of " + projectReference.projectID);
        UserRole role = UserRole.getRole(roleName);
        projectOperations.addUserToProject(loggedInusername, projectReference.projectID, username, role,
                defaultTemplate);

    }

    @Override
    public void removeUserFromProject(String loggedInusername, ProjectReference projectReference, String username,
            String sessionID) throws Exception {
        User user = projectOperations.getUser(username);
        if (!projectOperations.isOwner(loggedInusername, projectReference.projectID) && !user.isAdmin())
            throw new Exception("User " + loggedInusername + " is not the owner of " + projectReference.projectID);
        projectOperations.removeUserFromProject(loggedInusername, projectReference.projectID, username);
    }

    @Override
    public EPADUserList getReviewers(String loggedInusername, String username, String sessionID) throws Exception {
        EPADUserList userlist = new EPADUserList();
        List<User> users = projectOperations.getReviewers(username);
        for (User user : users) {
            EPADUser epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(),
                    user.getLastName(), user.getEmail(), user.isEnabled(), user.isAdmin(), user.isPasswordExpired(),
                    "", null);
            epadUser.colorpreference = user.getColorpreference();
            userlist.addEPADUser(epadUser);
        }
        return userlist;
    }

    @Override
    public EPADUserList getReviewees(String loggedInusername, String username, String sessionID) throws Exception {
        EPADUserList userlist = new EPADUserList();
        List<User> users = projectOperations.getReviewees(username);
        for (User user : users) {
            EPADUser epadUser = new EPADUser(user.getFullName(), user.getUsername(), user.getFirstName(),
                    user.getLastName(), user.getEmail(), user.isEnabled(), user.isAdmin(), user.isPasswordExpired(),
                    "", null);
            epadUser.colorpreference = user.getColorpreference();
            userlist.addEPADUser(epadUser);
        }
        return userlist;
    }

    @Override
    public void addReviewer(String loggedInUser, String username, String reviewer) throws Exception {
        projectOperations.addReviewer(loggedInUser, username, reviewer);
    }

    @Override
    public void addReviewee(String loggedInUser, String username, String reviewee) throws Exception {
        projectOperations.addReviewee(loggedInUser, username, reviewee);
    }

    @Override
    public void removeReviewer(String loggedInUser, String username, String reviewer) throws Exception {
        projectOperations.removeReviewer(loggedInUser, username, reviewer);
    }

    @Override
    public void removeReviewee(String loggedInUser, String username, String reviewee) throws Exception {
        projectOperations.removeReviewee(loggedInUser, username, reviewee);
    }

    /**
     * @param username
     * @param imageReference - Image from old study where old annotation created
     * @param followupStudyUID - StudyID of new study
     * @param sessionID
     * @return matching image from new study (same location)
     * @throws Exception
     */
    @Override
    public EPADImage getSameSliceFromNewStudy(String username, ImageReference imageReference,
            String followupStudyUID, String sessionID) throws Exception {
        SeriesReference oldSeriesReference = new SeriesReference(imageReference.projectID, imageReference.subjectID,
                imageReference.studyUID, imageReference.seriesUID);
        EPADSeries oldSeries = this.getSeriesDescription(oldSeriesReference, username, sessionID);
        EPADImage oldImage = this.getImageDescription(imageReference, sessionID);
        StudyReference studyReference = new StudyReference(imageReference.projectID, imageReference.subjectID,
                followupStudyUID);
        EPADSeriesList serieses = getSeriesDescriptions(studyReference, username, sessionID, new EPADSearchFilter(),
                true);
        for (EPADSeries newSeries : serieses.ResultSet.Result) {
            if (oldSeries.seriesDescription.equals(newSeries.seriesDescription)
                    || serieses.ResultSet.totalRecords == 1) {
                SeriesReference newSeriesReference = new SeriesReference(imageReference.projectID,
                        imageReference.subjectID, newSeries.studyUID, newSeries.seriesUID);
                EPADImageList imageList = this.getImageDescriptions(newSeriesReference, sessionID,
                        new EPADSearchFilter());
                EPADImage closest = imageList.ResultSet.Result.get(0);
                double diff = Math.abs(getDouble(oldImage.sliceLocation) - getDouble(closest.sliceLocation));
                for (EPADImage image : imageList.ResultSet.Result) {
                    double diff2 = Math.abs(getDouble(oldImage.sliceLocation) - getDouble(image.sliceLocation));
                    if (diff2 < diff) {
                        closest = image;
                        diff = diff2;
                    }
                }
                return closest;
            }
        }
        return null;
    }

    double getDouble(String doubleStr) {
        try {
            return Double.valueOf(doubleStr);
        } catch (Exception x) {
        }
        return 0.0;
    }
    // This is Pixelmed variant (though does not seem to be correct).
    // SourceImage srcDicomImage = new SourceImage(temporaryDicomFile.getAbsolutePath());
    // ImageEnhancer imageEnhancer = new ImageEnhancer(srcDicomImage);
    // imageEnhancer.findVisuParametersImage();
    // windowWidth = Math.round(imageEnhancer.getWindowWidth());
    // windowCenter = Math.round(imageEnhancer.getWindowCenter());

    //ml
    @Override
    public EPADProjectList getProjectsForStudy(String username, String sessionID, EPADSearchFilter searchFilter,
            boolean annotationCount, String studyUID) throws Exception {
        EPADProjectList epadProjectList = new EPADProjectList();
        long starttime = System.currentTimeMillis();
        List<Project> projects = new ArrayList<Project>();
        List projectList = projectOperations.getProjectsForStudy(studyUID);
        projectList = projectOperations.sort(projectList, "name", true);
        projects.addAll(projectList);
        long gettime = System.currentTimeMillis();
        log.info("get projects for study " + studyUID + " returned " + projectList.size() + " items");
        for (Project project : projects) {
            if ((project.getProjectId().equals(EPADConfig.xnatUploadProjectID) || project.getProjectId()
                    .equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))))
                continue;
            EPADProject epadProject = project2EPADProject(sessionID, username, project, searchFilter, false);

            if (epadProject != null) {
                //log.info("project " + epadProject.id + " aim count:" + epadProject.numberOfAnnotations);
                epadProjectList.addEPADProject(epadProject);
            }
        }
        long convtime = System.currentTimeMillis();
        log.info("Time to get " + epadProjectList.ResultSet.totalRecords + " projects:" + (gettime - starttime)
                + " msecs, to convert:" + (convtime - gettime) + " msecs");
        return epadProjectList;
    }

    //ml
    @Override
    public EPADProjectList getProjectsForSubject(String username, String sessionID, EPADSearchFilter searchFilter,
            boolean annotationCount, String subjectUID) throws Exception {
        EPADProjectList epadProjectList = new EPADProjectList();
        long starttime = System.currentTimeMillis();
        List<Project> projects = new ArrayList<Project>();
        List projectList = projectOperations.getProjectsForSubject(subjectUID);
        projectList = projectOperations.sort(projectList, "name", true);
        projects.addAll(projectList);
        long gettime = System.currentTimeMillis();
        log.info("get projects for subject " + subjectUID + " returned " + projectList.size() + " items");
        for (Project project : projects) {
            if ((project.getProjectId().equals(EPADConfig.xnatUploadProjectID) || project.getProjectId()
                    .equals(EPADConfig.getParamValue("UnassignedProjectID", "nonassigned"))))
                continue;
            EPADProject epadProject = project2EPADProject(sessionID, username, project, searchFilter, false);

            if (epadProject != null) {
                //log.info("project " + epadProject.id + " aim count:" + epadProject.numberOfAnnotations);
                epadProjectList.addEPADProject(epadProject);
            }
        }
        long convtime = System.currentTimeMillis();
        log.info("Time to get " + epadProjectList.ResultSet.totalRecords + " projects:" + (gettime - starttime)
                + " msecs, to convert:" + (convtime - gettime) + " msecs");
        return epadProjectList;
    }

}