/*
 * FormManager.java
 *
 */

package com.uvigo.tMaestro.SCOCreator.tool.metadata;

import com.uvigo.tMaestro.SCOCreator.tool.MainFrame;
import com.uvigo.tMaestro.SCOCreator.tool.MyOptionPane;
import com.uvigo.tMaestro.SCOCreator.tool.metadataGenerator.XmlGenerator;
import java.net.URL;
import java.util.ArrayList;

/**
 * Esta clase es una clase intermedia para la lectura de los elementos
 * de metadatos y sus valores. Realiza dos funciones principales: por un lado
 * lee los distintos esquemas de metadatos proporcionando a partir de ellos
 * distintos formularios que el usuario pueda cubrir y por otro lado carga
 * y gestiona las implementaciones encargadad de generar los ficheros .xml de metadatos
 * a partir de los datos recogidos desde los formularios
 * Es utilizada por el MetadataForm para la generaci�n de los campos del formulario y por
 * el MainFrame para la generaci�n de los ficheros de metadatos de los SCO's
 * @author raul
 * @version 0.1
 */
public class MetadataManager {
    
    /**
     * Array que contiene los distintos vocabularios de metadatos y sus
     * Categor�as le�das desde el correspondiente fichero de configuraci�n .xml
     * Cada uno de los elementos de esta estructura generar� un formulario
     */
    private java.util.ArrayList<java.util.ArrayList<Level>> oSchemasMetadata;
    
    /**
     * Los nombres de los vocabularios. Son importantes pues permiten localizar
     * las clases encargadas de la generaci�n de los ficheros .xml con los metadatos
     * del SCO
     */
    private java.util.ArrayList<String> oSchemaNames;
    
    
    /**
     * Array con los generadores correspondientes a los schemas. El generador de �ndice i es el
     * generador del schema cuyo nombre est� en el array oSchemaNames en el �ndice i.
     */
    private java.util.ArrayList<XmlGenerator> oGenerators;
    
