/**
 *  Copyright (C) 2010 by Mar'yan Rachynskyy
 *  mrach@users.sourceforge.net
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.sf.linuxorg.pcal.engine;

import static org.junit.Assert.*;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Set;
import java.util.Vector;

import javax.xml.parsers.ParserConfigurationException;

import net.sf.linuxorg.pcal.PCalDayInfo;
import net.sf.linuxorg.pcal.PCalPeriodInfo;
import net.sf.linuxorg.pcal.engine.EnginePreferences;
import net.sf.linuxorg.pcal.engine.Engine.PasswordRequiredException;

import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;

/**
 * @author Mar'yan Rachynskyy
 * 
 */
public class EngineTest {

	private Engine engine;
	private GregorianCalendar calendar;

	private Date bbtDates[]; 
	private int bbtValues[];
	private String intValues[];
	
	private static final String [] DEFAULT_SYMPTHOMS_LIST = {"Cervical Mucus"}; //$NON-NLS-1$
	private static final String [][] DEFAULT_SYMPTHOMS_LIST_LEVELS = {{"Dry", "Neutral", "Wet", "Very Wet"}}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
	private final String TEST_SYMPTHOM_KEY = "SYMPTHOM_TEST1";	 //$NON-NLS-1$
	private final Vector<String> TEST_SYMPTHOM_VALUES = new Vector<String>(); 
	private final String[] TEST_SYMPTHOM_VALUE_STRINGS = {"VALUE1", "VALUE2"}; //$NON-NLS-1$ //$NON-NLS-2$

	private final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd"); //$NON-NLS-1$

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		engine = new Engine();
		calendar = new GregorianCalendar();

		// Record some sample menstruation dates
		calendar.set(2007, 9, 1);
		engine.addStartDate(calendar.getTime());
		calendar.set(2007, 9, 26);
		engine.addStartDate(calendar.getTime());
		calendar.set(2007, 10, 20);
		engine.addStartDate(calendar.getTime());
		calendar.set(2007, 11, 15);
		engine.addStartDate(calendar.getTime());
		calendar.set(2008, 0, 9);
		engine.addStartDate(calendar.getTime());

		engine.setDateNote(calendar.getTime(), "Test Note"); //$NON-NLS-1$

