package com.tandbergtv.spec;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.tandbergtv.metadatamanager.JPFActivator;
import com.tandbergtv.metadatamanager.conf.SpecificationBuilder;
import com.tandbergtv.metadatamanager.exception.InvalidRevisionException;
import com.tandbergtv.metadatamanager.exception.MetadataException;
import com.tandbergtv.metadatamanager.exception.SearchException;
import com.tandbergtv.metadatamanager.exception.TranslationException;
import com.tandbergtv.metadatamanager.model.RootAssetRevision;
import com.tandbergtv.metadatamanager.search.AssetSearchService;
import com.tandbergtv.metadatamanager.spec.IIdentifier;
import com.tandbergtv.metadatamanager.spec.ISpecHandler;
import com.tandbergtv.metadatamanager.specimpl.ttv.TTVId;

public abstract class BaseHandlerTest extends TestCase {

	private static final String JPF_PLUGIN_REPOSITORY_PROPERTY = "org.java.plugin.boot.pluginsRepositories";
	public static final String EXTERNAL_REVISION_TEST_EXTERNAL = "testExternal";
	public static String textFileExtension = ".xml";
	protected ApplicationContext context;
	protected AssetSearchService searchService;
	protected PlatformTransactionManager txmgr;

	/*
	 * (non-Javadoc)
	 * 
	 * @see junit.framework.TestCase#setUp()
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();

		this.context = new ClassPathXmlApplicationContext(new String[] {
				"MetadataBeansContext.xml",
				"file:tests/MetadataManager_JTA_DBContext_UnitTest.xml",
				"file:tests/DataSource_UnitTest.xml" });
		searchService = (AssetSearchService) context.getBean("assetSearch");
		txmgr = (PlatformTransactionManager) context
				.getBean("transactionManager");
		
		Properties properties = new Properties();
		String installFolder = "/opt/tandbergtv/cms/plugins";

		properties.put(JPF_PLUGIN_REPOSITORY_PROPERTY, installFolder);

		
		JPFActivator activator = new JPFActivator();
		activator.start(properties);
		
		SpecificationBuilder builder = new SpecificationBuilder(activator.getPluginManager(), context);
		
		builder.buildSpecifications();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see junit.framework.TestCase#tearDown()
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}

	protected abstract ISpecHandler createSpecHandler();

	protected abstract String getSpecName();

	protected void putMutiple(String filePathAndName, int fileIndexStart, int fileIndexEnd){
		for(int i=fileIndexStart;i<=fileIndexEnd;i++){
			put(filePathAndName, i);
		}
	}
	
	protected void put(String filePathAndName, int fileIndex) {
		
//		TransactionStatus status = txmgr
//		.getTransaction(new DefaultTransactionDefinition(
//				PROPAGATION_REQUIRED));
		
		
		ISpecHandler handler = createSpecHandler();
		try {
			File file = new File(filePathAndName + "_" + fileIndex
					+ textFileExtension);
			System.out.println("put file:" + file);
			DocumentBuilder builder = null;
			Document input = null;
			try {
				builder = DocumentBuilderFactory.newInstance()
						.newDocumentBuilder();
				input = builder.parse(file);
			} catch (SAXException e1) {
				e1.printStackTrace();
				fail();
			} catch (IOException e1) {
				e1.printStackTrace();
				fail();
			} catch (ParserConfigurationException e2) {
				e2.printStackTrace();
				fail();
			}
			List<IIdentifier> ids = handler.put(input, "testsource", "comment"
					+ fileIndex, EXTERNAL_REVISION_TEST_EXTERNAL);
			System.out.println("Added doc which generated ids: ");
			for (IIdentifier id : ids) {
				System.out.println(id.toString());
			}
		} catch (MetadataException e) {
			e.printStackTrace();
			fail();
		}
		
//		txmgr.commit(status);
	}

	public List<RootAssetRevision> getAllRevisionsByIdentifier(IIdentifier id) {
		ISpecHandler handler = createSpecHandler();
		return getAllRevisionsByIdentifier(handler, id);
	}

	
	protected List<RootAssetRevision> getAllRevisionsByIdentifier(ISpecHandler handler , IIdentifier id) {
		List<RootAssetRevision> revisions = null;
//		Document doc;
//		int i = 1;
		try {
			revisions = handler.getRevisions(id);	
//			for (RootAssetRevision revision : revisions) {
//				System.out.println("getting " + revision);
//				print(handler.get(id, revision.getVersion()),
//						revision.getVersion());
//			}
		} catch (MetadataException e) {
			e.printStackTrace();
			fail();
		} catch (SearchException e) {
			e.printStackTrace();
			fail();
		} catch (TranslationException e) {
			e.printStackTrace();
			fail();
		}
		
		return revisions;
	}
	
	protected Document getAssetDocByIdentifierAndRevision(ISpecHandler handler, IIdentifier id,
			String revisionNumber) {
		Document assetDoc = null;
		try {
			if(revisionNumber==null){
				assetDoc = handler.get(id);
			}else{
			assetDoc = handler.get(id, revisionNumber);
			}
			print(assetDoc);
		} catch (MetadataException e) {
			e.printStackTrace();
			fail();
		} catch (SearchException e) {
			e.printStackTrace();
			fail();
		} catch (TranslationException e) {
			e.printStackTrace();
			fail();
		}
		
		return assetDoc;
	}

	protected Document getAssetDocByIdentifierAndRevision( IIdentifier id,
			String revisionNumber) {
		return getAssetDocByIdentifierAndRevision(createSpecHandler(), id, revisionNumber);
	}
	
	
	protected void rollback(long ttvId, String revisionNumber) {
		System.out.println("Rolling back for ttvid[" + ttvId + "], to revison: " + revisionNumber);
		ISpecHandler handler = createSpecHandler();
		Document doc;
		try {
			doc = handler.rollBackToRevision(new TTVId(ttvId), revisionNumber);
			print(doc);
		} catch (MetadataException e) {
			e.printStackTrace();
			fail();
		} catch (SearchException e) {
			e.printStackTrace();
			fail();
		} catch (TranslationException e) {
			e.printStackTrace();
			fail();
		} catch (InvalidRevisionException e) {
			e.printStackTrace();
			fail();
		}
	}

	protected void putRollbackGetAllRevisions(String filePathAndName,
			int putFileIndexStart, int putFileIndexEnd, int rollBackTTVid,
			String rollBackRevision, IIdentifier identifier) {
		//put
		putMutiple(filePathAndName, putFileIndexStart, putFileIndexEnd);
		
		//rollback
		rollback(rollBackTTVid, rollBackRevision);
		
		//getAllRevisions
		getAllRevisionsByIdentifier(identifier);

	}

	protected void print(Document doc, String version) {
		// a search could have failed. So not printing the empty doc.
		if (doc == null) {
			fail("doc is null!");
		}
		try {
			OutputFormat format = new OutputFormat(doc);
			format.setIndenting(true);
			File outFile = new File("tests/output/" + getSpecName()
					+ "_output_" + version + ".xml");
			XMLSerializer serializer = new XMLSerializer(new FileOutputStream(
					outFile, false), format);
			serializer.serialize(doc);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	protected void print(Document doc) {
		print(doc, "NoVersion");
	}

	public void getIdentifiers(String filePathAndName, int fileIndex){
		ISpecHandler handler = createSpecHandler();
		try {
			File file = new File(filePathAndName + "_" + fileIndex
					+ textFileExtension);
			System.out.println("put file:" + file);
			DocumentBuilder builder = null;
			Document input = null;
			try {
				builder = DocumentBuilderFactory.newInstance()
						.newDocumentBuilder();
				input = builder.parse(file);
			} catch (SAXException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (ParserConfigurationException e2) {
				e2.printStackTrace();
			}

			List<IIdentifier> ids = handler.getIdentifiers(input);
			System.out.println("getIdentifiers(): ");
			for (IIdentifier id : ids) {
				System.out.println(id.toString());
			}
		} catch (MetadataException e) {
			e.printStackTrace();
		}
	}
	
	protected String convertAssetDocToString(Document assetDoc){
		StringWriter out = new StringWriter();
		XMLSerializer serializer = new XMLSerializer(out, new OutputFormat(assetDoc, null, true));
		try {
			serializer.serialize(assetDoc);
		} catch (IOException e) {
			e.printStackTrace();
			fail();
		}
		return out.toString();
	}
	
	protected String putMultipleGetLatest(String inputFilePrefix, int inputFileStartIndex, int inputFileEndIndex, IIdentifier id){
		//put initial
		putMutiple(inputFilePrefix, inputFileStartIndex, inputFileEndIndex);
		
		//check result
		Document doc = getAssetDocByIdentifierAndRevision(id, null);
		String docString = convertAssetDocToString(doc);
		System.out.println(docString);
		return docString;
	}
}
