/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tmaestroplayer;

import edutainmentclient.Main;
import java.awt.Component;
import java.awt.GridBagLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import javax.media.CannotRealizeException;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.plaf.basic.BasicInternalFrameUI;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import db.DBAccessImplementation;

/**
 *
 * @author Gonzalo
 */
public class CourseLoader {

    private String rutaScorm;
    private String courseName;
    private String optionName;
    private String userName;
    //Cambiamos CVApplet por MainWindow
    //private CVApplet applet;
    private MainWindow frame;
    // private MainWindow_portada frame_portada;
    // Panel donde se añaden los componentes visuales
    JDesktopPane panel = new JDesktopPane();
    // JInternalFrame que contiene los elementos del menú de un curso
    VentanaSeleccionUnidad vsu = null;
    // Namespace asociados al fichero imsmanifest.xml de un curso
    Namespace manifestNS;
    Namespace metadataNS;
    Namespace manifestStyle;
    //Identifier del manifest
    private String courseId;
    protected String lastScoId;
    protected String scoPath;
    protected String scoPoint;
    protected boolean restored = false;

    //public CourseLoader(CVApplet applet) {
    public CourseLoader(MainWindow frame) {
        System.out.println("CourseLoader");
        //System.out.println("Entramos en el constructor de CourseLoader");
        //this.applet = applet;
        this.frame = frame;
        //this.courseName = this.applet.nombreCurso;
        this.courseName = this.frame.nombreCurso;

        //this.optionName = this.applet.option;
        this.optionName = this.frame.option;
        this.rutaScorm = this.frame.rutaScorm;
        this.userName = this.frame.userName;

    }

    /*
    public CourseLoader(MainWindow_portada frame) {
    System.out.println("entro por frame_portada");
    //System.out.println("Entramos en el constructor de CourseLoader");
    //this.applet = applet;
    this.frame_portada = frame;
    //this.courseName = this.applet.nombreCurso;
    this.courseName = this.frame_portada.nombreCurso;
    System.out.println("coruse name "+courseName);
    //this.optionName = this.applet.option;
    this.optionName = this.frame_portada.option;
    this.rutaScorm = this.frame_portada.rutaScorm;
    System.out.println("ruta scorm "+rutaScorm);
    this.userName = this.frame_portada.userName;

    }
     */
    public void setPanel(JDesktopPane panel) {
        this.panel = panel;
    }

    public Component getVisual() {
        panel.repaint();
        panel.setLayout(null);

        //System.out.println("Error nombre curso " + this.courseName);
        this.mostrarCurso(this.courseName);


        panel.setVisible(true);
        panel.setOpaque(true);
        panel.setBounds(0, 0, 720, 576);
        /*panel.addFocusListener(new FocusListener() {

        public void focusGained(FocusEvent e) {
        System.out.println("El JdesktopPane ganó el focus");

        }

        public void focusLost(FocusEvent e) {
        System.out.println("El JdesktopPane perdió el focus");
        }
        });
        panel.addKeyListener(new java.awt.event.KeyAdapter() {

        public void keyPressed(java.awt.event.KeyEvent evt) {
        System.out.println("Se recibió una pulsación de tecla en el JDesktopPane");
        }
        });*/
        //System.out.println(panel.getAllFrames().length);

        return panel;
    }