		EnginePreferences prefs = engine.getEnginePreferences();
		engine.setEnginePreferences(prefs);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getDayInfo(java.util.Date)}.
	 */
	@Test
	public void testGetDayInfo() {
		PCalDayInfo dayInfo;

		// test prehistoric dates edge case
		calendar.set(1980, 9, 26);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertNull(dayInfo);

		// test day 1 combinations
		// recorded day 0
		calendar.set(2007, 9, 26);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 0);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// estimated day 0
		calendar.set(2008, 1, 3);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 0);
		assertTrue(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// test fertile days combinations
		calendar.set(2007, 9, 12);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 11);
		assertFalse(dayInfo.estimate);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		calendar.set(2008, 0, 19);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 10);
		assertTrue(dayInfo.estimate);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// test non-fertile days combinations
		calendar.set(2007, 10, 25);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 5);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		calendar.set(2008, 0, 11);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 2);
		assertTrue(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// test pregnancy days combinations
		calendar.set(2008, 6, 2);
		Date date = calendar.getTime();
		engine.addPregnancyDate(date);

		calendar.set(2009, 3, 6);

		// estimated pregnancy date
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 278);
		assertTrue(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertTrue(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// estimated birth date
		calendar.set(2009, 3, 8);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 0);
		assertTrue(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.birth);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		engine.addBirthDate(calendar.getTime());

		// recorded birth
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 0);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.birth);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// recorded pregnancy
		calendar.set(2009, 3, 6);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 278);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertTrue(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// test the interrupted pregnancy functionality
		calendar.set(2009, 3, 8);
		engine.removeDateRecord(calendar.getTime());

		calendar.set(2009, 3, 6);
		engine.addPregnancyInterruptDate(calendar.getTime());

		// interruption date
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 0);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertTrue(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// after interruption
		calendar.set(2009, 3, 7);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, -1);
		assertTrue(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// before interruption
		calendar.set(2009, 3, 5);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 277);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.fertile);
		assertTrue(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.ovulation);
		assertFalse(dayInfo.unknown);

		// test the empty dataset case
		engine.newFile();
		assertNull(engine.getDayInfo(calendar.getTime()));

		calendar.set(2007, 9, 1);
		engine.addStartDate(calendar.getTime());
		calendar.set(2007, 9, 5);
		assertTrue(engine.getDayInfo(calendar.getTime()).unknown);
		calendar.set(2007, 10, 10);
		assertNull(engine.getDayInfo(calendar.getTime()));

	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getDayInfo(java.util.Date)}.
	 * Check the ovulation records functionality
	 */
	@Test
	public void testGetDayInfoWithOvulations() {
		PCalDayInfo dayInfo; 
			
		// set the ovulation for the past period
		calendar.set(2007, 9, 14);
		Date ovulationDate = calendar.getTime();

		engine.addOvulationDate(ovulationDate);
		
		// ovulation itself
		dayInfo = engine.getDayInfo(ovulationDate);
		assertEquals(dayInfo.day_num, 13);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertTrue(dayInfo.ovulation);
		

		// next day after ovulation
		calendar.set(2007, 9, 15);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 14);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// 3 days before ovulation
		calendar.set(2007, 9, 11);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 10);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// the first fertile day
		calendar.set(2007, 9, 9);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 8);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// the last non-fertile day
		calendar.set(2007, 9, 8);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 7);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);


		// test the ovulation prediction staff
		calendar.set(2008, 0, 22);
		ovulationDate = calendar.getTime();
		engine.addOvulationDate(ovulationDate);

		dayInfo = engine.getDayInfo(ovulationDate);
		assertEquals(dayInfo.day_num, 13);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertTrue(dayInfo.ovulation);

		// next day after ovulation
		calendar.set(2008, 0, 23);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 14);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// last day of the cycle
		calendar.set(2008, 1, 2);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 24);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// first day of the next cycle
		calendar.set(2008, 1, 3);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 0);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertTrue(dayInfo.badFeel);
		assertTrue(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);


		// 3 days before ovulation
		calendar.set(2008, 0, 19);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 10);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// the first fertile day
		calendar.set(2008, 0, 17);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 8);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// the last non-fertile day
		calendar.set(2008, 0, 16);
		dayInfo = engine.getDayInfo(calendar.getTime());
		assertEquals(dayInfo.day_num, 7);
		assertFalse(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertFalse(dayInfo.ovulation);

		// test the empty dataset case
		engine.newFile();

		// test day 1 combinations
		// recorded day 0
		calendar.set(2007, 9, 26);
		ovulationDate = calendar.getTime();
		engine.addOvulationDate(ovulationDate);
		dayInfo = engine.getDayInfo(ovulationDate);
		assertEquals(dayInfo.day_num, -1);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertTrue(dayInfo.ovulation);

		// ovulation within a regular cycle
		calendar.set(2007, 9, 6);
		Date mensDate = calendar.getTime();
		engine.addStartDate(mensDate);
		dayInfo = engine.getDayInfo(ovulationDate);
		assertEquals(dayInfo.day_num, 20);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertTrue(dayInfo.ovulation);

		// ovulation beyond a regular cycle
		engine.removeDateRecord(mensDate);
		calendar.set(2007, 7, 6);
		engine.addStartDate(calendar.getTime());
		dayInfo = engine.getDayInfo(ovulationDate);
		assertEquals(dayInfo.day_num, -1);
		assertTrue(dayInfo.fertile);
		assertFalse(dayInfo.pregnancy);
		assertFalse(dayInfo.birth);
		assertFalse(dayInfo.pregnancy_interruption);
		assertFalse(dayInfo.badFeel);
		assertFalse(dayInfo.estimate);
		assertTrue(dayInfo.ovulation);

	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#addStartDate(java.util.Date)}.
	 */
	@Test
	public void testAddStartDate() {
		calendar.set(2008, 1, 2);
		Date date = calendar.getTime();
		engine.addStartDate(date);
		assertTrue(engine.getDayInfo(date).day_num == 0);
		assertFalse(engine.getDayInfo(date).pregnancy);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#addPregnancyDate(java.util.Date)}
	 * .
	 */
	@Test
	public void testAddPregnancyDate() {
		calendar.set(2008, 6, 2);
		Date date = calendar.getTime();
		engine.addPregnancyDate(date);
		assertTrue(engine.getDayInfo(date).day_num == 0);
		assertTrue(engine.getDayInfo(date).pregnancy);
		calendar.set(2009, 3, 8);
		date = calendar.getTime();
		assertTrue(engine.getDayInfo(date).birth);
		assertTrue(engine.getDayInfo(date).estimate);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#addBirthDate(java.util.Date)}.
	 */
	@Test
	public void testAddBirthDate() {
		calendar.set(2008, 6, 2);
		Date date = calendar.getTime();
		engine.addPregnancyDate(date);
		assertTrue(engine.getDayInfo(date).day_num == 0);
		assertTrue(engine.getDayInfo(date).pregnancy);
		calendar.set(2009, 3, 1);
		date = calendar.getTime();
		engine.addBirthDate(date);
		assertTrue(engine.getDayInfo(date).birth);
		assertFalse(engine.getDayInfo(date).estimate);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#removeDateRecord(java.util.Date)}
	 * .
	 */
	@Test
	public void testRemoveDateRecord() {
		calendar.set(2008, 1, 2);
		Date date = calendar.getTime();
		engine.addStartDate(date);
		engine.removeDateRecord(date);
		assertTrue(engine.getDayInfo(date).estimate);
	}

	/**
	 * Test method for {@link net.sf.linuxorg.pcal.engine.Engine#newFile()}.
	 */
	@Test
	public void testNewFile() {
		engine.newFile();
		assertEquals(engine.getPeriodsCount(), 0);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getPeriodsStats()}.
	 */
	@Test
	public void testGetPeriodsStats() {
		Vector<PCalPeriodInfo> stats = engine.getPeriodsStats();
		assertEquals(stats.size(), 4);
		assertEquals(stats.get(0).length, 25);
		assertEquals(stats.get(1).length, 25);
		assertEquals(stats.get(2).length, 25);
		assertEquals(stats.get(3).length, 25);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getLastMenstruationDate()}.
	 */
	@Test
	public void testGetLastMenstruationDate() {
		calendar.set(2008, 0, 9);
		Date date = engine.getLastMenstruationDate();
		assertEquals(date.getTime(), calendar.getTimeInMillis());
		engine.newFile();
		assertNull(engine.getLastMenstruationDate());
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getDateNote(java.util.Date)}.
	 */
	@Test
	public void testGetDateNote() {
		calendar.set(2008, 4, 9);
		Date date = calendar.getTime();
		engine.setDateNote(date, "Test Notes"); //$NON-NLS-1$
		assertEquals(engine.getDateNote(date), "Test Notes"); //$NON-NLS-1$
		//test if engine overwrites the same note nicely
		engine.setDateNote(date, "Test Notes"); //$NON-NLS-1$
		assertEquals(engine.getDateNote(date), "Test Notes"); //$NON-NLS-1$
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#existsDateNote(java.util.Date)}
	 * .
	 */
	@Test
	public void testExistsDateNote() {
		calendar.set(2008, 4, 9);
		Date date = calendar.getTime();
		engine.setDateNote(date, "Test Notes"); //$NON-NLS-1$
		assertTrue(engine.existsDateNote(date));
	}

	/**
	 * Test method for {@link net.sf.linuxorg.pcal.engine.Engine#getNoteDates()}
	 * .
	 */
	@Test
	public void testGetNoteDates() {
		calendar.set(2008, 4, 9);
		Date date1 = calendar.getTime();
		engine.setDateNote(date1, "Test Notes"); //$NON-NLS-1$
		calendar.set(2008, 4, 11);
		Date date2 = calendar.getTime();
		engine.setDateNote(date2, "Test Notes2"); //$NON-NLS-1$
		Set<Date> dates = engine.getNoteDates();
		assertEquals(dates.size(), 3);
		assertTrue(dates.contains(date1));
		assertTrue(dates.contains(date2));
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#removeDateNote(java.util.Date)}
	 * .
	 */
	@Test
	public void testRemoveDateNote() {
		calendar.set(2008, 4, 9);
		Date date = calendar.getTime();
		engine.setDateNote(date, "Test Notes"); //$NON-NLS-1$
		assertTrue(engine.existsDateNote(date));
		engine.removeDateNote(date);
		assertFalse(engine.existsDateNote(date));
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#dateDiff(java.util.Date, java.util.Date)}
	 * .
	 */
	@Test
	public void testDateDiff() {
		calendar.set(2008, 4, 9);
		Date date1 = calendar.getTime();
		calendar.set(2011, 0, 21);
		Date date2 = calendar.getTime();
		assertEquals(Engine.dateDiff(date2, date1), 987);
		date1 = calendar.getTime();
		assertEquals(Engine.dateDiff(date2, date1), 0);
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getPredictedBirthDay(java.util.Date, int)}
	 * .
	 */
	@Test
	public void testGetPredictedBirthDay() {
		calendar.set(2008, 6, 2);
		Date date = calendar.getTime();
		engine.addPregnancyDate(date);
		calendar.set(2009, 3, 8);
		assertEquals(calendar.getTimeInMillis(), engine.getPredictedBirthDay(
				date, 0).getTime());
	}

	/**
	 * Test method for {@link net.sf.linuxorg.pcal.engine.Engine#isModified()}.
	 */
	@Test
	public void testIsModified() {
		assertTrue(engine.isModified());
		engine.newFile();
		assertFalse(engine.isModified());
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getCalMethodAccuracy()}.
	 */
	@Test
	public void testGetCalMethodAccuracy() {
		assertEquals(engine.getCalMethodAccuracy(), 2);
		calendar.set(2008, 1, 3);
		engine.addStartDate(calendar.getTime());
		assertEquals(engine.getCalMethodAccuracy(), 1);
	}

	/**
	 * Test method for {@link net.sf.linuxorg.pcal.engine.Engine#getAvgLength()}
	 * .
	 */
	@Test
	public void testGetAvgLength() {
		assertEquals(engine.getAvgLength(), 25);
		calendar.set(2008, 1, 8);
		engine.addStartDate(calendar.getTime());
		assertEquals(engine.getAvgLength(), 26);
		;
	}

	/**
	 * Test method for {@link net.sf.linuxorg.pcal.engine.Engine#getMaxLength()}
	 * .
	 */
	@Test
	public void testGetMaxLength() {
		assertEquals(engine.getMaxLength(), 25);
		calendar.set(2008, 1, 8);
		engine.addStartDate(calendar.getTime());
		assertEquals(engine.getMaxLength(), 30);
		;
	}

	/**
	 * Test method for {@link net.sf.linuxorg.pcal.engine.Engine#getMinLength()}
	 * .
	 */
	@Test
	public void testGetMinLength() {
		assertEquals(engine.getMinLength(), 25);
		calendar.set(2008, 0, 31);
		engine.addStartDate(calendar.getTime());
		assertEquals(engine.getMinLength(), 25);
		;
	}

	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#getPeriodsCount()}.
	 */
	@Test
	public void testGetPeriodsCount() {
		assertEquals(engine.getPeriodsCount(), 4);
		calendar.set(2008, 1, 2);
		engine.addStartDate(calendar.getTime());
		assertEquals(engine.getPeriodsCount(), 5);
	}
	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#convertTemperatureScale()}.
	 */
	@Test
	public void testConvertTemperatureScale() {
		assertEquals(Engine.convertTemperatureScale(false, 300), 860);
		assertEquals(Engine.convertTemperatureScale(true, 1040), 400);		 
		assertEquals(Engine.convertTemperatureScale(true, Engine.convertTemperatureScale(false, 366)), 366);
	}
	/**
	 * Test method for
	 * {@link net.sf.linuxorg.pcal.engine.Engine#setEnginePreferences()}.
	 */
	@Test
	public void testSetEnginePreferences() {

		// here we really care about converting BBT between the Celsius and Fahrenheit
		Date[] dates = new Date[3];

		calendar.set(2009, 9, 1);
		dates[0] = calendar.getTime();
		calendar.set(2009, 9, 2);
		dates[1] = calendar.getTime();
		calendar.set(2009, 9, 3);
		dates[2] = calendar.getTime();

		int[] tCelsius = {350, 366, 371};

		for(int i=0;i<3;i++) {
			engine.addBBT(dates[i], tCelsius[i]);
			assertEquals(tCelsius[i], engine.getBBT(dates[i]));
		}
	}

	/**
	 * Test method for load and save
	 */
	@Test
	public void testLoadSave() {
		// plain files
		try {
			File file = File.createTempFile("LORG_TEST", ""); //$NON-NLS-1$ //$NON-NLS-2$

			assertNull(engine.getWorkFile());

			prepareDateRecords(); // set up the bbt and date integer records
			prepareBBTSympthoms();			

			engine.saveToFile(file);
			assertEquals(engine.getWorkFile(), file);

			engine.loadFromFile(file, null);
			assertEquals(engine.getWorkFile(), file);

			testDateRecords();
			testBBTSympthoms();

			testGetDayInfo();

			file.deleteOnExit();

		} catch (IOException e) {
			fail(e.getMessage());
		} catch (ParserConfigurationException e) {
			fail(e.getMessage());
		} catch (SAXException e) {
			fail(e.getMessage());
		} catch (PasswordRequiredException e) {
			fail(e.getMessage());
		}
	}

	private void prepareDateRecords() {
		String stringDates[] = {"2007/09/01", //$NON-NLS-1$
				"2007/10/03", //$NON-NLS-1$
				"2007/10/07", //$NON-NLS-1$
				"2007/10/09", //$NON-NLS-1$
		"2007/10/21"};  //$NON-NLS-1$

		bbtDates = new Date[5];

		for(int i = 0; i<bbtDates.length; i++) {
			try {
				bbtDates[i] = DATE_FORMAT.parse(stringDates[i]);
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}

		bbtValues = new int[] {366, 367, 369, 333, 0};
		intValues = new String[] {"4,1,56,3", //$NON-NLS-1$
				",,,", //$NON-NLS-1$
				",11,23,", //$NON-NLS-1$
				"1,2,3,4", //$NON-NLS-1$
		"44,1,2,5"}; //$NON-NLS-1$

		for(int i = 0; i< bbtDates.length; i++) {
			engine.addBBT(bbtDates[i], bbtValues[i]);
			engine.setDateIntegers(bbtDates[i], DateIntsContainer.parseFromStringFactory(intValues[i]));
		}

	}

	private void testDateRecords() {
		for(int i = 0; i< bbtDates.length; i++) {
			assertEquals(bbtValues[i], engine.getBBT(bbtDates[i]));
			assertEquals(intValues[i], engine.getDateIntegers(bbtDates[i]).toString());
		}		
	}

	private void prepareBBTSympthoms() {
		BBTSympthomsSetDefinition sympthoms = engine.getBBTSympthoms();
	
		// sligtly modify the default set
		TEST_SYMPTHOM_VALUES.clear();
		TEST_SYMPTHOM_VALUES.add(TEST_SYMPTHOM_VALUE_STRINGS[0]);
		TEST_SYMPTHOM_VALUES.add(TEST_SYMPTHOM_VALUE_STRINGS[1]);
		
		sympthoms.setSypmthomNameAndValues(1, TEST_SYMPTHOM_KEY, new Vector<String>(TEST_SYMPTHOM_VALUES));
		testBBTSympthoms();
	}

	private void testBBTSympthoms() {
		BBTSympthomsSetDefinition sympthoms = engine.getBBTSympthoms();

		String[] names = sympthoms.getSympthoms();
		assertEquals(names[0], DEFAULT_SYMPTHOMS_LIST[0]);
		assertEquals(names[1], TEST_SYMPTHOM_KEY);
		
		String[] valuesTest1 = sympthoms.getSympthomValues(0);
		String[] valuesTest2 = sympthoms.getSympthomValues(1);

		
		for(int i=0; i<DEFAULT_SYMPTHOMS_LIST_LEVELS[0].length; i++) {
			assertEquals(valuesTest1[i], DEFAULT_SYMPTHOMS_LIST_LEVELS[0][i]);
		}

		for(int i=0; i<TEST_SYMPTHOM_VALUE_STRINGS.length; i++) {
			assertEquals(valuesTest2[i], TEST_SYMPTHOM_VALUE_STRINGS[i]);
		}
		
		assertEquals(sympthoms.getSympthomName(200), ""); //$NON-NLS-1$
		assertNull(sympthoms.getSympthomValues(200));
		assertEquals(sympthoms.getSympthomValuesCount(0), 4);
		
		String tempName = sympthoms.getSympthomName(1);
		sympthoms.changeSympthomName(1,"testName"); //$NON-NLS-1$
		assertEquals(sympthoms.getSympthomName(1), "testName"); //$NON-NLS-1$
		sympthoms.changeSympthomName(1,tempName);
		
		String tempValue = sympthoms.getSympthomValue(1, 1);
		sympthoms.setSypmthomValue(1, 1, "test value"); //$NON-NLS-1$
		assertEquals(sympthoms.getSympthomValue(1, 1), "test value"); //$NON-NLS-1$
		sympthoms.setSypmthomValue(1, 1, tempValue);
		sympthoms.insertSypmthomValue(1, 1, "test value2"); //$NON-NLS-1$
		assertEquals(sympthoms.getSympthomValue(1, 1), "test value2"); //$NON-NLS-1$
		assertEquals(sympthoms.getSympthomValue(1, 2), tempValue);
		assertEquals(sympthoms.getSympthomValueIndex(1, tempValue), 2);
		sympthoms.getSympthomValuesVector(1).remove(1);
		assertEquals(sympthoms.getSympthomValue(1, 1), tempValue);
		assertEquals(sympthoms.getSympthomValueIndex(1, tempValue), 1);
		
	}

	/**
	 * Test method for load and save of the encrypted files
	 */
	@Test
	public void testEncryptedLoadSave() {
		// encrypted files
		final char password[] = {'g','g','g'};
		final char badPassword[] = {'b','b','b'};

		try {
			File file = File.createTempFile("LORG_TEST", ""); //$NON-NLS-1$ //$NON-NLS-2$

			engine.saveToFile(file, password);
			try {
				engine.loadFromFile(file, null);
				fail("PasswordRequiredException not thrown"); //$NON-NLS-1$
			} catch (PasswordRequiredException e) {
				// expected exception
			}

			try {
				engine.loadFromFile(file, badPassword);
				fail("SAXException for bad password not thrown"); //$NON-NLS-1$
			} catch (IOException e) {
				// expected exception
			} catch (PasswordRequiredException e) {
				fail(e.getMessage());
			}

			engine.loadFromFile(file, password);
			testGetDayInfo();

			file.deleteOnExit();

		} catch (IOException e) {
			fail(e.getMessage());
		} catch (SAXException e) {
			fail(e.getMessage());
		} catch (ParserConfigurationException e) {
			fail(e.getMessage());
		} catch (PasswordRequiredException e) {
			fail(e.getMessage());
		}
	}

	/**
	 * Test import/export
	 */
	@Test
	public void testImportExport() {
		try {
			File file = File.createTempFile("LORG_TEST", ""); //$NON-NLS-1$ //$NON-NLS-2$

			engine.exportToFile(file);

			engine.importFromFile(file);

			testGetDayInfo();

			file.deleteOnExit();

		} catch (IOException e) {
			fail(e.getMessage());
		} catch (ParseException e) {
			fail(e.getMessage());
		}
	}

	/**
	 * Test getDefault engine preferences
	 */
	@Test
	public void testGetDefaultPreferences() {
		EnginePreferences enginePreferences = engine.getDefaultPreferences();
		assertEquals(enginePreferences.bufferDays, 0);
		assertEquals(enginePreferences.badFeelDaysBefore, 0);
		assertEquals(enginePreferences.badFeelDaysAfter, 0);
		assertEquals(enginePreferences.regularMinLength, 24);
		assertEquals(enginePreferences.regularMaxLength, 35);

	}

	/**
	 * Test BBT ACD functionality
	 */
	@Test
	public void testBBTACD() {
		calendar.set(2007, 9, 1);
		Date date = calendar.getTime();

		engine.addBBT(date, 366);
		assertEquals(engine.getBBT(date), 366);
		engine.addBBT(date, 367);
		assertEquals(engine.getBBT(date), 367);
		engine.removeBBT(date);
		assertEquals(engine.getBBT(date), 0);

	}
	
	/**
	 * Test for get/set/remove date integers
	 */
	@Test
	public void testGetSetRemoveDateIntegers() {
		calendar.set(2007, 9, 1);
		engine.setDateInteger(calendar.getTime(), 0, 5);
		assertTrue(engine.getDateIntegers(calendar.getTime()).getIntValue(0) == 5);
		engine.removeDateIntegers(calendar.getTime());
		assertNull(engine.getDateIntegers(calendar.getTime()));
	}

}