    /**
     * Constructor de la clase.
     * Lee los ficheros de los diferentes esquemas de metadatos proporcionados.
     * Por defecto con la aplicaci�n s�lo se proporciona el LOM v1.o por lo que:
     * Lee el fichero de vocabulario de LOM (contiene los elementos, y sus posibles valores)
     * El fichero de vocabulario (LOMv1.xml) es una fichero .xml que sigue el schema vocabulary.xsd
     */
    public MetadataManager() {
        try {
            //--> Parte de procesado de los schemas de metadatos
            //--------------------------------------------------------------------------------------------------------
            //Creamos el JAXBContext y el Unmarshaller que nos servir�n de ayuda
            //para leer el fichero .xml de vocabulario.
            javax.xml.bind.JAXBContext oJC = javax.xml.bind.JAXBContext.newInstance("com.uvigo.tMaestro.SCOCreator.tool.metadata");
            javax.xml.bind.Unmarshaller oUn = oJC.createUnmarshaller();
            com.uvigo.tMaestro.SCOCreator.tool.metadata.Levels oLevelsElement;
            
            
            //Debemos obtener todos los ficheros de vocabularios de metadatos del directorio
            java.net.URI oURI = (this.getClass().getResource("")).toURI();
            java.util.ArrayList<String> oSchemas = new java.util.ArrayList<String>();
            if (oURI.getScheme().equals("jar")) { //La aplicaci�n se ejecuta desde el jar
                //SSSS cambiamos SCOCreator.jar
                //TODO cambie JarFile por JarInputStream
                //java.util.jar.JarFile oJarFile= new java.util.jar.JarFile("ReloadTotalv4.jar", false);
                String packageUrl = this.getClass().getClassLoader().getResource(this.getClass().getPackage().getName().replace(".", "/")).toString();
                String reloadUrl = packageUrl.substring(packageUrl.indexOf(":") + 1, packageUrl.indexOf("!"));
                java.util.jar.JarInputStream oJarInputStream = new java.util.jar.JarInputStream(new URL(reloadUrl).openStream(), false);
                //String[] aSchemas = oJarFile.getManifest().getMainAttributes().getValue("Schemas").split(" ");
                String[] aSchemas = oJarInputStream.getManifest().getMainAttributes().getValue("Schemas").split(" ");
                oSchemas.addAll(java.util.Arrays.asList(aSchemas));
            } else { // La aplicaci�n se ejecuta desde el �rbol de directorios
                java.io.File oMetadata=new java.io.File(oURI);
                
                //Obtenemos los nombres de todos los ficheros del directorio metadata
                java.io.File[] oNames=oMetadata.listFiles();
                int i=0;
                for (i=0;i<oNames.length;i++) {
                    //Descartamos los ficheros que no sean .xml
                    if (!oNames[i].getName().contains(".xml")) continue;
                    oSchemas.add(oNames[i].getName());
                }
                
            }
            
            oSchemasMetadata = new java.util.ArrayList<java.util.ArrayList<Level>>();
            oSchemaNames  = new java.util.ArrayList<String>();
            
            for (String sSchema: oSchemas) {
                //Buscamos el fichero .xml en el directorio metadata
                java.io.InputStream oVocabularyFile = this.getClass().getResource(sSchema).openStream();
                
                //Creamos la estructura con las categor�as del vocabulario
                java.util.ArrayList<Level> oLevels = new java.util.ArrayList<Level>();
                java.util.ArrayList oNames = new java.util.ArrayList<String>();
                oLevelsElement = (com.uvigo.tMaestro.SCOCreator.tool.metadata.Levels) oUn.unmarshal(oVocabularyFile);
                java.util.List oLevelElements = oLevelsElement.getLevel();
                for (Object oObject : oLevelElements) {
                    com.uvigo.tMaestro.SCOCreator.tool.metadata.LevelType oLevelElement = (com.uvigo.tMaestro.SCOCreator.tool.metadata.LevelType) oObject;
                    if (oNames.contains(oLevelElement.getLevelName())) throw new Exception("Level name duplicated");
                    oNames.add(oLevelElement.getLevelName());
                    oLevels.add(createLevel(oLevelElement));
                }
                
                if (oNames.contains(oLevelsElement.getVocabulary())) throw new Exception("Vocabulary name duplicated");
                oSchemaNames.add(oLevelsElement.getVocabulary());
                oSchemasMetadata.add(oLevels);
            }
            
            oGenerators = new java.util.ArrayList<XmlGenerator>();
            //--> Parte de procesado de las clases encargaadas de la generaci�n de los ficheros .xml.
            //Estas clases se encuentran en el paquete metadataGenerator e implementan la interfaz xmlGenerator
            //-------------------------------------------------------------------------------------------------------------------
            for (int i=0;i<oSchemaNames.size();i++) { //Cargamos cada una de las classes correspondientes a un generador de xml
                Class oClase=Class.forName("com.uvigo.tMaestro.SCOCreator.tool.metadataGenerator."+oSchemaNames.get(i));
                //Instanciamos el generador y lo a�adimos a la lista de generadores
                XmlGenerator oInstancia=(XmlGenerator) oClase.newInstance();
                oGenerators.add(oInstancia);
            }
            
            
            
        } catch(Exception oE) {
            oE.printStackTrace();
            java.awt.Toolkit.getDefaultToolkit().beep();
            MyOptionPane.showMessageDialog(MainFrame.oMainFrame,MainFrame.oMainFrame.getMessage("Error27"),"Error",javax.swing.JOptionPane.ERROR_MESSAGE);
            System.exit(-1);
        }
    }
    
    /**
     * Crea un Level a partir del LevelElement (estructura intermedia generada para leer el xml)
     * @return Un Element listo para ser a�adido al HashMap de Levels.
     */
    private Level createLevel(com.uvigo.tMaestro.SCOCreator.tool.metadata.LevelType oLevelElement) throws Exception {
        java.util.ArrayList<Element> oElements = new java.util.ArrayList<Element>();
        java.util.ArrayList<String> oNames = new java.util.ArrayList<String>();
        java.util.List oElementElements = oLevelElement.getElement();
        for (Object oObject : oElementElements) {
            com.uvigo.tMaestro.SCOCreator.tool.metadata.ElementType oElementElement = (com.uvigo.tMaestro.SCOCreator.tool.metadata.ElementType) oObject;
            if (oNames.contains(oElementElement.getElementName())) throw new Exception("Element name duplicated");
            oNames.add(oElementElement.getElementName());
            oElements.add(createElement(oElementElement,oLevelElement.getLevelName()));
        }
        return new Level(oLevelElement.getLevelName(),oLevelElement.getScreenName(),oElements);
    }
    
