/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.model.parser;

import java.util.Iterator;
import java.util.List;

import org.eclipse.birt.report.model.api.ErrorDetail;
import org.eclipse.birt.report.model.api.FilterConditionHandle;
import org.eclipse.birt.report.model.api.GroupHandle;
import org.eclipse.birt.report.model.api.ListGroupHandle;
import org.eclipse.birt.report.model.api.ListHandle;
import org.eclipse.birt.report.model.api.SortKeyHandle;
import org.eclipse.birt.report.model.api.command.ContentException;
import org.eclipse.birt.report.model.api.elements.SemanticError;
import org.eclipse.birt.report.model.api.metadata.PropertyValueException;
import org.eclipse.birt.report.model.core.MultiElementSlot;
import org.eclipse.birt.report.model.elements.FreeForm;
import org.eclipse.birt.report.model.elements.GroupElement;
import org.eclipse.birt.report.model.elements.ListGroup;
import org.eclipse.birt.report.model.elements.ListItem;

/**
 * The test case of <code>ListItem</code> parser and writer.
 * <p>
 * <code>ListGroup</code> is also tested in this test case.
 * 
 * <p>
 * <table border="1" cellpadding="2" cellspacing="2" style="border-collapse:
 * collapse" bordercolor="#111111">
 * <th width="20%">Method</th>
 * <th width="40%">Test Case</th>
 * <th width="40%">Expected</th>
 * 
 * <tr>
 * <td>{@link #testParser()}</td>
 * <td>Test all slots of <code>ListItem</code> after parsing design file
 * </td>
 * <td>All slots are right</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td>Test all properties of Sorting after parsing design file</td>
 * <td>Sorting is not implemented</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td>Test all slots of <code>ListGroup</code> after parsing design file
 * </td>
 * <td>All properties are right</td>
 * </tr>
 * 
 * <tr>
 * <td>{@link #testWriter()}</td>
 * <td>Compare the written file with the golden file</td>
 * <td>Two files are same</td>
 * </tr>
 * 
 * <tr>
 * <td>{@link #testSemanticCheck()}</td>
 * <td>List is placed in header slot of table item</td>
 * <td>Context containment error found</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td>Filter has no column, operator, and filter expression.</td>
 * <td>Three value required error found</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td>List has no data set in the List/Table container of any level.</td>
 * <td>Missing Data set error found</td>
 * </tr>
 * 
 * <tr>
 * <td>{@link #testGroupNameSemanticCheck()}</td>
 * <td>All the groups names must be unique if the groups share a given named
 * data set.</td>
 * <td>Errors are found.</td>
 * </tr>
 * </table>
 * 
 * 
 * @see ListItem
 */

public class ListItemParseTest extends ParserTestCase
{

	String fileName = "ListItemParseTest.xml"; //$NON-NLS-1$
	String outFileName = "ListItemParseTest_out.xml"; //$NON-NLS-1$
	String goldenFileName = "ListItemParseTest_golden.xml"; //$NON-NLS-1$
	String semanticCheckFileName = "ListItemParseTest_1.xml"; //$NON-NLS-1$

	/*
	 * @see BaseTestCase#setUp()
	 */

	protected void setUp( ) throws Exception
	{
		super.setUp( );
		openDesign( fileName );
	}

