/FileExtraction/Java_unseen/IMS-MAXIMS_openMAXIMS/Source Library/openmaxims_workspace/Pathways/src/ims/pathways/domain/impl/EventConfigurationImpl.java
//#############################################################################
//#                                                                           #
//#  Copyright (C) <2015>  <IMS MAXIMS>                                       #
//#                                                                           #
//#  This program is free software: you can redistribute it and/or modify     #
//#  it under the terms of the GNU Affero General Public License as           #
//#  published by the Free Software Foundation, either version 3 of the       #
//#  License, or (at your option) any later version.                          # 
//#                                                                           #
//#  This program is distributed in the hope that it will be useful,          #
//#  but WITHOUT ANY WARRANTY; without even the implied warranty of           #
//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            #
//#  GNU Affero General Public License for more details.                      #
//#                                                                           #
//#  You should have received a copy of the GNU Affero General Public License #
//#  along with this program.  If not, see <http://www.gnu.org/licenses/>.    #
//#                                                                           #
//#  IMS MAXIMS provides absolutely NO GUARANTEE OF THE CLINICAL SAFTEY of    #
//#  this program.  Users of this software do so entirely at their own risk.  #
//#  IMS MAXIMS only ensures the Clinical Safety of unaltered run-time        #
//#  software that it builds, deploys and maintains.                          #
//#                                                                           #
//#############################################################################
//#EOH
// This code was generated by Catalin Tomozei using IMS Development Environment (version 1.60 build 2838.16667)
// Copyright (C) 1995-2007 IMS MAXIMS plc. All rights reserved.

package ims.pathways.domain.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import ims.admin.domain.ApplicationRoles;
import ims.admin.domain.impl.ApplicationRolesImpl;
import ims.admin.helper.RecordStatusValidator;
import ims.admin.vo.AppImageVoCollection;
import ims.admin.vo.AppRoleShortVoCollection;
import ims.admin.vo.domain.AppImageVoAssembler;
import ims.core.admin.domain.objects.ProviderSystem;
import ims.core.admin.vo.ProviderSystemRefVo;
import ims.core.configuration.domain.objects.AppUser;
import ims.core.configuration.vo.AppUserRefVo;
import ims.core.vo.lookups.PreActiveActiveInactiveStatus;
import ims.domain.DomainFactory;
import ims.domain.exceptions.DomainInterfaceException;
import ims.domain.exceptions.DomainRuntimeException;
import ims.domain.exceptions.ForeignKeyViolationException;
import ims.domain.exceptions.StaleObjectException;
import ims.domain.exceptions.UniqueKeyViolationException;
import ims.domain.exceptions.UnqViolationUncheckedException;
import ims.domain.lookups.LookupInstance;
import ims.framework.exceptions.CodingRuntimeException;
import ims.ocrr.vo.ProviderSystemVoCollection;
import ims.ocrr.vo.domain.ProviderSystemVoAssembler;
import ims.pathways.configuration.domain.objects.Event;
import ims.pathways.configuration.domain.objects.EventExternalEventMapping;
import ims.pathways.configuration.domain.objects.EventRTTEvent;
import ims.pathways.configuration.domain.objects.EventTarget;
import ims.pathways.configuration.domain.objects.RTTEvent;
import ims.pathways.configuration.vo.EventRefVo;
import ims.pathways.domain.ExternalEventMappingsConfiguration;
import ims.pathways.domain.RTTEventConfiguration;
import ims.pathways.domain.TargetConfiguration;
import ims.pathways.domain.base.impl.BaseEventConfigurationImpl;
import ims.pathways.vo.EventExternalEventMappingVoCollection;
import ims.pathways.vo.EventRTTEventVoCollection;
import ims.pathways.vo.EventTargetVoCollection;
import ims.pathways.vo.EventVo;
import ims.pathways.vo.EventVoCollection;
import ims.pathways.vo.ExternalEventMappingVo;
import ims.pathways.vo.ExternalEventMappingVoCollection;
import ims.pathways.vo.RTTEventVo;
import ims.pathways.vo.RTTEventVoCollection;
import ims.pathways.vo.TargetConfigurationShortVo;
import ims.pathways.vo.TargetConfigurationShortVoCollection;
import ims.pathways.vo.domain.EventExternalEventMappingVoAssembler;
import ims.pathways.vo.domain.EventRTTEventVoAssembler;
import ims.pathways.vo.domain.EventTargetVoAssembler;
import ims.pathways.vo.domain.EventVoAssembler;
import ims.pathways.vo.domain.ExternalEventMappingVoAssembler;
import ims.pathways.vo.domain.RTTEventVoAssembler;