    /**
     * Crea un Element a partir del ElementElement (estructura intermedia generada para leer el xml)
     * @param sHierarchicName (Parte del nombre jerarquico del elemento sin incluir su nombre simple)
     * @return Un Level listo para ser a�adido al HashMap de Elements de un level.
     */
    private Element createElement(com.uvigo.tMaestro.SCOCreator.tool.metadata.ElementType oElementElement,String sHierarchicName) throws Exception{
        if (oElementElement.getElementType().equals("enumeration")) return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.ENUMERATION,oElementElement.getValues().getValue());
        if (oElementElement.getElementType().equals("integer")) {
            return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.INTEGER,oElementElement.getMin(),oElementElement.getMax());
        }
        if (oElementElement.getElementType().equals("real")) {
            return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.REAL,oElementElement.getMin(),oElementElement.getMax());
        }
        if (oElementElement.getElementType().equals("complex")) {
            java.util.List oListElementElements = oElementElement.getElement();
            java.util.ArrayList<Element> oSons = new java.util.ArrayList<Element>();
            java.util.ArrayList<String> oNames = new java.util.ArrayList<String>();
            for (int i=0;i<oListElementElements.size();i++) {
                com.uvigo.tMaestro.SCOCreator.tool.metadata.ElementType oSonElementElement=(com.uvigo.tMaestro.SCOCreator.tool.metadata.ElementType)oListElementElements.get(i);
                if(oNames.contains(oSonElementElement.getElementName())) throw new Exception("Element name duplicated");
                oSons.add(createElement(oSonElementElement,sHierarchicName+"."+oElementElement.getElementName()));
            }
            return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.COMPLEX,oSons);
        }
        if (oElementElement.getElementType().equals("boolean")) return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.BOOLEAN);
        if (oElementElement.getElementType().equals("langCode")) return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.LANCODE);
        return new Element(sHierarchicName,oElementElement.getElementName(),oElementElement.getScreenName(),Element.TEXT);
    }
    
    /**
     * Devuelve la categor�a de �ndice iIndex del vocabulario de metadatos de �ndice iSchema
     */
    public Level getLevel(int iSchema,int iIndex) {
        return oSchemasMetadata.get(iSchema).get(iIndex);
    }
    
    /**
     * Devuelve el n�mero de categor�as del vocabulario de metadatos de �ndice iSchema
     */
    public int getLevelCount(int iSchema) {
        return oSchemasMetadata.get(iSchema).size();
    }
    
    
    /**
     * Devuelve el nombre del vocabulario de indice iSchema
     */
    public String getVocabularyName(int iSchema) {
        return oSchemaNames.get(iSchema);
    }
    
    /**
     * N�mero de categor�as de vocabulario
     */
    public int getVocabularyCount() {
        return oSchemasMetadata.size();
    }
    
    /**
     * M�todo llamado por el MainFrame para crear los ficheros de metadatos del SCO
     * @param oPath La ruta donde generar los ficheros.
     * @param sName El nombre del SCO.
     * @param oMetadata La estructura con los metadatos a convertir en fichero .xml
     */
    public void createMetadataFiles(java.io.File oPath,String sName,java.util.ArrayList<java.util.HashMap<String,Object>> oMetadata) throws Exception{
        if (oMetadata==null || oMetadata.size()==0) return;
        java.util.ArrayList<java.io.File> oFiles = new java.util.ArrayList<java.io.File>();
        for (int i=0;i<oGenerators.size();i++) {
            XmlGenerator oGenerator = oGenerators.get(i);
            java.io.File oNewFile = new java.io.File(oPath,sName.split(".jar")[0]+"_"+oSchemaNames.get(i)+".xml");
            oFiles.add(oNewFile);
            try {
                oGenerator.generateXMLFile(oNewFile,oMetadata.get(i));
                System.out.println(oNewFile);
            } catch(Exception oE) { //Si el proceso no termina con �xito borramos los ficheros generados
                for (java.io.File oFile:oFiles) if (oFile.exists()) oFile.delete();
                oE.printStackTrace();
                throw new Exception(MainFrame.oMainFrame.getMessage("Error29"));
            }
        }
    }
    
    
    
}
