package gov.va.vinci.dart.biz;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import gov.va.vinci.dart.common.SingletonShim;
import gov.va.vinci.dart.common.exception.ValidationException;
import gov.va.vinci.dart.common.test.BusinessIntegrationTest;
import gov.va.vinci.dart.biz.OperationalStudy;
import gov.va.vinci.dart.biz.ResearchStudy;
import gov.va.vinci.dart.service.DartObjectFactory;

public class TestResearchStudy extends BusinessIntegrationTest {

	@BeforeTest
	public void setup() {
		SingletonShim.getBean(DartObjectFactory.class);
	}

	@Test
	public void testOne() throws Exception {
		Assert.assertNull(ResearchStudy.findById(0));
		
		try {
			ResearchStudy.create("short name", new Date(), new Date(), "Official Name - this is a test!", null);
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {
		}

		try {
			ResearchStudy.create("short name", new Date(), new Date(), "Official Name - this is a test!", "");
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {
		}
		try {
			ResearchStudy.create("short name", new Date(), new Date(), "Official Name - this is a test!", "123456789012345678901234567890123456789012345678901234567890");
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {
		}

		ResearchStudy study = ResearchStudy.create("short name", new Date(), new Date(), "Official Name - this is a test!", "DNS");
		Assert.assertNotNull(study);
		
		Assert.assertEquals(study.getName(), "short name");
		
		int newId = study.getId();
		
		ResearchStudy study2 = ResearchStudy.findById(study.getId());
		Assert.assertNotNull(study2);
		Assert.assertEquals(study2.getName(), "short name");

		// update the short name and official name property
		study2.modify("new short name", study2.getStartDate(), study2.getEndDate(), "new official name", "modifier");

		ResearchStudy study3 = ResearchStudy.findById(study.getId());
		Assert.assertNotNull(study3);
		Assert.assertEquals(study3.getName(), "new short name");
		Assert.assertEquals(study3.getOfficialName(), "new official name");

		ResearchStudy study4 = ResearchStudy.findByShortName("new short name");
		Assert.assertNotNull(study4);
		Assert.assertEquals(study4.getName(), "new short name");
		Assert.assertEquals(study4.getOfficialName(), "new official name");

		ResearchStudy study5 = ResearchStudy.findById(1);

		Assert.assertTrue(study.hashCode() > 0);
		Assert.assertTrue(study5.hashCode() > 0);
		Assert.assertNotEquals(study.hashCode(), study5.hashCode());
		
		Assert.assertTrue(study.equals(study));
		Assert.assertFalse(study.equals(null));
		Assert.assertFalse(study.equals(""));
		Assert.assertFalse(study.equals(study5));
	}
	

	@Test
	public void testTwo() throws Exception {
		ResearchStudy rs = ResearchStudy.findById(1);
		Assert.assertNotNull(rs);
		
		Assert.assertEquals(rs.hashCode(), 1);
		Assert.assertTrue(rs.equals(rs));
		Assert.assertFalse(rs.equals(null));
		
		OperationalStudy os = OperationalStudy.findById(1);
		Assert.assertFalse(rs.equals(os));
	}

	@Test
	public void testThree() throws Exception {
		ResearchStudy study = ResearchStudy.create("short name", new Date(), new Date(), "Official Name - this is a test!", "DNS");
		Assert.assertNotNull(study);
		
		Assert.assertEquals(study.getName(), "short name");
		Assert.assertTrue(study.getId() > 0);

		// name can be null or 0 length, but not more than 1024
		try {
			study.modify(longString(1030), study.getStartDate(), study.getEndDate(), study.getOfficialName(), study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		// official name cannot be null or 0 length, or more than 1024
		try {
			study.modify(study.getName(), study.getStartDate(), study.getEndDate(), null, study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		try {
			study.modify(study.getName(), study.getStartDate(), study.getEndDate(), "", study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}
		
		try {
			study.modify(study.getName(), study.getStartDate(), study.getEndDate(), longString(1030), study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		GregorianCalendar gc = new GregorianCalendar();
		gc.set(Calendar.YEAR, 1800);
				
		// start date can be null, but if present not before 1900
		try {
			study.modify(study.getName(), gc.getTime(), study.getEndDate(), study.getOfficialName(), study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		// end date can be null, but if present not before 1900
		try {
			study.modify(study.getName(), study.getStartDate(), gc.getTime(), study.getOfficialName(), study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		gc.set(Calendar.YEAR, 1980);
		Date dEnd = gc.getTime();
		gc.set(Calendar.YEAR, 1990);
		Date dStart = gc.getTime();
		
		// start date cannot be after end date
		try {
			study.modify(study.getName(), dStart, dEnd, study.getOfficialName(), study.getCreatedBy());
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		// updated by is required and cannot be less than 1 or more than 32
		try {
			study.modify(study.getName(), study.getStartDate(), study.getEndDate(), study.getOfficialName(), null);
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		try {
			study.modify(study.getName(), study.getStartDate(), study.getEndDate(), study.getOfficialName(), "");
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

		try {
			study.modify(study.getName(), study.getStartDate(), study.getEndDate(), study.getOfficialName(), longString(1030));
			Assert.fail("Expected ValidationException");
		} catch (ValidationException e) {}

	}

	@Test
	public void testFour() throws Exception {
		ResearchStudy study = ResearchStudy.create("short name", null, new Date(), "Official Name - this is a test!", "DNS");
		Assert.assertNotNull(study);
		
		Assert.assertEquals(study.getName(), "short name");
		Assert.assertTrue(study.getId() > 0);
		
		List<String> msgs = new ArrayList<String>();
		
		study.validate(msgs);
		Assert.assertTrue(msgs.size() > 0);
	}
	
	public static String longString(int length) {
		char[] data = new char[length];
		for (int i = 0; i < length; i++) {
			data[i] = 'a';
		}
		return new String(data);
	}
	
	/*
	 * int hashCode()
	 * boolean equals(Object obj)
	 */
}