public class EventConfigurationImpl extends BaseEventConfigurationImpl
{
	private static final long	serialVersionUID	= 1L;

	public AppRoleShortVoCollection listRoles()
	{
		ApplicationRoles impl = (ApplicationRoles) getDomainImpl(ApplicationRolesImpl.class);
		return impl.listRoles();
	}

	public ExternalEventMappingVoCollection listExternalEventMappingsByCriteria(ExternalEventMappingVo filter)
	{
		ExternalEventMappingsConfiguration impl = (ExternalEventMappingsConfiguration) getDomainImpl(ExternalEventMappingsConfigurationImpl.class);
		return impl.listByCriteria(null);
	}

	public RTTEventVoCollection listRTTEvents(RTTEventVo rttEventVo)
	{
		RTTEventConfiguration impl = (RTTEventConfiguration) getDomainImpl(RTTEventConfigurationImpl.class);
		return impl.listRTTEvents(rttEventVo);
	}

	private AppUser getUser()
	{
		if(getMosUser() != null)
		{
			AppUserRefVo user = ((ims.core.vo.MemberOfStaffShortVo)getMosUser()).getAppUser();
			return (AppUser) getDomainFactory().getDomainObject(user);
		}
		return null;
	}
	
	public EventVo save(
			EventVo event, 
				EventTargetVoCollection eventTargets, 
					EventExternalEventMappingVoCollection externalToBeAdded, 
						EventExternalEventMappingVoCollection externalToBeDeleted,
							EventRTTEventVoCollection rttToBeAdded,
								EventRTTEventVoCollection rttToBeDeteled) 
									throws StaleObjectException, ForeignKeyViolationException, UniqueKeyViolationException, DomainInterfaceException
	{
		if (event == null)
		{
			throw new DomainRuntimeException("Invalid record");
		}
		if (!event.isValidated())
		{
			throw new CodingRuntimeException("Record not validated");
		}
		
		//CheckForUniq
		checkForUniqRecords(event, externalToBeAdded, rttToBeAdded);

		DomainFactory factory = getDomainFactory();

		if (eventTargets != null)
		{
			event.setEventTargets(eventTargets.toIRecordStatusTreeArray());
		}

		RecordStatusValidator helper = new RecordStatusValidator(factory, getLookupService());
		helper.validate(event);

		// Save Event
		Event domainRecord = EventVoAssembler.extractEvent(factory, event);
		
		if(domainRecord.getName() != null)
		{
			domainRecord.setUpperName(domainRecord.getName().toUpperCase());
		}
		
		factory.save(domainRecord);
		event = EventVoAssembler.create(domainRecord);
		
		//Save External
		saveExternal(event, externalToBeAdded, externalToBeDeleted, factory, domainRecord);
		//Save RTT
		saveRTT(event, rttToBeAdded, rttToBeDeteled, factory, domainRecord);
		//Save Targets
		saveTargets(event, eventTargets, factory);

		return EventVoAssembler.create(domainRecord);
	}

	private void checkForUniqRecords(EventVo event,
				EventExternalEventMappingVoCollection externalToBeAdded,
					EventRTTEventVoCollection rttToBeAdded)
						throws UniqueKeyViolationException 
	{
		// Check for UNIQ only for ACTIVE records
		if (event.getStatusIsNotNull() && event.getStatus().equals(PreActiveActiveInactiveStatus.ACTIVE))
		{
			// Check Event
			if (checkForUniqEvent(event).size() > 0)
				throw new UniqueKeyViolationException("Event Name must be unique!");

			// Check External Mappings
			if (externalToBeAdded != null && externalToBeAdded.size() > 0)
			{
				String err = checkForUniqueExternalMappings(externalToBeAdded);
				if (err != null && err.trim().length() > 0)
				{
					throw new UniqueKeyViolationException(err);
				}
			}

			// Check RTT Event
			if (rttToBeAdded != null && rttToBeAdded.size() > 0)
			{
				String err = checkForUniqueRTT(rttToBeAdded);
				if (err != null && err.trim().length() > 0)
				{
					throw new UniqueKeyViolationException(err);
				}
			}
		}
	}