    /******************************************************************************
     * Función que muestra el menú del curso en el applet                         *
     * @param nombre: nombre del curso seleccionado                               *
     ******************************************************************************/
    public void mostrarCurso(String nombre) {
        System.out.println("mostrar curso " + nombre);
        courseId = frame.courseId;
        scoPath = frame.scoPath;
        lastScoId = frame.scoId;
        scoPoint = frame.scoTimestamp;

        final Unit[] resultado = openCourse(nombre);



        //Gonzalo 17122009: este método nos dice que organization usar
        //int index = getOrganization(resultado, applet.userName);
        //SSS OJO
        int index = getOrganization(resultado, this.userName);
        //int index=0;
        System.out.println("organizacion " + index + " userNme " + this.userName);


        /*int index = 0;
        while (true) {
        int indexp = str.indexOf("/", index + 1);
        if (indexp == -1) break;
        else index = indexp;
        }*/
        //final String path = "http://localhost:8080/tMAESTRO" + str.substring(0, index + 1);
        //final String path = applet.rutaScorm + nombre;
        final String path = this.rutaScorm + nombre;
        //Gonzalo 17122009: Ahora leemos el estilo de la organizacion correspondiente
        //final Vector valuesStyle = getStyleValues(nombre);

        System.out.println("Identificador del curso: " + resultado[index].getIdentifier());

        final Vector valuesStyle = getStyleValues(nombre, resultado[index].getIdentifier());


        /****** Ahora vamos a utilizar un reproductor unico para el audio *****/
        /****** Lo inicializamos aquí **********************/
        HashMap styleMap = (HashMap) valuesStyle.get(0);
        String backgroundmusic = (String) styleMap.get("backgroundmusic");

        URL dirPlayer = null;
        try {
            dirPlayer = new URL(path + backgroundmusic);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        if (frame != null) {
            try {
                frame.bgMusicPlayer = Manager.createRealizedPlayer(dirPlayer);
            } catch (NoPlayerException e) {
                System.err.println(e);
            } catch (CannotRealizeException e) {
                System.err.println(e);
            } catch (IOException e) {
                System.err.println(e);
            }
        }


        //readStyleValues(valuesStyle);
        System.out.println("cuanto hago el for " + resultado.length);
        // for (int i = 0; i < resultado.length; i++) {
        Unit[] units = resultado[index].getSubUnits();


        //Gonzalo 17122009: Cambiado para pasarle la organizacion a mostrar
        //vsu = new VentanaSeleccionUnidad(new Unit[]{resultado[index]}, path, applet, this.optionName, valuesStyle, 0, null);
        System.out.println("llamo a ventana seleccion unidad3 ");
        Unit[] unit = new Unit[]{resultado[index]};
        vsu = new VentanaSeleccionUnidad(unit, path, frame, this.optionName, valuesStyle, 0, null);
        //vsu = new VentanaSeleccionUnidad(resultado, path, applet, this.optionName, valuesStyle, 0, null);

        // Eliminar top border JInternalFrame
        BasicInternalFrameUI ui = (BasicInternalFrameUI) vsu.getUI();
        ui.setNorthPane(null);


        panel.add(vsu);
        //frame.scoId = null;
//System.out.println("veo si tengo q forzar: "+Main.forzar);
        //Gonzalo 25032009: utilizamos el identifier del organization para recuperar la información de la posición
        System.out.println("Forzar Inicio " + frame.forzarInicio);
        System.out.println("scoId " + frame.scoId);
        System.out.println("courseId " + frame.courseId);



        if ((!frame.forzarInicio) && (frame.scoId.compareTo("") != 0)) {
            boolean borrar = false;
            System.out.println("//SSS voy a empezar en algún punto(forzarInicio&&scoID!=0");
            System.out.println("Ultimo SCO: " + frame.scoId);

            // if (!scoIdvacio) {
            System.out.println("scoPath antes : " + frame.scoPath);
            frame.scoPath = frame.scoPath.substring(frame.scoPath.indexOf(" ") + 1);
            frame.oCL.scoPath = frame.scoPath;
            System.out.println("scoPath: " + frame.scoPath);
            System.out.println("scoPoint: " + frame.scoTimestamp);
            //Indicamos que hemos restaurado un estado previo
            restored = true;

            //Cargamos la siguiente VSU para poder llegar al punto en el que estabamos
            vsu.restorePoint();

            //Anhadimos el controlador al reprocutor pero no lo iniciamos
            if (frame.bgMusicPlayer != null) {
                frame.bgMusicPlayer.addControllerListener(frame);
            }
            // }
        } else if ((Main.basededatos)) {

            System.out.println("//SSS voy a empezar en algún punto (basededatos)");
            frame.scoId = DBAccessImplementation.getInstance().getLastScoId(frame.courseId, userName);
            if (frame.scoId.compareTo("") == 0) {
                //System.out.println("forzar Inicio false");
                frame.forzarInicio = false;
                System.out.println("//SSS Pero solo en el curso");
                vsu.moveToFront(); // mejor que andar poniendo y quitando los elementos para que vsu quede al frente (y mucho más rápido)

                vsu.setVisible(true);

                if (frame != null) {
                    //Y aquí lo ponemos a reproducir
                    if (frame.bgMusicPlayer != null) {
                        System.out.println("musicstart");
                        frame.bgMusicPlayer.addControllerListener(frame);
                        frame.bgMusicPlayer.start();
                    }
                }
                if (!DBAccessImplementation.getInstance().deleteLastSco(frame.courseId, userName)) {
                    System.out.println("no se puedo eliminar la entrada del curso");
                }
            } else {
                System.out.println("Ultimo SCO: " + frame.scoId);

                frame.oCL.lastScoId = frame.scoId;
                frame.scoPath = DBAccessImplementation.getInstance().getScoPath(frame.scoId);

                System.out.println("scoPath antes : " + frame.scoPath);
                frame.scoPath = frame.scoPath.substring(frame.scoPath.indexOf(" ") + 1);

                frame.scoTimestamp = DBAccessImplementation.getInstance().getScoPoint(frame.scoId, userName);
                frame.oCL.scoPath = frame.scoPath;
                System.out.println("scoPath: " + frame.scoPath);
                System.out.println("scoPoint: " + frame.scoTimestamp);

                //Una vez recuperamos el punto lo eliminamos de la base de datos

                if (!DBAccessImplementation.getInstance().deleteLastSco(frame.courseId, userName)) {
                    System.out.println("no se puedo eliminar la entrada del curso");
                }

                //Indicamos que hemos restaurado un estado previo
                restored = true;
                //Cargamos la siguiente VSU para poder llegar al punto en el que estabamos
                vsu.restorePoint();

                //Anhadimos el controlador al reprocutor pero no lo iniciamos
                if (frame.bgMusicPlayer != null) {
                    frame.bgMusicPlayer.addControllerListener(frame);
                }
            }
        } else {
            //if ((!frame.forzarInicio) && (frame.scoId.compareTo("") == 0)) {

            System.out.println("//SSS Voy a empezar en el curso");
            vsu.moveToFront(); // mejor que andar poniendo y quitando los elementos para que vsu quede al frente (y mucho más rápido)

            vsu.setVisible(true);

            if (frame != null) {
                //Y aquí lo ponemos a reproducir
                if (frame.bgMusicPlayer != null) {
                    System.out.println("musicstart");
                    frame.bgMusicPlayer.addControllerListener(frame);
                    frame.bgMusicPlayer.start();
                }
            }

        }


        // System.out.println("Memoria total: " + Runtime.getRuntime().totalMemory());
        // System.out.println("Memoria libre: " + Runtime.getRuntime().freeMemory());

        /**********************************************************************/

        /*panel.addContainerListener(new java.awt.event.ContainerListener() {

        public void actionPerformed(java.awt.event.ActionEvent evt) {
        }

        public void componentAdded(ContainerEvent arg0) {
        }

        public void componentRemoved(ContainerEvent arg0) {
        }
        });*/
        //applet.add(panel);
        //frame.add(panel);
        //}
    }

    /*************************************************************************************
     * Función que devuelve los elementos Units almacenados en el manifiesto de un curso *
     * @param namemanifest: ruta del fichero manifiesto de un curso                      *
     *************************************************************************************/
    private Unit[] openCourse(String nombreCurso) {

        SAXBuilder builder = new SAXBuilder(false);
        org.jdom.Document doc = null;
        try {
            String namem = "imsmanifest.xml";
            //doc = builder.build(new URL(this.applet.rutaScorm + nombreCurso + namem));
            URL url = new URL(rutaScorm + nombreCurso + namem);
            //System.out.println("ruta= " + url);
            doc = builder.build(new URL(rutaScorm + nombreCurso + namem));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //Construyo el arbol en memoria desde el fichero que se lo paso por parametro.
        org.jdom.Element raiz = doc.getRootElement();

        frame.courseId = raiz.getAttributeValue("identifier");

        manifestNS = raiz.getNamespace();
        metadataNS = raiz.getNamespace("imsmd");
        org.jdom.Element organizations = raiz.getChild("organizations", manifestNS);
        List organizationList = organizations.getChildren("organization", manifestNS);

        Unit[] units = addElementsToTree(organizationList, raiz.getChild("resources", manifestNS));
        //System.out.println("tamaño " + units.length);
        return units;
    }

    /*************************************************************************************
     * Función que devuelve los elementos Units almacenados en el manifiest de un curso  *
     * @param nodeList: lista de nodos del documento del manifiesto                      *
     * @param resourcesNode: elemento de tipo identifierref                              *
     *************************************************************************************/
    private Unit[] addElementsToTree(List nodeList, org.jdom.Element resourcesNode) {

        List<Unit> units = new LinkedList<Unit>();
        for (Object obj : nodeList) {
            if (obj instanceof org.jdom.Element) {
                org.jdom.Element element = (org.jdom.Element) obj;

                String[] resources = null;
                // identifierref indica si hay un SCO asociado al item
                String resourceID = element.getAttributeValue("identifierref");
                if (resourceID != null) {
                    resources = getResourcesUrls(resourceID, resourcesNode);
                }
                Unit u = new Unit(element.getChild("title", manifestNS).getTextTrim(), getMetadata(element), null, resources);

                Unit[] subUnits = addElementsToTree(element.getChildren("item", manifestNS), resourcesNode);
                u.setSubUnits(subUnits);
                u.setIdentifier(element.getAttributeValue("identifier"));
                units.add(u);
            }
        }
        //System.out.println("#######Hay "+units.size()+" organizations");
        return units.toArray(new Unit[0]);
    }

    /****************************************************************************************
     * Función que devuelve valores identifier almacenados en el manifiest de un curso      *
     * @param resourceID: valor del atributo identifierref                                  *
     * @param resourcesNode: elemento de tipo identifierref                                 *
     ****************************************************************************************/
    private String[] getResourcesUrls(String resourceID, org.jdom.Element resourcesNode) {
        List l = resourcesNode.getChildren("resource", manifestNS);
        List<String> resourcesFileNames = new ArrayList<String>();
        for (Object o : l) {
            if (o instanceof org.jdom.Element) {
                org.jdom.Element resource = (org.jdom.Element) o;
                if (resourceID.equals(resource.getAttributeValue("identifier").trim())) {
                    for (Object res : resource.getChildren("file", manifestNS)) {
                        String value = ((org.jdom.Element) res).getAttributeValue("href").trim();
                        if (value != null) {
                            resourcesFileNames.add(value);
                        }
                    }
                    break;
                }
            }
        }
        if (resourcesFileNames.size() == 0) {
            return null;
        } else {
            return resourcesFileNames.toArray(new String[0]);
        }
    }

    /****************************************************************************************
     * Función que devuelve valores description almacenados en el manifiest de un curso     *
     * @param element: elemento del arbol                                                   *
     ****************************************************************************************/
    private String getMetadata(org.jdom.Element element) {
        org.jdom.Element metadata;
        org.jdom.Element lom;
        org.jdom.Element general;
        if ((metadata = element.getChild("metadata", manifestNS)) != null) {
            if ((lom = metadata.getChild("lom", metadataNS)) != null) {
                if ((general = lom.getChild("general", metadataNS)) != null) {
                    String description = null;
                    if (general.getChild("description", metadataNS) != null) {
                        description = general.getChild("description", metadataNS).getChild("langstring", metadataNS).getTextTrim();
                    }
                    return /*title+"\n"+*/ description;
                }
            }
        }
        return null;
    }

    /**********************************************************************************
     * Función que lee los valores de estilo almacenados en el manifiesto de un curso *
     * @param namemanifest: ruta del fichero manifiesto                               *
     **********************************************************************************/
    //Gonzalo 17122009: Cambiado el constructor para pasarle el identificador de la organizacion
    //de la que hay que leer el estilo
    private Vector getStyleValues(String nombreCurso, String identifier) {
        //private Vector getStyleValues(String nombreCurso) {
        Vector style = new Vector();
        HashMap valueStyle = new HashMap();

        SAXBuilder builder = new SAXBuilder(false);
        org.jdom.Document doc = null;
        try {
            //doc = builder.build(new URL(this.applet.rutaScorm + nombreCurso + "imsmanifest.xml"));
            doc = builder.build(new URL(this.rutaScorm + nombreCurso + "imsmanifest.xml"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        org.jdom.Element raiz = doc.getRootElement();
        manifestStyle = raiz.getNamespace("idtv");

        org.jdom.Element organizations = raiz.getChild("organizations", manifestNS);
        org.jdom.Element organization = organizations.getChild("organization", manifestNS);
        //Gonzalo 17122009: Ahora obtenemos todas las organizaciones y con el identificador
        //Seleccionamos de cual vamos a extraer el estilo
        List organizationList = organizations.getChildren("organization", manifestNS);
        //org.jdom.Element p = organization.getChild("style", manifestStyle);
        org.jdom.Element p = null;
        for (Object obj : organizationList) {
            if (obj instanceof org.jdom.Element) {
                org.jdom.Element element = (org.jdom.Element) obj;
                if (element.getAttributeValue("identifier").equals(identifier)) {
                    p = element.getChild("style", manifestStyle);
                    break;
                }
            }
        }
        if (p == null) {
            return style;
        }


        // Lectura de todos cada elemento de estilo:
        org.jdom.Element element = p.getChild("backgroundimage", manifestStyle);
        valueStyle.put("backgroundimage", element.getText());

        element = p.getChild("backgroundmusic", manifestStyle);
        valueStyle.put("backgroundmusic", element.getText());

        element = p.getChild("exiticon", manifestStyle);
        valueStyle.put("exiticon", element.getText());

        element = p.getChild("gobackicon", manifestStyle);
        valueStyle.put("gobackicon", element.getText());

        element = p.getChild("bulletpoints", manifestStyle);
        valueStyle.put("bulletpoints", element.getText());

        element = p.getChild("scrolluparrow", manifestStyle);
        valueStyle.put("scrolluparrow", element.getText());

        element = p.getChild("scrolldownarrow", manifestStyle);
        valueStyle.put("scrolldownarrow", element.getText());

        element = p.getChild("normalfont", manifestStyle);
        List lista2 = element.getChildren();
        HashMap valuesfont = new HashMap();
        for (Object obj : lista2) {
            if (obj instanceof org.jdom.Element) {
                org.jdom.Element element2 = (org.jdom.Element) obj;
                if (element2.getName().equals("name")) {
                    valuesfont.put("name", element2.getText());
                }
                if (element2.getName().equals("fontstyle")) {
                    valuesfont.put("fontstyle", element2.getText());
                }
                if (element2.getName().equals("size")) {
                    valuesfont.put("size", element2.getText());
                }
            }
        }
        valueStyle.put("normalfont", valuesfont);

        element = p.getChild("normalcolor", manifestStyle);
        lista2 = element.getChildren();
        valuesfont = new HashMap();
        for (Object obj : lista2) {
            if (obj instanceof org.jdom.Element) {
                org.jdom.Element element2 = (org.jdom.Element) obj;
                if (element2.getName().equals("r")) {
                    valuesfont.put("r", element2.getText());
                }
                if (element2.getName().equals("g")) {
                    valuesfont.put("g", element2.getText());
                }
                if (element2.getName().equals("b")) {
                    valuesfont.put("b", element2.getText());
                }
            }
        }
        valueStyle.put("normalcolor", valuesfont);

        element = p.getChild("focusedfont", manifestStyle);
        lista2 = element.getChildren();
        valuesfont = new HashMap();
        for (Object obj : lista2) {
            if (obj instanceof org.jdom.Element) {
                org.jdom.Element element2 = (org.jdom.Element) obj;
                if (element2.getName().equals("name")) {
                    valuesfont.put("name", element2.getText());
                }
                if (element2.getName().equals("fontstyle")) {
                    valuesfont.put("fontstyle", element2.getText());
                }
                if (element2.getName().equals("size")) {
                    valuesfont.put("size", element2.getText());
                }
            }
        }
        valueStyle.put("focusedfont", valuesfont);

        element = p.getChild("focusedcolor", manifestStyle);
        lista2 = element.getChildren();
        valuesfont = new HashMap();
        for (Object obj : lista2) {
            if (obj instanceof org.jdom.Element) {
                org.jdom.Element element2 = (org.jdom.Element) obj;
                if (element2.getName().equals("r")) {
                    valuesfont.put("r", element2.getText());
                }
                if (element2.getName().equals("g")) {
                    valuesfont.put("g", element2.getText());
                }
                if (element2.getName().equals("b")) {
                    valuesfont.put("b", element2.getText());
                }
            }
        }
        valueStyle.put("focusedcolor", valuesfont);

        style.add(valueStyle);
        return style;
    }

    private int getOrganization(Unit[] resultado, String userName) {

        if (resultado.length == 1) {
            return 0;
        }
        if (userName == null) {
            return 0;
        } else if (userName.toLowerCase().equals("john")) {
            return 1;
        } else if (userName.toLowerCase().equals("experto")) {
            return 1;
        }

        return 0;
    }

    public String getCourseId() {
        return frame.courseId;
    }
}
