package com.tandbergtv.metadatamanager.specimpl.ttv;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.transaction.annotation.Transactional;

import com.tandbergtv.metadatamanager.ITTVDataModelHandler;
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.RootAssetRevision;
import com.tandbergtv.metadatamanager.model.SearchCriteria;
import com.tandbergtv.metadatamanager.model.Spec;
import com.tandbergtv.metadatamanager.spec.IIdentifier;
import com.tandbergtv.metadatamanager.specimpl.IdentifierBase;
import com.tandbergtv.metadatamanager.specimpl.SpecHandlerBase;
import com.tandbergtv.metadatamanager.util.AssetUtil;

public class TTVSpecHandler extends SpecHandlerBase implements
		ITTVDataModelHandler {

	private static final String TTV_ROOTELEMENT_NAME = "TTVSpec";

	public TTVSpecHandler() {
		super();
		this.spec = Spec.TTV;
		this.rootElementName = TTV_ROOTELEMENT_NAME;
	}

	@Override
	public IIdentifier extractId(Asset asset) {
		return asset.getTTVId();
	}

	@Override
	protected SearchCriteria prepareSearchPathById(List<Field> fields) {
		return null;
	}

	@Override
	public IdentifierBase getIdentifier() {
		TTVId id = new TTVId();
		id.setSearchService(searchService);
		return id;
	}
	
	@Override
	protected Map<String, String> translate(List<String> fields) {
		// simply create a map with key and value both as the field name which
		// is a ttv xpath
		Map<String, String> fieldsXPath = new HashMap<String, String>();
		for (String field : fields) {
			fieldsXPath.put(field, field);
		}
		return fieldsXPath;
	}

	@Override
	public TTVId getTTVId(Asset asset, Asset rootAsset)
			throws SearchException {
		if (asset.getTTVId().getId() <= 0) {
			return null;
		} else {
			return asset.getTTVId();
		}
	}


	/**
	 * 
	 * Need to override this method since the mergeFields method in the
	 * spechandlerbase also looks up specspecific xpaths to determine what
	 * needsw to be deleted. In TTV, no such lookup is needed since the
	 * assumption is that all fields coming in as TTV represent the latest and
	 * most uptodate asset fields.
	 */
	@Override
	public  boolean isXPathPartOfSpec(String assetType, String ttvXPath){
		return true;
	}

	@Override
	@Transactional
	public void delete(Asset asset) throws SearchException {
		metadataManagerDAO.delete(asset);
	}

	@Override
	@Transactional(readOnly=true)
	public Asset getAsset(TTVId id) throws SearchException {
		return getAsset(id, null);
	}	

	@Override
	@Transactional
	public Asset saveAsset(Asset asset, boolean saveAsDraft) throws MetadataException {
		return saveAsset(asset, null, null, null, saveAsDraft);
	}

	@Override
	@Transactional
	public Asset getAsset(TTVId id, String revision) throws SearchException {
		return getAssetTree(id, revision, true);
	}

	@Override
	@Transactional
	public List<RootAssetRevision> getRevisions(TTVId id)
			throws SearchException {
		Asset topLevelAsset =  metadataManagerDAO.getAsset(id, true);
		if(!(topLevelAsset instanceof Group)){
			throw new SearchException("Asset with TTVID[" + id + "] is not a top level asset, thus no revision history.");
		}
		return ((Group)topLevelAsset).getRevisions();
	}

	@Override
	@Transactional
	public Asset saveAsset(Asset asset, String revisionSource,
			String revisionComment, String externalRevision, boolean saveAsDraft) throws MetadataException {
		
		asset = new AssetUtil().unWrap(asset);
		
		if(!(asset instanceof Group)){
			throw new MetadataException("Asset:" + asset + ", is not a top level asset, can not be saved.");
		}
		asset.loadCompleteTree();
		AssetUtil.evictAssetTree(asset, metadataManagerDAO.getCurrentSession());
		
		RootAssetRevision rootAssetRevision = null;
		rootAssetRevision = new RootAssetRevision(revisionSource, revisionComment, externalRevision);

		List<Asset> toBeMergedAssets = new ArrayList<Asset>();
		toBeMergedAssets.add(asset);

		List<Asset> mergedAssets = mergeSaveAssets(toBeMergedAssets, true, rootAssetRevision, false, saveAsDraft);
		if(mergedAssets != null && mergedAssets.size()>0){
			return mergedAssets.get(0);
		}
		return null;
	}

	/**
	 * for TTV spec, this always returns true
	 */
	@Override
	protected boolean isAssetTypePartOfSpec(String assetType) {
		return true;
	}

	@Override
	protected Asset searchNewTargetAsset(String oldTargetAssetType, Asset newAsset,
			Asset oldTargetAsset) {
		return newAsset.getAsset(oldTargetAsset.getTTVId().getId());
	}

	@Override
	protected void checkDuplicateChildItems(Asset asset, Set<String> criteriaValueSet) throws MetadataException {
	}

	@Override
	protected Asset searchTargetAssetInMemory(Asset newTargetAsset, Asset rootAsset, Asset oldAsset) {
		if(newTargetAsset.getTTVId() == null || newTargetAsset.getTTVId().getId() <= 0){
			return null;
		} 
		return oldAsset.getAsset(newTargetAsset.getTTVId().getId());
	}
	
	
	
}
