/**
 * Petals View - Functional Supervision.
 * Copyright (c) 2010 EBM Websourcing, http://www.ebmwebsourcing.com/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * -------------------------------------------------------------------------
 * NotificationReaderTest.java
 * -------------------------------------------------------------------------
 */
package com.ebmwebsourcing.petalsview.service.notification;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.annotation.Resource;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.ebmwebsourcing.petalsview.persistence.dao.flow.FlowDAO;
import com.ebmwebsourcing.petalsview.persistence.dao.flow.FlowStepDAO;
import com.ebmwebsourcing.petalsview.persistence.dao.flowref.FlowRefDAO;
import com.ebmwebsourcing.petalsview.persistence.dao.flowref.FlowStepErrorRefDAO;
import com.ebmwebsourcing.petalsview.persistence.dao.flowref.FlowStepRefDAO;
import com.ebmwebsourcing.petalsview.persistence.model.flow.Flow;
import com.ebmwebsourcing.petalsview.persistence.model.flow.FlowStep;
import com.ebmwebsourcing.petalsview.persistence.model.flowref.FlowRef;
import com.ebmwebsourcing.petalsview.persistence.model.flowref.FlowStepErrorRef;
import com.ebmwebsourcing.petalsview.persistence.model.flowref.FlowStepRef;
import com.ebmwebsourcing.petalsview.persistence.model.flowref.StepParameter;
import com.ebmwebsourcing.petalsview.service.CommonServiceConfig;

/**
 * @author ofabre
 */
@RunWith(SpringJUnit4ClassRunner.class)
public class NotificationReaderTest extends CommonServiceConfig {

	public static int GF_TYPE = 0;
	public static int GRDR_TYPE = 1;

	@Resource
	private FlowDAO flowDAO;
	
	@Resource
	private FlowStepDAO flowStepDAO;
	
	@Resource
	private NotificationProcessor notificationProcessor;

	@Resource
	private FlowRefDAO flowRefDAO;

	@Resource
	private FlowStepRefDAO flowStepRefDAO;

	@Resource
	private FlowStepErrorRefDAO flowStepErrorRefDAO;


	public void testReadNotificationClassicalOrder() {
		Notification notification = null;
		List<Notification> notificationList = null;
		try {
			final NotificationReader reader = new NotificationReader();
			final NotificationProcessorImpl processor = new NotificationProcessorImpl();
			final ClassLoader classLoader = this.getClass().getClassLoader();
			notificationList = new CopyOnWriteArrayList<Notification>();
			final Source start1 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-start-1.xml"));
			final Source start2 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-start-2.xml"));
			final Source start3 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-start-3.xml"));
			final Source start4 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-start-4.xml"));
			final Source stop1 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-stop-1.xml"));
			final Source stop2 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-stop-2.xml"));
			final Source stop3 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-stop-3.xml"));
			final Source stop4 = new StreamSource(classLoader
					.getResourceAsStream("notifMessage-stop-4.xml"));

			// start1
			notification = reader.read(start1);
			notificationList.add(notification);
			processor.process(notificationList);
			Flow flow = this.load("AAAA");
			List<FlowStep> steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(1, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			assertEquals(Flow.IN_PROGRESS_STATUS, steps.get(0).getStatus());
			assertEquals("endpoint1", steps.get(0).getEndpointName());
			/*
			 * List<String> params = flow.getParameters();
			 * assertNotNull(params); assertEquals(3, params.size());
			 * assertTrue(params.contains("param1"));
			 * assertTrue(params.contains("param2"));
			 * assertTrue(params.contains("param3"));
			 */

			// start2
			notification = reader.read(start2);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(2, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			FlowStep flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
			FlowStep flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
			assertNotNull(flowStep1);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep2.getStatus());

			// start3
			notification = reader.read(start3);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(3, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			flowStep1 =  this.flowStepDAO.loadByMeUUID("0001");
			flowStep2 =  this.flowStepDAO.loadByMeUUID("0002");
			FlowStep flowStep3 =  this.flowStepDAO.loadByMeUUID("0003");
			assertNotNull(flowStep1);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep2.getStatus());
			assertNotNull(flowStep3);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep3.getStatus());

			// start4
			notification = reader.read(start4);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(4, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
			flowStep2 = this.flowStepDAO.loadByMeUUID("0003");
			flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
			FlowStep flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
			assertNotNull(flowStep1);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep2.getStatus());
			assertNotNull(flowStep3);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep3.getStatus());
			assertNotNull(flowStep4);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep4.getStatus());

