package it.micegroup.voila2.cartridge.library.javaservice;

import java.util.Collection;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Property;

public class ExceptionHandlerUtils {

	private static final Logger LOGGER = Logger.getLogger(ExceptionHandlerUtils.class.getName());

	static {
		LOGGER.setUseParentHandlers(false);

		ConsoleHandler handler = new ConsoleHandler();
		Formatter formatter = new LogFormatter();

		handler.setFormatter(formatter);

		LOGGER.addHandler(handler);
	}

	/**
	 * Return true if there are Self-Relations without assigned property members
	 * names
	 * 
	 * @author Jessica Pascarella <jessica.pascarella@micegroup.it>
	 *
	 * @param classe
	 * @return true if there are Self-Relations without assigned property members
	 *         names
	 */
	private boolean hasSelfRelationNameException(Class classe) {
		if (EntityUtils.isEntityStereotype(classe)) {
			for (Association association : classe.getAssociations()) {
				if (AssociationUtils.isSelfRelation(association)) {
					for (Property property : association.getMemberEnds()) {
						if (property != null && (property.getName() == null || property.getName().equals(""))) {
							LOGGER.log(Level.SEVERE, ConsoleMsgJavaUtils.GENERIC_ENTITY_EXCEPTION_MSG + classe.getName()
									+ " - " + ConsoleMsgJavaUtils.SELF_RELATION_NAMES_EXCEPTION_MSG);
							return true;
						}
					}
				}
			}
			return false;
		}
		return false;
	}

	/**
	 * Return true if the entity has a sequenceName defined but not an Code Type Id
	 * 
	 * @author Jessica Pascarella <jessica.pascarella@micegroup.it>
	 * @param classe
	 * @return true if the entity has a sequenceName defined but not an Code Type Id
	 */
	private boolean hasSequenceNameException(Class classe) {
		String sequenceName = "";
		sequenceName = EntityUtils.getSequenceName(classe);
		if (sequenceName != null && !("").equals(sequenceName)) {
			for (Property p : classe.getOwnedAttributes()) {
				if (p.isID() && p.getType() != null && p.getType().getName().equals("Code"))
					return false;
			}
			LOGGER.log(Level.SEVERE, ConsoleMsgJavaUtils.GENERIC_ENTITY_EXCEPTION_MSG + classe.getName() + " - "
					+ ConsoleMsgJavaUtils.SEQ_NAME_EXCEPTION_MSG);
			return true;
		}
		return false;
	}

	/**
	 * Return true if there are more entities with the same name
	 * 
	 * @author Jessica Pascarella <jessica.pascarella@micegroup.it>
	 * @param classes
	 * @param classe
	 * @return true if there are more entities with the same name
	 */
	private boolean hasEntityNamesException(Class classe, Collection<Class> classes) {
		if (EntityUtils.isEntityStereotype(classe)) {
			for (Class c : classes) {
				if (classe != c && EntityUtils.isEntityStereotype(c) && classe.getName().equals(c.getName())) {
					LOGGER.log(Level.SEVERE, ConsoleMsgJavaUtils.GENERIC_ENTITY_EXCEPTION_MSG + classe.getName() + " - "
							+ ConsoleMsgJavaUtils.DUPLICATED_ENTITY_NAME_EXCEPTION_MSG);
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Return true if the entity has not an ID (owner attribute), an autogenerated
	 * Id id or an id by a parent class
	 * 
	 * @author Jessica Pascarella <jessica.pascarella@micegroup.it>
	 *
	 * @return true if the entity has not an ID (owner attribute), an autogenerated
	 *         Id id or an id by a parent class
	 */
	private boolean hasEntityIdException(Class classe) {
		if (!EntityUtils.isEntityStereotype(classe))
			return false;
		if (EntityUtils.getCompositeKeyAttributes(classe).size() > 0)
			return false;
		LOGGER.log(Level.SEVERE, ConsoleMsgJavaUtils.GENERIC_ENTITY_EXCEPTION_MSG + classe.getName() + " - "
				+ ConsoleMsgJavaUtils.MISSING_ENTITY_ID_EXCEPTION_MSG);
		return true;
	}

	/**
	 * Return true if there is an attribute without type for the entity
	 * 
	 * @author Jessica Pascarella <jessica.pascarella@micegroup.it>
	 *
	 * @param type
	 * @return true if there is an attribute without type for the entity
	 */
	private boolean hasTypeMissingException(Class classe) {

		if (!EntityUtils.isEntityStereotype(classe))
			return false;
		for (Property p : classe.getOwnedAttributes()) {
			if (p.getType() == null) {
				LOGGER.log(Level.SEVERE, ConsoleMsgJavaUtils.GENERIC_ENTITY_EXCEPTION_MSG + classe.getName() + " - "
						+ ConsoleMsgJavaUtils.MISSING_TYPE_EXCEPTION_MSG);
				return true;
			}
		}
		return false;
	}

	/**
	 * Return true if the Diagram is valid for code generation
	 * 
	 * @author Jessica Pascarella <jessica.pascarella@micegroup.it>
	 *
	 * @param model
	 * @return true if the Diagram is valid for code generation
	 */
	public boolean hasDiagramExceptions(Model model) {
		boolean checkException = false;
		LOGGER.log(Level.INFO, "Diagram Validation Phase started");
		Collection<Class> classes = ModelUtils.getModelEntities();
		for (Class classe : classes) {
			checkException = hasEntityNamesException(classe, classes) || checkException;
			checkException = hasTypeMissingException(classe) || checkException;
			checkException = hasSequenceNameException(classe) || checkException;
			checkException = hasEntityIdException(classe) || checkException;
			checkException = hasSelfRelationNameException(classe) || checkException;
		}
		if (checkException)
			LOGGER.log(Level.SEVERE, "Diagram Validation Phase failed");
		else
			LOGGER.log(Level.INFO, "Diagram Validation Phase passed");
		return checkException;
	}
}