	/**
	 * Test the slots of List item.
	 * 
	 * @throws Exception
	 *             if any exception
	 */
	public void testParser( ) throws Exception
	{

		ListItem list = (ListItem) design.findElement( "My List" ); //$NON-NLS-1$
		assertNotNull( list );

		ListHandle listHandle = list.handle( design );
		assertEquals( "my list on create", listHandle.getOnCreate( ) ); //$NON-NLS-1$
		assertEquals( "my list on prepare", listHandle.getOnPrepare( ) ); //$NON-NLS-1$
		assertEquals( "my list on render", listHandle.getOnRender( ) ); //$NON-NLS-1$
		assertEquals( "my list on page break", listHandle.getOnPageBreak( ) ); //$NON-NLS-1$

		assertEquals( 120, listHandle.getPageBreakInterval( ) );

		// test sorting

		Iterator sortKeys = listHandle.sortsIterator( );

		SortKeyHandle sortKeyHandle = (SortKeyHandle) sortKeys.next( );
		assertEquals( "age", sortKeyHandle.getKey( ) ); //$NON-NLS-1$
		assertEquals( "asc", sortKeyHandle.getDirection( ) ); //$NON-NLS-1$

		sortKeyHandle = (SortKeyHandle) sortKeys.next( );

		assertEquals( "grade", sortKeyHandle.getKey( ) ); //$NON-NLS-1$
		assertEquals( "desc", sortKeyHandle.getDirection( ) ); //$NON-NLS-1$

		assertNull( sortKeys.next( ) );

		// test filter

		Iterator filters = listHandle.filtersIterator( );
		FilterConditionHandle filterHandle = (FilterConditionHandle) filters
				.next( );

		assertEquals( "lt", filterHandle.getOperator( ) ); //$NON-NLS-1$
		assertEquals( "filter expression", filterHandle.getExpr( ) ); //$NON-NLS-1$
		assertEquals( "value1 expression", filterHandle.getValue1( ) ); //$NON-NLS-1$
		assertEquals( "value2 expression", filterHandle.getValue2( ) ); //$NON-NLS-1$

		// header slot

		MultiElementSlot header = (MultiElementSlot) list
				.getSlot( ListItem.HEADER_SLOT );
		FreeForm form = (FreeForm) header.getContent( 0 );
		assertEquals( "Header Section", form.getStringProperty( design, //$NON-NLS-1$
				FreeForm.COMMENTS_PROP ) );

		// detail slot

		MultiElementSlot detail = (MultiElementSlot) list
				.getSlot( ListItem.DETAIL_SLOT );
		form = (FreeForm) detail.getContent( 0 );
		assertEquals( "Detail Section", form.getStringProperty( design, //$NON-NLS-1$
				FreeForm.COMMENTS_PROP ) );

		// header slot

		MultiElementSlot footer = (MultiElementSlot) list
				.getSlot( ListItem.FOOTER_SLOT );
		form = (FreeForm) footer.getContent( 0 );
		assertEquals( "Footer Section", form.getStringProperty( design, //$NON-NLS-1$
				FreeForm.COMMENTS_PROP ) );

		// group slot

		MultiElementSlot groupSlot = (MultiElementSlot) list
				.getSlot( ListItem.GROUP_SLOT );
		ListGroup group = (ListGroup) groupSlot.getContent( 0 );

		// group filter

		ListGroupHandle groupHandle = (ListGroupHandle) group
				.getHandle( design );

		assertEquals( "2005/05/20", groupHandle.getGroupStart( ) ); //$NON-NLS-1$
		assertEquals( "2005 statistics", groupHandle.getTocExpression( ) ); //$NON-NLS-1$
		assertTrue( groupHandle.hideDetail( ) );

		filters = groupHandle.filtersIterator( );

		filterHandle = (FilterConditionHandle) filters.next( );

		assertEquals( "lt", filterHandle.getOperator( ) ); //$NON-NLS-1$
		assertEquals( "filter expression", filterHandle.getExpr( ) ); //$NON-NLS-1$
		assertEquals( "value1 expression", filterHandle.getValue1( ) ); //$NON-NLS-1$
		assertEquals( "value2 expression", filterHandle.getValue2( ) ); //$NON-NLS-1$

		// group header

		header = (MultiElementSlot) group.getSlot( ListGroup.HEADER_SLOT );
		form = (FreeForm) header.getContent( 0 );
		assertEquals( "Group Header Section", form.getStringProperty( design, //$NON-NLS-1$
				FreeForm.COMMENTS_PROP ) );

		// group footer

		footer = (MultiElementSlot) group.getSlot( ListGroup.FOOTER_SLOT );
		form = (FreeForm) footer.getContent( 0 );
		assertEquals( "Group Footer Section", form.getStringProperty( design, //$NON-NLS-1$
				FreeForm.COMMENTS_PROP ) );

		assertEquals( "week", groupHandle.getInterval( ) ); //$NON-NLS-1$
		assertTrue( 3.0 == groupHandle.getIntervalRange( ) ); //$NON-NLS-1$
		assertEquals( "desc", groupHandle.getSortDirection( ) ); //$NON-NLS-1$
		assertEquals( "complex-sort", groupHandle.getSortType( ) ); //$NON-NLS-1$
		assertEquals( "[Country]", groupHandle.getKeyExpr( ) ); //$NON-NLS-1$
		assertEquals( "group test", groupHandle.getName( ) ); //$NON-NLS-1$
		// assertEquals( "create", groupHandle.getOnCreate( ) ); //$NON-NLS-1$
		assertEquals( "prepare", groupHandle.getOnPrepare( ) ); //$NON-NLS-1$
		// assertEquals( "render", groupHandle.getOnRender( ) ); //$NON-NLS-1$
		assertEquals( "page break", groupHandle.getOnPageBreak( ) ); //$NON-NLS-1$

		// check sort under group.

		sortKeys = groupHandle.sortsIterator( );

		sortKeyHandle = (SortKeyHandle) sortKeys.next( );

		assertEquals( "name", sortKeyHandle.getKey( ) ); //$NON-NLS-1$
		assertEquals( "asc", sortKeyHandle.getDirection( ) ); //$NON-NLS-1$

		sortKeyHandle = (SortKeyHandle) sortKeys.next( );

		assertEquals( "birthday", sortKeyHandle.getKey( ) ); //$NON-NLS-1$
		assertEquals( "desc", sortKeyHandle.getDirection( ) ); //$NON-NLS-1$

	}

