package com.tandbergtv.metadatamanager;

import static org.springframework.transaction.TransactionDefinition.PROPAGATION_REQUIRED;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.w3c.util.DateParser;
import org.w3c.util.InvalidDateException;

import com.tandbergtv.metadatamanager.exception.MetadataException;
import com.tandbergtv.metadatamanager.exception.SearchException;
import com.tandbergtv.metadatamanager.model.Asset;
import com.tandbergtv.metadatamanager.model.Field;
import com.tandbergtv.metadatamanager.model.Group;
import com.tandbergtv.metadatamanager.model.Item;
import com.tandbergtv.metadatamanager.model.Group.GroupType;
import com.tandbergtv.metadatamanager.model.Item.ItemType;
import com.tandbergtv.metadatamanager.specimpl.ttv.TTVId;

/**
 * Test cases to unit test metadata manager methods.
 * 
 * @author spuranik
 * 
 */
public class MetadataManagerUnitTest extends TestCase {

	private MetadataManagerDAO daoImpl;
	private PlatformTransactionManager txmgr;

	/*
	 * (non-Javadoc)
	 * 
	 * @see junit.framework.TestCase#setUp()
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();		
		ApplicationContext context = new ClassPathXmlApplicationContext(
				new String[] { "MetadataBeansContext.xml",
						"MetadataManagerDBContext.xml",
						"file:tests/DataSource_UnitTest.xml" });

		daoImpl = (MetadataManagerDAO) context.getBean("metadataManagerDAOImpl");
		txmgr = (PlatformTransactionManager) context
				.getBean("transactionManager");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see junit.framework.TestCase#tearDown()
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}

	/**
	 * tests the jigsaw date parser
	 */
	public void _testDate() {
		try {
			DateParser.parse("1997-07-16T19:20:30+05:00");
			DateParser.parse("1997-07-16T19:20:30Z");
			DateParser.parse("1997-07-16T19:20:30.222+05:00");
			DateParser.parse("1997-07-16T19:20:30.222");
			DateParser.parse("1997-07-16");
			DateParser.parse("1997-07-16T19:20:30");
			DateParser.parse("1997-07-16T19:20");
			DateParser.parse("1997-07-16T19:20+01:00");
		} catch (InvalidDateException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Creates a single asset in the db with the given id and version.
	 */
	public void testCreateSingleAsset() {
		try {
			Asset asset = createSingleAsset(0);
			TTVId id = daoImpl.saveAsset(asset);

			System.out.println("Created single asset with id: " + id.getId());
		} catch (MetadataException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Search for the package given its TTV identifier (with version)
	 */
	public void _testAssetSearchByTTVId() {

		TransactionStatus status = txmgr
				.getTransaction(new DefaultTransactionDefinition(
						PROPAGATION_REQUIRED));

		// look for specified version
		TTVId identifier = new TTVId(1L);

		try {
			System.out.println("Searching for asset with id: "
					+ identifier.getId());
			Asset asset = daoImpl.getAsset(identifier, true, true);
			assertEquals(identifier.getId(), asset.getTTVId().getId());

			for (Field f : asset.getFields()) {
				Object val = f.getTypedValue();
				assertNotNull(val);
				System.out.println("val == " + val);
			}
		} catch (SearchException e) {
			System.out.println("Search exception: " + e);
		}

		txmgr.commit(status);
	}

	/**
	 * Deletes an asset with the given ttv id
	 */
	public void _testDelete() {
		TTVId id = new TTVId(67);

		System.out.println("Deleting asset with id: " + id.getId());
		TransactionStatus status = txmgr
				.getTransaction(new DefaultTransactionDefinition(
						PROPAGATION_REQUIRED));

		try {
			daoImpl.delete(id.getAsset());
			System.out.println("Deleted  asset with id: " + id.getId());
		} catch (SearchException e) {
			e.printStackTrace();
		}
		txmgr.commit(status);
	}

	/**
	 * Updates an existing asset.
	 */
	public void _testUpdate() {
		TransactionStatus status = txmgr
				.getTransaction(new DefaultTransactionDefinition(
						PROPAGATION_REQUIRED));

		Asset oldAsset = null;
		TTVId id = new TTVId(5L);
		try {
			oldAsset = daoImpl.getAsset(id, true, true);
		} catch (SearchException e1) {
			e1.printStackTrace();
		}

		if (oldAsset != null) {
			List<Field> fldList = new ArrayList<Field>();
			fldList.add(createField("/tns:Fields/tns:UnitTest",
					"i got set by a unit test"));

			oldAsset.setFields(fldList);
			try {
				TTVId id1 = daoImpl.saveAsset(oldAsset);
				System.out.print("Updated Asset with TTVId: " + id1.getId());
			} catch (MetadataException e) {
				e.printStackTrace();
			}
		}
		txmgr.commit(status);
	}

	/**
	 * Updates an existing asset.
	 */
	public void _testUpdateWithBlankField() {
		TransactionStatus status = txmgr
				.getTransaction(new DefaultTransactionDefinition(
						PROPAGATION_REQUIRED));

		Asset oldAsset = null;
		TTVId id = new TTVId(5L);
		try {
			oldAsset = daoImpl.getAsset(id, true, true);
		} catch (SearchException e1) {
			e1.printStackTrace();
		}

		if (oldAsset != null) {
			String xpath = oldAsset.getFields().get(0).getTtvXPath();
			oldAsset.getFields().get(0).setValue("");
			System.out.println("Changing the value for " + xpath + " to blank");
			try {
				TTVId id1 = daoImpl.saveAsset(oldAsset);
				System.out.print("Updated Asset with TTVId: " + id1.getId());
			} catch (MetadataException e) {
				e.printStackTrace();
			}
		}
		txmgr.commit(status);
	}

	/**
	 * Creates a group asset and adds it.
	 */
	public void _testTreeAsset() {
		Asset groupAsset = createTreeAsset();
		try {
			TTVId id = daoImpl.saveAsset(groupAsset);
			System.out.print("Created group with TTVId: " + id.getId());
		} catch (MetadataException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Creates a group asset and adds it.
	 */
	public void _testTreeAssetWithBlankFields() {
		Asset groupAsset = createAssetWithBlankFields();
		try {
			TTVId id = daoImpl.saveAsset(groupAsset);
			System.out.print("Created group with TTVId: " + id.getId());
		} catch (MetadataException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Creates a single asset with no relations.
	 * 
	 * @return
	 */
	private Asset createSingleAsset(int id) {
		Group g = new Group();
		if (id > 0)
			g.setId(id);

		g.setType(GroupType.PACKAGE);

		Field fAssetName = new Field();
		fAssetName.setTtvXPath("/tns:Fields/tns:AssetName");
		fAssetName.setValue("Batman");
		ArrayList<Integer> indices = new ArrayList<Integer>();
		indices.add(1);
		indices.add(1);
		fAssetName.setIndices(indices);

		Field fAssetClass = new Field();
		fAssetClass.setTtvXPath("/tns:Fields/tns:AssetClass");
		fAssetClass.setValue("package1");
		fAssetClass.setIndices(indices);

		Field fIdentifier = new Field();
		fIdentifier.setTtvXPath("/tns:Fields/tns:Identifier/Id");
		fIdentifier.setValue("OutbreakWVC12242528x4802398pWMA129wmv");
		ArrayList<Integer> indicesThree = new ArrayList<Integer>();
		indicesThree.add(1);
		indicesThree.add(1);
		indicesThree.add(1);
		fIdentifier.setIndices(indicesThree);

		Field fProviderInfoIdentifier = new Field();
		fProviderInfoIdentifier
				.setTtvXPath("/tns:Fields/tns:ProviderInfo/tns:Identifier/Id");
		fProviderInfoIdentifier.setValue("NoEncode");
		ArrayList<Integer> indicesFour = new ArrayList<Integer>();
		indicesFour.add(1);
		indicesFour.add(1);
		indicesFour.add(1);
		indicesFour.add(1);
		fProviderInfoIdentifier.setIndices(indicesFour);

		g.addField(fAssetName);
		g.addField(fAssetClass);
		g.addField(fIdentifier);
		g.addField(fProviderInfoIdentifier);

		return g;
	}

	/**
	 * Creates a package which has title movie and preview assets.
	 * 
	 * @return
	 */
	private Asset createTreeAsset() {
		Group g = new Group();
		g.setType(GroupType.PACKAGE);

		g.addField(createField("/tns:Fields/tns:AssetName",
				"CaptainCorellisMandolinpackage"));
		g.addField(createField("/tns:Fields/tns:AssetClass", "package"));
		g.addField(createField("/tns:Fields/tns:Description/tns:Text",
				"Captain Corellis Mandolin asset package"));
		g.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"OutbreakWVC12242528x4802398pWMA129wmv"));
		g.addField(createField(
				"/tns:Fields/tns:ProviderInfo/tns:Identifier/tns:Id",
				"indemand.com"));
		g.addField(createField(
				"/tns:Fields/tns:ProviderInfo/tns:Identifier/tns:Name",
				"In Demand"));

		// Title
		Item it = new Item();
		it.setType(ItemType.TITLE);

		it.addField(createField("/tns:Fields/tns:AssetName",
				"Captain Corellis Mandolin title"));
		it.addField(createField("/tns:Fields/tns:AssetClass", "title"));
		it.addField(createField("/tns:Fields/tns:Description/tns:Text",
				"Captain Corellis Mandolin title asset"));
		it.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"UNVA2001081701003001"));
		it.addField(createField(
				"/tns:Fields/tns:BillingInfo/tns:SuggestedPrice/tns:Value",
				"3.95"));

		// Movie
		Item im = new Item();
		im.setType(ItemType.MOVIE);

		im.addField(createField("/tns:Fields/tns:AssetName",
				"Captain Corellis Mandolin feature"));
		im.addField(createField("/tns:Fields/tns:AssetClass", "movie"));
		im.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"UNVA2001081701003002"));
		im.addField(createField("/tns:Fields/tns:Content/tns:Locator/tns:Uri",
				"MandolinTR.mpg"));
		im.addField(createField(
				"/tns:Fields/tns:ProviderInfo/tns:Identifier/tns:Id",
				"indemand.com"));
		im.addField(createField(
				"/tns:Fields/tns:ProviderInfo/tns:Identifier/tns:Name",
				"In Demand"));
		im.addField(createField("/tns:Fields/tns:ProductInfo/tns:Name", "MOD"));

		// Preview
		Item ip = new Item();
		ip.setType(ItemType.PREVIEW);

		ip.addField(createField("/tns:Fields/tns:AssetName",
				"Captain Corellis Mandolin trailer"));
		ip.addField(createField("/tns:Fields/tns:AssetClass", "preview"));
		ip.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"UNVA2001081701003003"));
		ip.addField(createField("/tns:Fields/tns:Content/tns:Locator/tns:Uri",
				"Mandolin.mpg"));
		ip.addField(createField(
				"/tns:Fields/tns:ProviderInfo/tns:Identifier/tns:Id",
				"indemand.com"));
		ip.addField(createField(
				"/tns:Fields/tns:ProviderInfo/tns:Identifier/tns:Name",
				"In Demand"));

		g.addChild(it);
		g.addChild(im);
		g.addChild(ip);

		return g;
	}

