package com.tandbergtv.watchpoint.contentmgmt.communication.handlers;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.w3c.dom.Document;

import com.tandbergtv.metadatamanager.ITTVDataModelHandler;
import com.tandbergtv.metadatamanager.factoryImpl.SpecHandlerFactory;
import com.tandbergtv.metadatamanager.model.Asset;
import com.tandbergtv.metadatamanager.spec.ISpecHandler;
import com.tandbergtv.metadatamanager.spec.IValidator;
import com.tandbergtv.metadatamanager.validation.ValidationError;
import com.tandbergtv.watchpoint.communication.Util;
import com.tandbergtv.watchpoint.pmm.communication.HandlerErrorCode;
import com.tandbergtv.watchpoint.pmm.communication.MessageHandler;
import com.tandbergtv.watchpoint.pmm.communication.MessageHandlerException;
import com.tandbergtv.watchpoint.pmm.dao.hibernate.ApplicationContextHelper;
import com.tandbergtv.watchpoint.pmm.entities.Title;
import com.tandbergtv.watchpoint.pmm.title.ITitleService;
import com.tandbergtv.workflow.core.service.ServiceRegistry;
import com.tandbergtv.workflow.message.IMessageKey;
import com.tandbergtv.workflow.message.IMessageUID;
import com.tandbergtv.workflow.message.WorkflowMessage;
import com.tandbergtv.workflow.message.WorkflowMessage.MessageType;

/**
 * This message handler is responsible to get the asset associated with the the given titleid, 
 * convert it into its metadata xml in the given spec and validate it against the spec.
 * 
 * @author spuranik
 * 
 */
public class ValidateTitleMessageHandler implements MessageHandler {

	/* constants for the message */
	private static String SPEC_NAME = "spec";
	private static String TITLE_ID = "titleId";
	
	/* messages in the response */
	private static String NO_VALIDATOR_FOR_SPEC = "No validator for spec defined.";
	private static String NO_TITLE_FOUND = "No title found with given id."; 
	private static String SPEC_HANDLER_NOT_FOUND = "No handler found for the given spec.";
	private static String VALIDATION_FAILED = "Failed to validate the given metadata: ";
	
	@Override
	public WorkflowMessage handleMessage(WorkflowMessage message) throws Exception {
		// validate the input.
		Util.validateRequired(message, TITLE_ID, SPEC_NAME);
		
		String spec = Util.getStringValueTrimmed(message, SPEC_NAME);
		long titleId = Util.getLongValue(message, TITLE_ID);

		/* fetch the title */
		ITitleService titleService = ServiceRegistry.getDefault().lookup(ITitleService.class);
		Title t = titleService.getTitle(titleId);
		
		/* check if title was found */
		if(t == null) {
			throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, NO_TITLE_FOUND);
		}

		/* get the asset from metadata manager */
		ApplicationContext springContext = ApplicationContextHelper.getInstance().getContext();
		ITTVDataModelHandler ttvSpecHandler = (ITTVDataModelHandler) springContext.getBean("TTVSpecHandler");
		long assetId = t.getAsset().getId();
		Asset asset = ttvSpecHandler.getAsset(assetId);

		ISpecHandler specHandler = SpecHandlerFactory.getInstance(spec);
		/* check if the spec handler exists */
		if(specHandler == null) {
			throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, SPEC_HANDLER_NOT_FOUND);
		}
		
		/* now convert this asset into its metadata xml */
		Document metadataDocument = specHandler.convertAssetToXMLDocument(asset);
		
		/*
		 * The validator we are actually interested in is called
		 * [specNameAlias]Validator. Can;t depend on the name as its configurable
		 * so pick the first validator registered with the spec handler.
		 */
		IValidator validator = specHandler.getRuleValidators().values().iterator().next();
		/* If no validator was found, throw an exception */
		if(validator == null) {
			throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR, NO_VALIDATOR_FOR_SPEC);
		}
		List<ValidationError> errors = validator.validate(metadataDocument);
		
		/* If there were any errors throw an exception */
		if (!errors.isEmpty()) {
			throw new MessageHandlerException(HandlerErrorCode.RUNTIME_ERROR,
					VALIDATION_FAILED + getErrorMsg(errors));
		}

		/* If there were no errors, build the ack response message */
		IMessageUID uid = message.getMessageUID();
		IMessageKey key = message.getKey();
		return new WorkflowMessage(uid, key, MessageType.ack);
	}

	/**
	 * Prepares a comma separated list of validation errors.
	 * 
	 * @param errors
	 * @return
	 */
	private String getErrorMsg(List<ValidationError> errors) {
		StringBuilder sb = new StringBuilder();
		for (ValidationError error : errors) {
			if (sb.length() > 0) {
				sb.append(", ");
			}
			sb.append(error.toString());
		}
		return sb.toString();
	}
}
