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

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.zip.CRC32;

import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;

public class GeneralUtils extends AssociationUtils {

	private static List<Properties> properties;
	private static String outputDir;
	private static String baseDir;
	
	public static void setupProps(List<String> p, String oDir, String bDir) {
		outputDir = oDir;
		baseDir = bDir;
		properties = new ArrayList<Properties>();
		for (String p1 : p) {
			Properties props = new Properties();
			try {
				props.load(new FileInputStream(new File(p1)));
				properties.add(props);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static String getOutputDir() {
		return outputDir;
	}
	
	public static String getBaseDir() {
		return baseDir;
	}
	
	public static String getProperty(String pName) {
		for (Properties p : properties) {
			String value = p.getProperty(pName);
			if (value != null) {
				return value;
			}
		}
		return null;
	}
	/**
	 * Method to generate a SerialUID based on actual Timestamp
	 * 
	 * @author Vittorio Niespolo <vittorio.niespolo@micegroup.it>
	 * @param object
	 * @return the generated SerialUID
	 */
	public String getGeneratedSerialUID(Class classe) {
		CRC32 crc = new CRC32();
		crc.update(getEntityDump(classe).getBytes());
		return String.valueOf(crc.getValue()) + "L";
	}

	public String getEntityDump(Class classe) {
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		sb.append(classe.getName()).append("; ");

		// ID
		sb.append("[");
		Collection<Property> ids = EntityUtils.getClassIDs(classe);
		if (ids != null) {
			Iterator<Property> i = ids.iterator();
			while (i.hasNext()) {
				Property id = i.next();
				sb.append(getAttributeDump(id));
			}
		}
		sb.append("]");
		sb.append(", ");

		// ATTRIBUTI GENERICI
		sb.append("[");
		Collection<Property> attributi = classe.getAttributes();

		if (attributi != null) {
			Iterator<Property> i = attributi.iterator();
			while (i.hasNext()) {
				Property attribute = i.next();
				sb.append(getAttributeDump(attribute));
			}
		}
		sb.append("]");
		return sb.toString();
	}

	public String getAttributeDump(Property attribute) {
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		sb.append(attribute.getName()).append("; ");
		sb.append(attribute.getType().getName()).append("; ");
		sb.append(PropertyUtils.isRequired(attribute)).append("; ");
		sb.append("} ");
		return sb.toString();
	}

	/**
	 * Return true if parent specified by association and property (end) has 0 or 1
	 * multiplicity
	 * 
	 * @author Jessica Pascarella
	 * @param association
	 * @param property
	 * @return
	 */
	// TODO VN ELIMINARE QUESTO METODO
	public static boolean isParentZeroOneMultiplicity(Association association, Property property) {
		if (isOneToOneRelation(association) && hasChildOneToOne((Class) property.getType(), association, property)) {
			return true;
		} else if (!isOneToOneRelation(association) && PropertyUtils.isZeroOneMultiplicity(property))
			return true;
		return false;
	}

	/**
	 * Return true if child specified by association and property (end) has 0 or 1
	 * multiplicity
	 * 
	 * @author Jessica Pascarella
	 */
	// TODO VN ELIMINARE QUESTO METODO
	public static boolean isChildZeroOneMultiplicity(Association association, Property property) {
		if (isOneToOneRelation(association) && hasParentOneToOne((Class) property.getType(), association, property)) {
			return true;
		}
		return false;
	}

	/**
	 * Ritorna il package del domain importato nel modello
	 * @author Vittorio Niespolo <vittorio.niespolo@micegroup.it>
	 *
	 * @param umlElement
	 * @return
	 */
	public static Package getDomainPackage(Element umlElement) {
		for (Package pack : umlElement.getModel().getImportedPackages()) {
			if (pack.getName().equals("domain_model")) {
				return pack;
			}
		}
		ConsoleUtils.consoleMessage(SeverityLevels.ERROR, "Non è stato possibile trovare il domain_model nel modello");
		return null;
	}
	
	public static Class getVoilaType(Class classe, String wishedDataType) {
		Package domainPackage = getDomainPackage(classe);
		Package domains = (Package) domainPackage.getPackagedElement("domains");

		Class dataType = (Class) domains.getPackagedElement(wishedDataType);
		return dataType;
	}
}