	private void saveTargets(EventVo event,
				EventTargetVoCollection eventTargets, DomainFactory factory)
					throws ForeignKeyViolationException, StaleObjectException,
						UniqueKeyViolationException 
	{
		if (eventTargets != null)
		{
			try
			{
				saveTargetEvents(event, factory, eventTargets);
			}
			catch (UnqViolationUncheckedException e)
			{
				throw new UniqueKeyViolationException("Event Target Management must be unique!");
			}
		}
	}

	private void saveExternal(EventVo event,
				EventExternalEventMappingVoCollection externalToBeAdded,
					EventExternalEventMappingVoCollection externalToBeDeleted,
						DomainFactory factory, Event domainRecord)
							throws StaleObjectException, ForeignKeyViolationException 
	{	
		// Save External
		if(externalToBeAdded != null)
		{
			for (int i = 0; i < externalToBeAdded.size(); i++)
			{
				EventExternalEventMapping domainExternal = EventExternalEventMappingVoAssembler.extractEventExternalEventMapping(factory, externalToBeAdded.get(i));
				domainExternal.setEvent(domainRecord);
				if(domainExternal.getStatus().equals(getDomLookup(PreActiveActiveInactiveStatus.ACTIVE)) &&
						domainExternal.getActivatedDateTime() == null)
				{
					domainExternal.setStatus(getDomLookup(PreActiveActiveInactiveStatus.ACTIVE));
					domainExternal.setActivatedBy(getUser());
					domainExternal.setActivatedDateTime(new Date());
				}
				else if(domainExternal.getStatus().equals(getDomLookup(PreActiveActiveInactiveStatus.INACTIVE)))
				{
					if(domainExternal.getInactivatedBy() == null)
					{
						domainExternal.setInactivatedBy(getUser());
						domainExternal.setInactivatedDateTime(new Date());
					}
				}
				
				factory.save(domainExternal);
			}
		}
		
		if(externalToBeDeleted != null)
		{
			for (int i = 0; i < externalToBeDeleted.size(); i++)
			{
				EventExternalEventMapping domainExternal = EventExternalEventMappingVoAssembler.extractEventExternalEventMapping(factory, externalToBeDeleted.get(i));
				factory.delete(domainExternal);
			}
		}
	}

	private void saveRTT(EventVo event, EventRTTEventVoCollection rttToBeAdded,
				EventRTTEventVoCollection rttToBeDeteled, DomainFactory factory,
					Event domainRecord) throws StaleObjectException,
						ForeignKeyViolationException 
	{
		// Save RTT
		if (rttToBeAdded != null)
		{
			for (int j = 0; j < rttToBeAdded.size(); j++)
			{
				EventRTTEvent domainRTT = EventRTTEventVoAssembler.extractEventRTTEvent(factory, rttToBeAdded.get(j));
				RTTEvent rttEvent = (RTTEvent) domainRTT.getRTTEvent();;
				rttEvent.setUpperName(rttEvent.getName());
				domainRTT.setEvent(domainRecord);
				
				if(domainRTT.getStatus().equals(getDomLookup(PreActiveActiveInactiveStatus.ACTIVE)) &&
						domainRTT.getActivatedDateTime() == null)
				{
					domainRTT.setStatus(getDomLookup(PreActiveActiveInactiveStatus.ACTIVE));
					domainRTT.setActivatedBy(getUser());
					domainRTT.setActivatedDateTime(new Date());
				}
				else if(domainRTT.getStatus().equals(getDomLookup(PreActiveActiveInactiveStatus.INACTIVE)) &&
						domainRTT.getInactivatedDateTime() == null)
				{
					if(domainRTT.getInactivatedBy() == null)
					{
						domainRTT.setInactivatedBy(getUser());
						domainRTT.setInactivatedDateTime(new Date());
					}
				}
				
				factory.save(domainRTT);
			}
		}
		if(rttToBeDeteled != null)
		{
			for (int j = 0; j < rttToBeDeteled.size(); j++)
			{
				EventRTTEvent domainRTT = EventRTTEventVoAssembler.extractEventRTTEvent(factory, rttToBeDeteled.get(j));
				factory.delete(domainRTT);
			}
		}
	}

