package com.tandbergtv.watchpoint.pmm.web.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.tandbergtv.watchpoint.pmm.core.AssetsManager;
import com.tandbergtv.watchpoint.pmm.core.IPMMService;
import com.tandbergtv.watchpoint.pmm.core.PMMException;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.title.ITitlePersistenceService;
import com.tandbergtv.watchpoint.pmm.title.ITitleService;
import com.tandbergtv.watchpoint.pmm.title.TitleUtil;
import com.tandbergtv.watchpoint.pmm.title.conf.IMetadataConverter;
import com.tandbergtv.watchpoint.pmm.title.conf.ISpecificationManager;
import com.tandbergtv.watchpoint.pmm.title.conf.Specification;
import com.tandbergtv.watchpoint.pmm.title.provider.ITitleProvider;
import com.tandbergtv.watchpoint.pmm.title.provider.ITitleProviderInstance;
import com.tandbergtv.watchpoint.pmm.title.provider.ITitleProviderRegistry;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.sanmanager.SANManagementException;

/**
 * A Facade class to get information required for UI Title section from the core system.
 * 
 * @author Raj Prakash
 */
public class TitleFacade {
	
	/**
	 * Gets all the specifications as html option objects,
	 *  sorted in ascending order of their label.
	 */
	public static List<HTMLOption> getSpecifications() {
		List<HTMLOption> specs = new ArrayList<HTMLOption>();
		ISpecificationManager sm = ServiceRegistry.getDefault().lookup(ISpecificationManager.class);
		for(Specification s : sm.getAllSpecifications())
			specs.add(new HTMLOption(s.getName(), s.getName()));
		sort(specs);
		return specs;
	}
	
	/**
	 * Gets all the title providers that support the given specification as html options,
	 *  sorted in ascending order of their label.
	 */
	public static List<HTMLOption> getTitleProviderInstances(String type) {
		List<HTMLOption> providers = new ArrayList<HTMLOption>();
		ITitleProviderRegistry tpr = getService(ITitleProviderRegistry.class);
		Collection<ITitleProvider> titleProviders = tpr.getProviders(type);
		if(titleProviders != null) {
			for(ITitleProvider tp : titleProviders) {
				if (tp != tpr.getDefaultProvider()) {
					Collection<ITitleProviderInstance> instances = tp.getProviderInstances();
					if (instances != null) {
						for (ITitleProviderInstance tpi : instances) {
							providers.add(new HTMLOption(tpi.getName(), tpi.getKey()));
						}
					}
				}
			}
		}
		sort(providers);
		
		/* Add the default empty provider */
		providers.add(0, new HTMLOption(""));

		return providers;
	}
	
	/**
	 * Gets the name of the default title provider.
	 */
	public static String getDefaultTitleProvider() {
		String defaultTitleProviderName = null;
		ITitleProviderRegistry tpr = getService(ITitleProviderRegistry.class);
		if(tpr != null) {
			ITitleProvider defaultTitleProvider = tpr.getDefaultProvider();
			if(defaultTitleProvider != null)
				defaultTitleProviderName = defaultTitleProvider.getName();
		}
		return defaultTitleProviderName;
	}

	/**
	 * @see com.tandbergtv.watchpoint.pmm.title.ITitleService#createTitlesForSpecification(java.lang.String)
	 */
	@Deprecated
	public static Title createTitlesForSpecification(String specName) {
		//return getService(ITitleService.class).createTitlesForSpecification(specName);
		return null;
	}
	
	/**
	 * Saves the given title to the persistence store.
	 */
	@Deprecated
	public static void save(Title rootTitle) {
		// getService(ITitleService.class).save(rootTitle);
	}
	
	/**
	 * Finds root title with the given id. Returns null, if not found. 
	 */
	public static Title findTitle(long id) {
		return getService(ITitlePersistenceService.class).get(id);
	}

	/** Gets the specification that is of the given name */
	public static Specification getSpecificationByName(String name) {
		return getService(ISpecificationManager.class).getSpecificationByName(name);
	}
	
	/** Send Asset Received Status for the given rootTitle and titleName */
	public static void sendAssetReceivedStatus(Title rootTitle, String titleName) {
		getService(IPMMService.class).sendAssetReceivedStatus(rootTitle,
				titleName, null, null, null);
	}
	
	/** Send Metadata Received Status for the given rootTitle */
	public static void sendMetadataReceivedStatus(Title rootTitle) {
		getService(IPMMService.class).sendMetadataReceivedStatus(rootTitle,
				null, null, null);
	}