			// stop3
			notification = reader.read(stop3);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(4, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
			flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
			flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
			flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
			assertNotNull(flowStep1);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep2.getStatus());
			assertNotNull(flowStep3);
			assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
			assertNotNull(flowStep4);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep4.getStatus());

			// stop4
			notification = reader.read(stop4);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(4, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
			flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
			flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
			flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
			assertNotNull(flowStep1);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep2.getStatus());
			assertNotNull(flowStep3);
			assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
			assertNotNull(flowStep4);
			assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());

			// stop2
			notification = reader.read(stop2);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(4, steps.size());
			assertEquals(Flow.IN_PROGRESS_STATUS, flow.getStatus().intValue());
			flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
			flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
			flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
			flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
			assertNotNull(flowStep1);
			assertEquals(Flow.IN_PROGRESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.SUCCESS_STATUS, flowStep2.getStatus());
			assertNotNull(flowStep3);
			assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
			assertNotNull(flowStep4);
			assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());

			// stop1
			notification = reader.read(stop1);
			notificationList.clear();
			notificationList.add(notification);
			processor.process(notificationList);
			flow = this.load("AAAA");
			steps = this.flowStepDAO.loadByFlowId("AAAA");

			assertNotNull(flow);
			assertNotNull(steps);
			assertEquals(4, steps.size());
			assertEquals(Flow.SUCCESS_STATUS, flow.getStatus().intValue());
			flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
			flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
			flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
			flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
			assertNotNull(flowStep1);
			assertEquals(Flow.SUCCESS_STATUS, flowStep1.getStatus());
			assertNotNull(flowStep2);
			assertEquals(Flow.SUCCESS_STATUS, flowStep2.getStatus());
			assertNotNull(flowStep3);
			assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
			assertNotNull(flowStep4);
			assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());

			// cleanup
			this.removeStep("AAAA", "0001", "interface1",
					"service1", "endpoint1");
			this.removeStep("AAAA", "0002", "interface2",
					"service2", "endpoint2");
			this.removeStep("AAAA", "0003", "interface3",
					"service3", "endpoint3");
			this.removeStep("AAAA", "0004", "interface4",
					"service4", "endpoint4");
			this.remove("AAAA");
		} catch (final NotificationProcessingException e) {
			fail(e.getMessage());
		}
	}
	
	public void remove(final String id) {
		flowDAO.remove(flowDAO.loadByPetalsId(id));
	}
	
	public void removeStep(final String flowId, final String meUUID,
			final String interfaceName, final String serviceName,
			final String endpointName) {
		final FlowStep flowStep = flowStepDAO.loadByMeUUID(meUUID);
		flowStepDAO.remove(flowStep);
	}

	@Test
	public void testReadNotificationReverseOrder()
			throws NotificationProcessingException {
		Notification notification = null;
		List<Notification> notificationList = null;

		final NotificationReader reader = new NotificationReader();
		final ClassLoader classLoader = this.getClass().getClassLoader();
		notificationList = new CopyOnWriteArrayList<Notification>();
		final Source start1 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-1.xml"));
		final Source start2 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-2.xml"));
		final Source start3 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-3.xml"));
		final Source start4 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-4.xml"));
		final Source stop1 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-1.xml"));
		final Source stop2 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-2.xml"));
		final Source stop3 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-3.xml"));
		final Source stop4 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-4.xml"));
		// stop1, stop2, stop4, stop3
		notification = reader.read(stop1);
		notificationList.add(notification);
		notification = reader.read(stop2);
		notificationList.add(notification);
		notification = reader.read(stop4);
		notificationList.add(notification);
		notification = reader.read(stop3);
		notificationList.add(notification);
		notificationProcessor.process(notificationList);
		Flow flow = this.load("AAAA");
		List<FlowStep> steps = this.flowStepDAO.loadByFlowId("AAAA");
		assertNotNull(flow);
		assertNotNull(steps);
		assertEquals(4, steps.size());
		assertEquals(Flow.SUCCESS_STATUS, flow.getStatus().intValue());
		FlowStep flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
		FlowStep flowStep2 = this.flowStepDAO.loadByMeUUID("0003");
		FlowStep flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
		FlowStep flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
		assertNotNull(flowStep1);
		assertEquals(Flow.SUCCESS_STATUS, flowStep1.getStatus());
		assertNull(flowStep1.getStartDate());
		assertNotNull(flowStep2);
		assertEquals(Flow.SUCCESS_STATUS, flowStep2.getStatus());
		assertNull(flowStep2.getStartDate());
		assertNotNull(flowStep3);
		assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
		assertNull(flowStep3.getStartDate());
		assertNotNull(flowStep4);
		assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());
		assertNull(flowStep4.getStartDate());

		// start4, start3, start2, start1
		notificationList.clear();
		notification = reader.read(start4);
		notificationList.add(notification);
		notification = reader.read(start3);
		notificationList.add(notification);
		notification = reader.read(start2);
		notificationList.add(notification);
		notification = reader.read(start1);
		notificationList.add(notification);
		notificationProcessor.process(notificationList);

		flow = this.load("AAAA");
		long longStartDate = flow.getStartDate();
		assertEquals(1100000, longStartDate);
		long longEndDate = flow.getEndDate();
		assertEquals(1800000, longEndDate);
		steps = this.flowStepDAO.loadByFlowId("AAAA");
		assertNotNull(flow);
		assertNotNull(steps);
		assertEquals(4, steps.size());
		assertEquals(Flow.SUCCESS_STATUS, flow.getStatus().intValue());
		flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
		flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
		flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
		flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
		assertNotNull(flowStep1);
		assertEquals(Flow.SUCCESS_STATUS, flowStep1.getStatus());
		assertEquals(1100000, flowStep1.getStartDate().longValue());
		assertEquals(1800000, flowStep1.getEndDate().longValue());
		assertNotNull(flowStep2);
		assertEquals(Flow.SUCCESS_STATUS, flowStep2.getStatus());
		assertEquals(1200000, flowStep2.getStartDate().longValue());
		assertEquals(1700000, flowStep2.getEndDate().longValue());
		assertNotNull(flowStep3);
		assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
		assertEquals(1300000, flowStep3.getStartDate().longValue());
		assertEquals(1500000, flowStep3.getEndDate().longValue());
		assertNotNull(flowStep4);
		assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());
		assertEquals(1400000, flowStep4.getStartDate().longValue());
		assertEquals(1600000, flowStep4.getEndDate().longValue());

		// cleanup
		this.removeStep("AAAA", "0001", "interface1", "service1",
				"endpoint1");
		this.removeStep("AAAA", "0002", "interface2", "service2",
				"endpoint2");
		this.removeStep("AAAA", "0003", "interface3", "service3",
				"endpoint3");
		this.removeStep("AAAA", "0004", "interface4", "service4",
				"endpoint4");
		this.remove("AAAA");

	}

	@Test
	public void testReadNotificationReverseOrderWithFailure()
			throws NotificationProcessingException {
		Notification notification = null;
		List<Notification> notificationList = null;

		final NotificationReader reader = new NotificationReader();
		final ClassLoader classLoader = this.getClass().getClassLoader();
		notificationList = new CopyOnWriteArrayList<Notification>();
		final Source start1 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-1.xml"));
		final Source start2 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-2.xml"));
		final Source start3 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-3.xml"));
		final Source start4 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-start-4.xml"));
		final Source failure1 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-failure-1.xml"));
		final Source stop2 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-2.xml"));
		final Source stop3 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-3.xml"));
		final Source stop4 = new StreamSource(classLoader
				.getResourceAsStream("notifMessage-stop-4.xml"));

		// failure1, stop2, stop4, stop3
		notificationList.clear();
		notification = reader.read(failure1);
		notificationList.add(notification);
		notification = reader.read(stop2);
		notificationList.add(notification);
		notification = reader.read(stop4);
		notificationList.add(notification);
		notification = reader.read(stop3);
		notificationList.add(notification);
		notificationProcessor.process(notificationList);
		Flow flow = this.load("AAAA");
		List<FlowStep> steps = this.flowStepDAO.loadByFlowId("AAAA");
		assertNotNull(flow);
		assertNotNull(steps);
		assertEquals(4, steps.size());
		assertEquals(1, flow.getStatus().intValue());
		FlowStep flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
		FlowStep flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
		FlowStep flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
		FlowStep flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
		assertNotNull(flowStep1);
		assertEquals(1, flowStep1.getStatus());
		assertNull(flowStep1.getStartDate());
		assertNotNull(flowStep2);
		assertEquals(Flow.SUCCESS_STATUS, flowStep2.getStatus());
		assertNull(flowStep2.getStartDate());
		assertNotNull(flowStep3);
		assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
		assertNull(flowStep3.getStartDate());
		assertNotNull(flowStep4);
		assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());
		assertNull(flowStep4.getStartDate());

		// start4, start3, start2, start1
		notificationList.clear();
		notification = reader.read(start4);
		notificationList.add(notification);
		notification = reader.read(start3);
		notificationList.add(notification);
		notification = reader.read(start2);
		notificationList.add(notification);
		notification = reader.read(start1);
		notificationList.add(notification);
		notificationProcessor.process(notificationList);
		flow = this.load("AAAA");
		long longStartDate = flow.getStartDate();
		assertEquals(1100000, longStartDate);
		long longEndDate = flow.getEndDate();
		assertEquals(1800000, longEndDate);
		steps = this.flowStepDAO.loadByFlowId("AAAA");
		assertNotNull(flow);
		assertNotNull(steps);
		assertEquals(4, steps.size());
		assertEquals(1, flow.getStatus().intValue());
		flowStep1 = this.flowStepDAO.loadByMeUUID("0001");
		flowStep2 = this.flowStepDAO.loadByMeUUID("0002");
		flowStep3 = this.flowStepDAO.loadByMeUUID("0003");
		flowStep4 = this.flowStepDAO.loadByMeUUID("0004");
		assertNotNull(flowStep1);
		assertEquals(1, flowStep1.getStatus());
		assertEquals(1100000, flowStep1.getStartDate().longValue());
		assertEquals(1800000, flowStep1.getEndDate().longValue());
		List<String> params = flowStep1.getParameters();
		assertNotNull(params);
		assertEquals(3, params.size());
		assertTrue(params.contains("param11"));
		assertTrue(params.contains("param12"));
		assertTrue(params.contains("param13"));

		assertNotNull(flowStep2);
		assertEquals(Flow.SUCCESS_STATUS, flowStep2.getStatus());
		assertEquals(1200000, flowStep2.getStartDate().longValue());
		assertEquals(1700000, flowStep2.getEndDate().longValue());
		params = flowStep2.getParameters();
		assertNotNull(params);
		assertEquals(1, params.size());
		assertTrue(params.contains("param21"));

		assertNotNull(flowStep3);
		assertEquals(Flow.SUCCESS_STATUS, flowStep3.getStatus());
		assertEquals(1300000, flowStep3.getStartDate().longValue());
		assertEquals(1500000, flowStep3.getEndDate().longValue());
		params = flowStep3.getParameters();
		assertNotNull(params);
		assertEquals(1, params.size());
		assertTrue(params.contains("param31"));

		assertNotNull(flowStep4);
		assertEquals(Flow.SUCCESS_STATUS, flowStep4.getStatus());
		assertEquals(1400000, flowStep4.getStartDate().longValue());
		assertEquals(1600000, flowStep4.getEndDate().longValue());
		params = flowStep4.getParameters();
		assertNotNull(params);
		assertEquals(1, params.size());
		assertTrue(params.contains("param41"));

		// cleanup
		this.removeStep("AAAA", "0001", "interface1", "service1",
				"endpoint1");
		this.removeStep("AAAA", "0002", "interface2", "service2",
				"endpoint2");
		this.removeStep("AAAA", "0003", "interface3", "service3",
				"endpoint3");
		this.removeStep("AAAA", "0004", "interface4", "service4",
				"endpoint4");
		this.remove("AAAA");

	}

	@Before
	public void populateRef() {
		createGFRef();
		createGRDRRef();
	}

	private FlowRef createGFRef() {
		final FlowRef f = new FlowRef();
		f.setType(GF_TYPE);
		f.setCreationDate(new Date());
		f.setName("GF");

		flowRefDAO.save(f);

		// --- steps
		FlowStepRef fsr;

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface1");
		fsr.setServiceName("service1");
		fsr.setFlowStartStep(true);
		fsr.setFlowEndStep(true);
		fsr.setName("Réception");
		fsr.setSuccessMessage("");
		// --- params
		final List<StepParameter> paramNames = new ArrayList<StepParameter>();
		paramNames.add(new StepParameter("Siret", false));
		paramNames.add(new StepParameter("Service", false));
		paramNames.add(new StepParameter("Guichet", false));
		paramNames.add(new StepParameter("N° Dossier", false));
		fsr.setParameterNames(paramNames);
		// addErrorMessage(fsr, 1, "Requête invalide: xxx");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface11");
		fsr.setServiceName("service11");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Validation");
		fsr.setSuccessMessage("Requête valide");
		addErrorMessage(fsr, 1, "Requête invalide: $ErrorMessage");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface12");
		fsr.setServiceName("service12");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Récupération PJs");
		fsr
				.setSuccessMessage("Toutes les pièces jointes ont été récupérées : $AttachmentList");
		addErrorMessage(fsr, 1, "Pièce(s) jointe(s) manquante(s)");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface111");
		fsr.setServiceName("service111");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Interrogation UDDI");
		fsr.setSuccessMessage("Coordonnées $Connecteur récupérées");
		addErrorMessage(fsr, 1,
				"Erreur lors de l'interrogation UDDI : $ErrorMessage");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface121");
		fsr.setServiceName("service121");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Envoi");
		fsr.setSuccessMessage("Télédossier Transmis");
		addErrorMessage(fsr, 1,
				"Erreur lors de l'envoi du télédossier : $ErrorMessage");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface122");
		fsr.setServiceName("service122");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Acquittement");
		fsr.setSuccessMessage("Acquittement Transmis");
		addErrorMessage(fsr, 1,
				"Erreur de l'envoi de l'acquittement : $ErrorMessage");
		flowStepRefDAO.save(fsr);

		getHibernateSession().flush();
		return f;
	}

	private FlowRef createGRDRRef() {
		final FlowRef f = new FlowRef();
		f.setType(GRDR_TYPE);
		f.setCreationDate(new Date());
		f.setName("GRDR");

		flowRefDAO.save(f);

		// --- steps
		FlowStepRef fsr;

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface1");
		fsr.setServiceName("service1");
		fsr.setFlowStartStep(true);
		fsr.setFlowEndStep(true);
		fsr.setName("R�ception");
		fsr.setSuccessMessage("");
		// --- params
		final List<StepParameter> paramNames = new ArrayList<StepParameter>();
		paramNames.add(new StepParameter("Siret", false));
		paramNames.add(new StepParameter("Service", false));
		paramNames.add(new StepParameter("Guichet", false));
		fsr.setParameterNames(paramNames);
		// addErrorMessage(fsr, 1, "Requête invalide: xxx");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface2");
		fsr.setServiceName("service2");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Validation");
		fsr.setSuccessMessage("Requête valide");
		addErrorMessage(fsr, 1, "Requête invalide: $ErrorMessage");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface3");
		fsr.setServiceName("service3");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Mise à jour UDDI");
		fsr.setSuccessMessage("Mise à jour effectuée");
		addErrorMessage(fsr, 1,
				"Erreur lors de la mise à jour de l'UDDI : $ErrorMessage");
		flowStepRefDAO.save(fsr);

		fsr = new FlowStepRef();
		fsr.setFlowref(f);
		fsr.setInterfaceName("interface4");
		fsr.setServiceName("service4");
		fsr.setFlowStartStep(false);
		fsr.setFlowEndStep(false);
		fsr.setName("Acquittement");
		fsr.setSuccessMessage("Acquittement Transmis");
		addErrorMessage(fsr, 1,
				"Erreur de l'envoi de l'acquittement : $ErrorMessage");
		flowStepRefDAO.save(fsr);
		getHibernateSession().flush();
		return f;
	}

	private FlowStepErrorRef addErrorMessage(final FlowStepRef fsr,
			final int code, final String message) {
		if (fsr.getErrorMessages() == null) {
			fsr.setErrorMessages(new HashMap<Integer, FlowStepErrorRef>(1));
		}
		final FlowStepErrorRef fser = new FlowStepErrorRef();
		fser.setFlowstepref(fsr);
		fser.setErrorCode(code);
		fser.setMessage(message);
		fsr.getErrorMessages().put(code, fser);
		flowStepErrorRefDAO.save(fser);
		return fser;
	}
	
	public Flow load(final String id) {
		final Flow flow = flowDAO.loadByPetalsId(id);
		if (flow != null) {
			this.updateFlowStatusAndDates(flow);
		}
		return flow;
	}
	
	/**
	 * Flow status is calculated at runtime because it could change when the
	 * corresponding flow ref is defined
	 * 
	 * @param idpetals
	 * @return
	 */
	private void updateFlowStatusAndDates(final Flow flow) {
		// Try to find a flow step ref defined as the end of the flow
		final FlowStepRef startStepRef = flowStepRefDAO
				.loadEndStepByFlowType(flow.getType());
		if (startStepRef != null) {
			// The flow status is equal to this step status
			// Load the dynamic flow step corresponding to this step service
			// name and interface name
			final List<FlowStep> flowSteps = flowStepDAO
					.loadByFlowIdAndMeProps(flow.getIdpetals(), startStepRef
							.getInterfaceName(), startStepRef.getServiceName());
			if (flowSteps != null && flowSteps.size() == 1) {
				flow.setStatus(flowSteps.get(0).getStatus());
				// Date endDate = new Date(flowSteps.get(0).getEndDate());
				flow.setEndDate(flowSteps.get(0).getEndDate());
			}
		}
		// Try to find a flow step ref defined as the start of the flow
		final FlowStepRef endStepRef = flowStepRefDAO
				.loadStartStepByFlowType(flow.getType());
		if (endStepRef != null) {
			// The flow status is equal to this step status
			// Load the dynamic flow step corresponding to this step service
			// name and interface name
			final List<FlowStep> flowSteps = flowStepDAO
					.loadByFlowIdAndMeProps(flow.getIdpetals(), endStepRef
							.getInterfaceName(), endStepRef.getServiceName());
			if (flowSteps != null && flowSteps.size() == 1) {
				// Date startDate = new Date(flowSteps.get(0).getStartDate());
				flow.setStartDate(flowSteps.get(0).getStartDate());
			}
		} else {
			flow.setStatus(-1);
		}
	}

}