	/**
	 * Test writer.
	 * 
	 * @throws Exception
	 *             if any exception
	 */

	public void testWriter( ) throws Exception
	{
		ListHandle listHandle = (ListHandle) designHandle
				.findElement( "My List" ); //$NON-NLS-1$
		assertNotNull( listHandle );

		listHandle.setOnPrepare( "new prepare on the list" ); //$NON-NLS-1$
		listHandle.setOnCreate( "new create on the list" ); //$NON-NLS-1$
		listHandle.setOnRender( null ); 
		listHandle.setPageBreakInterval( 100 );
		listHandle.setOnPageBreak( "new list page break" );//$NON-NLS-1$

		GroupHandle groupHandle = (GroupHandle) listHandle.getGroups( ).get( 0 );
		groupHandle.setGroupStart( "2006/01/01" ); //$NON-NLS-1$
		groupHandle.setTocExpression( "toc1" ); //$NON-NLS-1$
		groupHandle.setSortType( "none" ); //$NON-NLS-1$
		groupHandle.setOnPageBreak( "new page break" );//$NON-NLS-1$

		saveAs( outFileName );
		assertTrue( compareTextFile( goldenFileName, outFileName ) );
	}

	/**
	 * Test semantic check.
	 * 
	 * @throws Exception
	 * 
	 */

	public void testSemanticCheck( ) throws Exception
	{
		openDesign( semanticCheckFileName );

		List errors = design.getErrorList( );

		int i = 0;

		assertEquals( 4, errors.size( ) );

		ErrorDetail error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "My First Table", error.getElement( ).getName( ) ); //$NON-NLS-1$
		assertEquals(
				ContentException.DESIGN_EXCEPTION_INVALID_CONTEXT_CONTAINMENT,
				error.getErrorCode( ) );

		error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "My First List", error.getElement( ).getName( ) ); //$NON-NLS-1$
		assertEquals( PropertyValueException.DESIGN_EXCEPTION_VALUE_REQUIRED,
				error.getErrorCode( ) );

		error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "Second table", error.getElement( ).getName( ) ); //$NON-NLS-1$
		assertEquals( SemanticError.DESIGN_EXCEPTION_MISSING_DATA_SET, error
				.getErrorCode( ) );

		error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "Second inner list", error.getElement( ).getName( ) ); //$NON-NLS-1$
		assertEquals( SemanticError.DESIGN_EXCEPTION_MISSING_DATA_SET, error
				.getErrorCode( ) );
	}

	/**
	 * Test semantic check.
	 * 
	 * @throws Exception
	 * 
	 */

	public void testGroupNameSemanticCheck( ) throws Exception
	{
		openDesign( "ListItemParseTest_2.xml" ); //$NON-NLS-1$

		List errors = design.getErrorList( );

		int i = 0;
		this.printSemanticErrors( );
		assertEquals( 3, errors.size( ) );

		ErrorDetail error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "group 2", //$NON-NLS-1$ 
				error.getElement( ).getLocalProperty( design,
						GroupElement.GROUP_NAME_PROP ) );
		assertEquals( PropertyValueException.DESIGN_EXCEPTION_VALUE_REQUIRED,
				error.getErrorCode( ) );

		error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "group 5", //$NON-NLS-1$ 
				error.getElement( ).getLocalProperty( design,
						GroupElement.GROUP_NAME_PROP ) );
		assertEquals( PropertyValueException.DESIGN_EXCEPTION_VALUE_REQUIRED,
				error.getErrorCode( ) );

		error = ( (ErrorDetail) errors.get( i++ ) );
		assertEquals( "group 4", //$NON-NLS-1$ 
				error.getElement( ).getLocalProperty( design,
						GroupElement.GROUP_NAME_PROP ) );
		assertEquals( PropertyValueException.DESIGN_EXCEPTION_VALUE_REQUIRED,
				error.getErrorCode( ) );

	}
}