	/**
	 * Creates a package which has title movie and preview assets.
	 * 
	 * @return
	 */
	private Asset createAssetWithBlankFields() {
		Group g = new Group();
		g.setType(GroupType.PACKAGE);

		g.addField(createField("/tns:Fields/tns:AssetName", ""));
		g.addField(createField("/tns:Fields/tns:AssetClass", "package"));
		g.addField(createField("/tns:Fields/tns:Description/tns:Text",
				"package1"));
		g.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"OutbreakWVC12242528x4802398pWMA129wmv"));

		// Title
		Item it = new Item();
		it.setType(ItemType.TITLE);

		it.addField(createField("/tns:Fields/tns:AssetName", ""));
		it.addField(createField("/tns:Fields/tns:AssetClass", "title"));
		it.addField(createField("/tns:Fields/tns:Description/tns:Text",
				"package1 title asset"));
		it.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"UNVA2001081701003001"));
		it.addField(createField(
				"/tns:Fields/tns:BillingInfo/tns:SuggestedPrice/tns:Value",
				"3.95"));

		// Movie
		Item im = new Item();
		im.setType(ItemType.MOVIE);

		im.addField(createField("/tns:Fields/tns:AssetName", ""));
		im.addField(createField("/tns:Fields/tns:AssetClass", "movie"));
		im.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"UNVA2001081701003002"));
		im.addField(createField("/tns:Fields/tns:Content/tns:Locator/tns:Uri",
				"MandolinTR.mpg"));

		// Preview
		Item ip = new Item();
		ip.setType(ItemType.PREVIEW);

		im.addField(createField("/tns:Fields/tns:AssetName", ""));
		im.addField(createField("/tns:Fields/tns:AssetClass", "preview"));
		im.addField(createField("/tns:Fields/tns:Identifier/tns:Id",
				"UNVA2001081701003003"));

		g.addChild(it);
		g.addChild(im);
		g.addChild(ip);

		return g;
	}

	private Field createField(String xpath, String value) {
		Field f = new Field();
		f.setTtvXPath(xpath);
		f.setValue(value);

		String[] a = xpath.split("/");
		ArrayList<Integer> indices = new ArrayList<Integer>(a.length);
		for (int i = 0; i < a.length; i++) {
			indices.add(new Integer(1));
		}

		f.setIndices(indices);

		return f;
	}
}