	@SuppressWarnings("unchecked") private String checkForUniqueExternalMappings(EventExternalEventMappingVoCollection externalMappings)
	{
		ArrayList<String> names = new ArrayList<String>();
		ArrayList<Serializable> values = new ArrayList<Serializable>();

		DomainFactory factory = getDomainFactory();
		StringBuffer ids = new StringBuffer();
		StringBuffer exclude = new StringBuffer();
		exclude.append(externalMappings.get(0).getEvent().getID_Event());

		String errors = new String();
		
		for (int i = 0; i < externalMappings.size(); i++)
		{
			if(externalMappings.get(i).getStatus().equals(PreActiveActiveInactiveStatus.ACTIVE))
			{
				if (i > 0 &&
						i < externalMappings.size())
				{
							ids.append(" , ");
				}
				ids.append(externalMappings.get(i).getExternalEventMapping().getID_ExternalEventMapping());				
			}
		}

		if (ids.length() == 0)
			return null;
		
		names.add("id_status");
		values.add(PreActiveActiveInactiveStatus.ACTIVE.getID());

		List eventsMappings = factory.find("select ext.event.id, ext.externalEventMapping.id, event.id, event.name, event.status, event.status.id, external.id, external.group, external.detail, external.specialty, mosname.name.surname, mosname.name.forename, external.clinicCode, provider.systemName from EventExternalEventMapping as ext left join ext.event as event left join ext.externalEventMapping as external left join external.consultant as consult left join consult.mos as mosname left join external.providerSystem as provider where ext.externalEventMapping.id in (" + ids + ") and event.id <> " + exclude + " and event.status.id = :id_status ", names, values);

		Iterator eventsMappingsList = eventsMappings.iterator();
		while (eventsMappingsList.hasNext())
		{
			Object[] obj = (Object[]) eventsMappingsList.next();
			errors += ("External system " + ((String) obj[13]).toUpperCase() + ", " + ((LookupInstance) obj[7]).getText() + ", " + ((LookupInstance) obj[8]).getText() + ", " + ((LookupInstance) obj[9]).getText() + (((String) obj[10]) != null ? ", " + ((String) obj[10]) + " " : "") + (((String) obj[11]) != null ? ((String) obj[11]) + " , " : "") + (((String) obj[12]) != null ? ((String) obj[12]) : "") + " is already linked to event " + ((String) obj[3]).toUpperCase() + "\n");
		}

		return errors;
	}

	@SuppressWarnings("unchecked") private String checkForUniqueRTT(EventRTTEventVoCollection rttColl)
	{
		ArrayList<String> names = new ArrayList<String>();
		ArrayList<Serializable> values = new ArrayList<Serializable>();

		DomainFactory factory = getDomainFactory();
		StringBuffer ids = new StringBuffer();
		StringBuffer exclude = new StringBuffer();
		String errors = new String();
		exclude.append(rttColl.get(0).getEvent().getID_Event());

		for (int i = 0; i < rttColl.size(); i++)
		{
			if(rttColl.get(i).getStatus().equals(PreActiveActiveInactiveStatus.ACTIVE))
			{
				ids.append(rttColl.get(i).getRTTEvent().getID_RTTEvent());
				if (i < rttColl.size() - 1  &&
						rttColl.get(rttColl.size() - 1) != null &&
							rttColl.get(rttColl.size() - 1).getStatusIsNotNull() &&
								!rttColl.get(rttColl.size() - 1).getStatus().equals(PreActiveActiveInactiveStatus.INACTIVE))
				{
					ids.append(" , ");
				}
			}
		}

		if (ids.length() == 0)
			return null;
		
		names.add("id_status");
		values.add(PreActiveActiveInactiveStatus.ACTIVE.getID());

		List rtt = factory.find("select exRTT.event.name, exRTT.event.status, provider.systemName, exRTT.id, rtt.name from EventRTTEvent as exRTT left join exRTT.event as event left join exRTT.rTTEvent as rtt left join rtt.providerSystem as provider left join event.status as status where rtt.id in (" + ids + ") and event.id <> " + exclude + " and status.id = :id_status ", names, values);

		Iterator rttEvent = rtt.iterator();
		while (rttEvent.hasNext())
		{
			Object[] obj = (Object[]) rttEvent.next();
			errors += ("RTT status event  " + ((String) obj[2]).toUpperCase() + " , " + ((String) obj[4]).toUpperCase() + " is already linked to event " + ((String) obj[0]).toUpperCase() + "\n");
		}

		return errors;
	}

