package com.uvigo.mhp;

import com.uvigo.mhp.ui.*;
import com.uvigo.mhp.xml.course.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import javax.xml.bind.*;
import org.havi.ui.*;

// La clase Course se encarga del secuenciamiento de las p�ginas de un curso,
// de permitir el acceso a las mismas... Maneja las vistas correspondientes
// a cada una de las p�ginas, y tambi�n al front-end.
// Todas las p�ginas contienen un objeto CourseDelegate, invocable en tiempo
// de dise�o, y que sirve de intermediario con el objeto Course principal (ofrece
// sus mismos m�todos).

// Para minimizar el gasto de memoria, s�lo se mantiene en memoria una p�gina,
// la que se est� mostrando en cada momento. Cualquier informaci�n de estado
// que necesiten mantener las p�ginas deber�n almacenarla en el curso a trav�s
// del CourseDelegate.
public class Course implements CourseManager
{
    private JAXBContext jc;
    private String configurationFile;
    private ClassLoader loader;
    private static HScene scene;
    private Container panel;
    private int current;
    private java.util.List pages;
    private static FrontEnd frontend;
    private Page currentPage;
    private FrontEndType fet;
    // si panel no es null, las p�ginas se muestran sobre �l,
    // no sobre la escena completa.
    
    public Course()
    {
        try
        {
            jc=JAXBContext.newInstance("com.uvigo.mhp.xml.course");
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        
        current=-1;
        configurationFile="";
        loader=ClassLoader.getSystemClassLoader();
        panel=null;
    }
    
    public String getConfigurationFile()
    {
        return configurationFile;
    }
    
    public void setConfigurationFile(String s) throws Exception
    {
        if ((s==null) || (s=="")) return;
        
        //System.out.println("Cargando configuraci�n");
        URL url=new URL(s);
        URLConnection con=url.openConnection();
        
        Unmarshaller u=jc.createUnmarshaller();
        u.setValidating(true);
        CourseConfiguration conf=(CourseConfiguration) u.unmarshal(con.getInputStream());
        configurationFile=s;
        
        // Se instancia el frontend y se fijan sus propiedades
        fet=conf.getFrontEnd();
        
        String className=fet.getClassName();
        Class frontendClass=loader.loadClass(className);
        frontend=(FrontEnd) frontendClass.newInstance(); // se llama al constructor sin par�metros
        
        if (!(frontend instanceof FrontEnd))
            throw new Exception("The front-end must be a subclass of com.uvigo.mhp.FrontEnd");
        
        frontend.setCourse(this);
        applyParameters(frontend, fet.getParameters());
        panel=frontend.getMainPanel();
        if (panel instanceof HScrollPane)
            panel=((HScrollPane) panel).getViewport();
        
        // Se recupera la informaci�n correspondiente a las p�ginas. La configuraci�n
        // para cada p�gina se establece cada vez que se muestra.
        pages=conf.getPage();
    }
    
    /////////////////////////////////////////////////////////////////////////
    // M�todos para el secuenciamiento de p�ginas
    /////////////////////////////////////////////////////////////////////////
    
    public void gotoFrontEnd()
    {
        current=-1;
        currentPage=null;
        
        Container c;
        if (panel==null)
            c=scene;
        else
            c=panel;
        
        c.setVisible(false);
        c.removeAll();
        c.add(frontend);
        c.setVisible(true);
        c.validate();
        
        // Adem�s. el InputManager del frontend debe recibir el foco,
        // pero todav�a no est�n implementados los InputManager.
    }
    
    public void gotoFirstPage()
    {
        if (pages.size()==0)
            return;
        gotoPage(0);
    }
    
    public void gotoLastPage()
    {
        if (pages.size()==0)
            return;
        gotoPage(pages.size()-1);
    }
    
    public void gotoNextPage()
    {
        if ((pages.size()==0) || (current==pages.size()-1))
            return;
        gotoPage(current+1);
    }
    
    public void gotoPreviousPage()
    {
        if ((pages.size()==0) || (current==0))
            return;
        gotoPage(current-1);
    }
    
    public void gotoPage(int index)
    {
        if (current==index)
            return;
        
        try
        {
            PageType pt=(PageType) pages.get(index);
            
            // Hay que comprobar si esta permitido el acceso, viendo de que
            // paginas depende (elementos "lockedBy") y si estas estan "unlocked".
            java.util.List locks=pt.getLockedBy();
            for (int i=0;i<pages.size();i++)
            {
                if (i==index) continue;
                
                PageType temp=(PageType) pages.get(i);
                String id=temp.getId();
                
                if ((id==null) || (id.equals(""))) continue;
                if ((locks.contains(id)) && (temp.getState().equals("locked")))
                    throw new Exception("Acceso no permitido a la p�gina "+pt.getId());
            }
            
            // Si se permite el acceso, se viene por aqu�.
            
            String className=pt.getClassName();
            Class pageClass=loader.loadClass(className);
            
            current=index;
            currentPage=(Page) pageClass.newInstance();
            currentPage.setCourse(this);
            Container c;
            if (panel==null)
                c=scene;
            else
                c=panel;
            
            applyParameters(currentPage, pt.getParameters());
            
            c.setVisible(false);
            c.removeAll();
            c.add(currentPage);
            c.setVisible(true);
            c.validate();
        }
        catch (Exception ex)
        {
            System.out.println("gotoPage: "+ex.getMessage());
        }
    }
    
    /////////////////////////////////////////////////////////////////////////
    // M�todos para permitir/restringir el acceso a las p�ginas
    /////////////////////////////////////////////////////////////////////////
    
    public void lock()
    {
        // bloquea la p�gina actual, restringiendo el acceso a las que
        // dependan de ella.
        PageType pt=(PageType) pages.get(current);
        lock(pt.getId());
    }
    
    public void lock(String id)
    {
        for (int i=0;i<pages.size();i++)
        {
            PageType pt=(PageType) pages.get(i);
            if (id.equals(pt.getId()))
            {
                pt.setState("locked");
                break;
            }
        }
    }
    
    public void unlock()
    {
        PageType pt=(PageType) pages.get(current);
        unlock(pt.getId());
    }
    
    public void unlock(String id)
    {
        for (int i=0;i<pages.size();i++)
        {
            PageType pt=(PageType) pages.get(i);
            if (id.equals(pt.getId()))
            {
                pt.setState("unlocked");
                break;
            }
        }
    }
    
    /////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////
    
    // CAMBIAR ESTO PARA QUE TAMBIEN LOCALICE OBJETOS QUE NO HEREDEN DE
    // COMPONENT, COMO PUEDEN SER BEANS NO VISUALES!!! Hay que utilizar
    // el mecanismo de reflexi�n: se listan todos los objetos que tiene
    // un objeto dado, se ve si tienen m�todo getName... Como s�lo se puede
    // acceder a objetos p�blicos, hay que hacer que el Form Editor haga
    // p�blicas las variables generadas (SETTINGS->FORM EDITOR).
    private Component getByName(Container c, String name)
    {
        for (int i=0;i<c.getComponentCount();i++)
        {
            Component cmp=c.getComponent(i);
            //System.out.println(cmp);
            if (name.equals(cmp.getName()))
                return cmp;
            
            if (cmp instanceof Container)
            {
                Component cmp2=getByName((Container) cmp, name);
                if (cmp2!=null)
                    return cmp2;
            }
        }
        return null;
    }
    
    private void applyParameters(Container c, java.util.List params) throws Exception
    {
        for (int i=0;i<params.size();i++)
        {
            ParameterType pt=(ParameterType) params.get(i);
            String name=pt.getComponentName();
            String property=pt.getProperty();
            String value=pt.getValue();
            
            String methodName="set"+property.substring(0,1).toUpperCase()+property.substring(1);
            System.out.print("Buscando "+methodName+"->");
            Component cmp=getByName(c, name);
            System.out.println(cmp);
            Method mth=cmp.getClass().getMethod(methodName,new Class[]
            {String.class});
            Object temp[]=new Object[]
            {value};
            mth.invoke(cmp, temp);
        }
    }
    
    public static void main(String args[])
    {
        try
        {
            // args[0] indica el fichero del que leer la configuraci�n
            Course c=new Course();
            System.out.println(args.length);
            c.setConfigurationFile("file:/D:/Documents and Settings/raul/Escritorio/Java/PFCMartin/Teleco/demo/course.xml");
            
            HSceneFactory hsFactory = HSceneFactory.getInstance();
            scene = hsFactory.getBestScene(new HSceneTemplate());
            scene.setLayout(new GridLayout(1,1));
            
            scene.add(frontend);
            scene.addWindowListener(new WindowAdapter()
            {
                public void windowClosing(WindowEvent e)
                {
                    System.exit(0);
                }
            }
            );
            scene.setVisible(true);
            scene.validate();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
}