	/**
	 * Gets unmapped files as list of HTMLOption objects.
	 * 
	 * @throws SANManagementException	when the unmapped files drive does not exist
	 * @throws IOException				for any file system access exceptions
	 */
	public static List<HTMLOption> getUnmappedFiles() throws SANManagementException, IOException {
		List<HTMLOption> unmappedFilesHTMLOptions = new ArrayList<HTMLOption>();
		
		for(File unmappedFile : AssetsManager.getThreadLocalInstance().getUnmappedFiles())
			unmappedFilesHTMLOptions.add(new HTMLOption(unmappedFile.getAbsolutePath()));
		
		sort(unmappedFilesHTMLOptions);
		
		return unmappedFilesHTMLOptions;
	}
	
	/**
	 * Maps unmapped assets, if there are any that relate to the given title.
	 * 
	 * @see IPMMService#mapAssets(Title)
	 */
	@Deprecated
	public static List<Title> mapAssets(Title rootTitle) {
		//return getService(IPMMService.class).mapAssets(rootTitle);
		return null;
	}

	/**
	 * Checks if the given file path refers to a file within unmapped files dircetory. 
	 */
	public static boolean isInUnmappedFilesDirectory(String filePath)
			throws SANManagementException {
		if(!TitleHelper.containsValue(filePath))
			return false;
		File unmappedFilesDir = AssetsManager.getThreadLocalInstance().getUnmappedFilesDirectory();
		return filePath.startsWith(unmappedFilesDir.getAbsolutePath());
	}
	
	/**
	 * Checks if the given file path refers to a file within mapped files directory.
	 */
	public static boolean isInMappedFilesDirectory(String filePath)
			throws SANManagementException {
		if(!TitleHelper.containsValue(filePath))
			return false;
		File mappedFilesDir = AssetsManager.getThreadLocalInstance().getMappedFilesDirectory();
		return filePath.startsWith(mappedFilesDir.getAbsolutePath());
	}

	/**
	 * Moves the given file to mapped files directory.
	 * 
	 * @see AssetsManager#moveToMappedFilesDirectory(File)
	 */
	public static String moveToMappedFilesDirectory(String filePath)
													throws IOException, SANManagementException {
		File file = new File(filePath);
		File movedFile = AssetsManager.getThreadLocalInstance().moveToMappedFilesDirectory(file);
		return movedFile.getAbsolutePath();
	}
	
	/**
	 * Moves the given file to unmapped files directory.
	 * 
	 * @see AssetsManager#moveToUnmappedFilesDirectory(File)
	 */
	public static String moveToUnmappedFilesDirectory(String filePath)
													throws IOException, SANManagementException {
		File file = new File(filePath);
		File movedFile = AssetsManager.getThreadLocalInstance().moveToUnmappedFilesDirectory(file);
		return movedFile.getAbsolutePath();
	}
	
	/**
	 * @see AssetsManager#beginTransaction()
	 */
	public static void beginAssetsManagerTx() {
		AssetsManager.getThreadLocalInstance().beginTransaction();
	}
	
	/**
	 * @see AssetsManager#commitTransaction()
	 */
	public static void commitAssetsManagerTx() {
		AssetsManager.getThreadLocalInstance().commitTransaction();
	}

	/**
	 * @see AssetsManager#rollbackTransaction()
	 */
	public static void rollbackAssetsManagerTx() {
		AssetsManager.getThreadLocalInstance().rollbackTransaction();
	}

	/**
	 * @throws PMMException
	 * @see TitleUtil#replaceMetadata(Title, Title)
	 */
	public static void replaceMetadata(Title parsedMetadata, Title rootTitle) throws PMMException {
		TitleUtil.replaceMetadata(parsedMetadata, rootTitle);
	}

	/**
	 * Parses the given metadata file using the specification (type)'s
	 * configured converter class.
	 */
	public static Title parseMetadata(String type, String metadataFilePath)
		throws Exception {
		Specification spec = getSpecificationByName(type);
		IMetadataConverter metadataConverter = spec.getMetadataConverter();
		return metadataConverter.unmarshal(new File(metadataFilePath));
	}

	/**
	 * Approves the title.
	 * 
	 * @see ITitleService#approve(long)
	 */
	public static Title approve(long titleID) throws PMMException {
		return getService(ITitleService.class).approve(titleID);
	}
	
	/**
	 * Disapproves the title.
	 * 
	 * @see ITitleService#disapprove(long)
	 */
	public static Title disapprove(long titleID) throws PMMException {
		return getService(ITitleService.class).disapprove(titleID);
	}

	/**
	 * Sorts the given html options in ascending order of their label.
	 */
	private static void sort(List<HTMLOption> options) {
		Collections.sort(options, new Comparator<HTMLOption>() {
			public int compare(HTMLOption o1, HTMLOption o2) {
				if(o1 == null)
					return 1;
				if(o2 == null)
					return -1;
				return o1.getLabel().compareTo(o2.getLabel());
			}
		});
	}
	
	/**
	 * Looks up implementation of the given service interface in the Service Registry.
	 */
	private static <T> T getService(Class<T> clazz) {
		return ServiceRegistry.getDefault().lookup(clazz);
	}
}