	@SuppressWarnings("unchecked") private EventVoCollection checkForUniqEvent(EventVo record)
	{
		DomainFactory factory = getDomainFactory();
		StringBuffer hql = new StringBuffer();
		ArrayList<String> names = new ArrayList<String>();
		ArrayList<Serializable> values = new ArrayList<Serializable>();

		hql.append("select event from Event as event left join event.status as status where event.name = :name and status.id = :id_status ");
		names.add("name");
		names.add("id_status");
		values.add(record.getName());
		values.add(PreActiveActiveInactiveStatus.ACTIVE.getID());

		if (record.getID_EventIsNotNull())
		{
			hql.append(" and event.id <> :id  ");
			names.add("id");
			values.add(record.getID_Event());
		}

		List collection = factory.find(hql.toString(), names, values);
		return EventVoAssembler.createEventVoCollectionFromEvent(collection);
	}

	@SuppressWarnings("unchecked") private void saveTargetEvents(EventVo event, DomainFactory factory, EventTargetVoCollection eventTargets) throws ForeignKeyViolationException, StaleObjectException, UniqueKeyViolationException, UnqViolationUncheckedException
	{
		if (event.getID_Event() != null)
		{
			List oldEventsTargets = factory.find("from EventTarget et where et.event.id = '" + event.getID_Event().toString() + "'");
			Iterator oldEventsTargetsList = oldEventsTargets.iterator();
			while (oldEventsTargetsList.hasNext())
			{
				EventTarget doOldEventTarget = (EventTarget) oldEventsTargetsList.next();
				factory.delete(doOldEventTarget);
			}
		}
		else
		{
			return;
		}

		for (int i = 0; i < eventTargets.size(); i++)
		{
			eventTargets.get(i).getEvent().setID_Event(event.getID_Event());
			eventTargets.get(i).setID_EventTarget(null);
		}

		// Save eventTarget
		List newEventsTargets = EventTargetVoAssembler.extractEventTargetList(factory, eventTargets);
		Iterator newEventsTargetsList = newEventsTargets.iterator();

		while (newEventsTargetsList.hasNext())
		{
			EventTarget doNewEventTarget = (EventTarget) newEventsTargetsList.next();
			factory.save(doNewEventTarget);
		}
	}

	public TargetConfigurationShortVoCollection listTargetByCriteria(TargetConfigurationShortVo filter)
	{
		TargetConfiguration impl = (TargetConfiguration) getDomainImpl(TargetConfigurationImpl.class);
		return impl.listByCriteria(filter);
	}

	public ProviderSystemVoCollection listProviderSystems()
	{
		DomainFactory factory = getDomainFactory();
		return ProviderSystemVoAssembler.createProviderSystemVoCollectionFromProviderSystem(factory.listDomainObjects(ProviderSystem.class)).sort();
	}

	public RTTEventVoCollection getNameByProviderSystems(ProviderSystemRefVo voRef)
	{
		return RTTEventVoAssembler.createRTTEventVoCollectionFromRTTEvent(getDomainFactory().find("from RTTEvent as rtt where rtt.providerSystem.id = :id ", new String[]{"id"}, new Object[]{voRef.getID_ProviderSystem()}));
	}

	public EventVo getEvent(EventRefVo voRef)
	{
		if (voRef == null)
			throw new DomainRuntimeException("Cannot get EventVo for null EventRefVo");

		DomainFactory factory = getDomainFactory();
		Event doEvent = (Event) factory.getDomainObject(Event.class, voRef.getID_Event());
		return EventVoAssembler.create(doEvent);
	}

	public RTTEventVo getRTTEventByPASCode(String code)
	{
		if (code == null)
			throw new DomainRuntimeException("Cannot get RTTEventVo for null PAS code");

		DomainFactory factory = getDomainFactory();
		RTTEvent result = RTTEvent.getRTTEventFromPASCode(factory, code);
		return RTTEventVoAssembler.create(result);
	}

	public AppImageVoCollection list16x16Icons(String name)
	{
		return AppImageVoAssembler.createAppImageVoCollectionFromAppImage(getDomainFactory().find("from AppImage as appImage where (appImage.height = :height and appImage.width = :width and appImage.imagePath like '%" + name + "%')", new String[]{"height", "width"}, new Object[]{16, 16}, 1000));
	}

	public EventTargetVoCollection getEventTargetsByEvent(EventRefVo voRef)
	{
		//list all ACTIVE and PREACTIVE EventsTargets
		return EventTargetVoAssembler.createEventTargetVoCollectionFromEventTarget(getDomainFactory().find("from EventTarget et where et.event.id = :id ", new String[]{"id"}, new Object[]{voRef.getID_Event()}));
	}

	@SuppressWarnings("unchecked")
	public ExternalEventMappingVoCollection getEventMappingsByEventAndStatus(EventRefVo voRef, PreActiveActiveInactiveStatus status)
	{
		DomainFactory factory = getDomainFactory();
		ArrayList markers = new ArrayList();
		ArrayList values = new ArrayList();
		
		String query = "select eem.externalEventMapping from EventExternalEventMapping as eem where eem.event.id = :idEvent";
		markers.add("idEvent");
		values.add(voRef.getID_Event());
		
		if (status != null)
		{
			query += " and eem.status = :status";
			markers.add("status");
			values.add(getDomLookup(status));
		}
		
		List exts = factory.find(query, markers, values,1000);
		return ExternalEventMappingVoAssembler.createExternalEventMappingVoCollectionFromExternalEventMapping(exts); 
	}

	@SuppressWarnings("unchecked")
	public RTTEventVoCollection getRTTByEventAndStatus(EventRefVo voRef, PreActiveActiveInactiveStatus status)
	{
		DomainFactory factory = getDomainFactory();
		ArrayList markers = new ArrayList();
		ArrayList values = new ArrayList();
		
		String query = "select ere.rTTEvent from EventRTTEvent as ere where ere.event.id = :idEvent";
		markers.add("idEvent");
		values.add(voRef.getID_Event());
		
		if (status != null)
		{
			query += " and ere.status = :status";
			markers.add("status");
			values.add(getDomLookup(status));
		}
		
		List rtts = factory.find(query, markers, values);
		return RTTEventVoAssembler.createRTTEventVoCollectionFromRTTEvent(rtts); 
	}
	
	@SuppressWarnings("unchecked")
	public EventRTTEventVoCollection getEventRTTEvent(EventRefVo voRef, PreActiveActiveInactiveStatus status)
	{
		DomainFactory factory = getDomainFactory();
		ArrayList markers = new ArrayList();
		ArrayList values = new ArrayList();
		
		String query = "select ertt from EventRTTEvent as ertt where ertt.event.id = :idEvent";
		markers.add("idEvent");
		values.add(voRef.getID_Event());
		
		if (status != null)
		{
			query += " and ertt.event.status = :status";
			markers.add("status");
			values.add(getDomLookup(status));
		}
		
		List rtts = factory.find(query, markers, values);
		return EventRTTEventVoAssembler.createEventRTTEventVoCollectionFromEventRTTEvent(rtts); 
	}
	
	@SuppressWarnings("unchecked")
	public EventExternalEventMappingVoCollection getEventExternalEventMapping(EventRefVo voRef, PreActiveActiveInactiveStatus status)
	{
		DomainFactory factory = getDomainFactory();
		ArrayList markers = new ArrayList();
		ArrayList values = new ArrayList();
		
		String query = "select eeem from EventExternalEventMapping as eeem where eeem.event.id = :idEvent";
		markers.add("idEvent");
		values.add(voRef.getID_Event());
		
		if (status != null)
		{
			query += " and eeem.event.status = :status";
			markers.add("status");
			values.add(getDomLookup(status));
		}
		
		List eeem = factory.find(query, markers, values, 1000);
		return EventExternalEventMappingVoAssembler.createEventExternalEventMappingVoCollectionFromEventExternalEventMapping(eeem); 
	}
}
