package es.ejie.frmk.presentacion.iu.taglib.html.menu.displayer;

import java.io.IOException;
import java.net.MalformedURLException;
import java.text.MessageFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;

import org.apache.struts.util.RequestUtils;

import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70Traza;
import es.ejie.frmk.presentacion.iu.taglib.base.Q70Constants;
import es.ejie.frmk.presentacion.iu.taglib.html.menu.base.Q70MenuComponent;

public class Q70DHTMLCascadeMenuDisplayer extends Q70MessageResourcesMenuDisplayer  {

	private static Q70Traza tr = Q70Traza.getSingleton();

	// main message format of the menu.  only 10 args max in jdk1.3 :( 
    private static MessageFormat menuMessage =
        new MessageFormat(
        		"oCMenu.makeMenu(''{0}'',''{1}'',''{2}'',''{3}'',''{4}'',''{5}''");
    private static final String SCRIPT_START =
        "<script language=\"javascript\" type=\"text/javascript\"> \r\n";
    private static final String SCRIPT_END = "</script>\n";
    private static final String END_STATEMENT =
        "\noCMenu.construct()\n";

    private static final String DEFAULT_JAVASCRIPTFILES ="dhtmlcascademenus.js,dhtmlcascademenu-config.js";

    protected String getJavaScriptsFilesDefault() {
    	return DEFAULT_JAVASCRIPTFILES;
    }
    
    /**
     * @param context
     * @param mapping
     * @throws JspException
     */
    public void init(PageContext context, Q70MenuDisplayerMapping mapping) throws JspException
    {
        super.init(context, mapping);
        
        try 
        {
            out.println(SCRIPT_START);
        } 
        catch (Exception e) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Q70DHTMLCascadeMenuDisplayer: Throwable recogida en metodo init():" + e.getMessage());
			}            
        }
    }

    /**
     * Prints the appropriate javascript for CoolMenu using \
     * <code>menuMessage</code> as the format.
     * @param menu
     * @param pageContext
     */
    public void display(Q70MenuComponent menu,PageContext pageContext) throws JspException, IOException 
    {        
    	this.pageContext=pageContext;
		super.setSecureId(menu.getSecureId());
		boolean allowed =(Q70Constants.MODE_NOTDISPLAYED!=super.getDisplayMode()?true:false);
      
		StringBuffer sb = new StringBuffer();
       	buildMenuString(menu, sb, allowed,pageContext);
      	out.print(sb);
    }

    /**
     * This will output the ending javascript statements defined in
     * <code>END_STATEMENT</code> and <code>SCRIPT_END</code>
     * @param context
     */
    public void end(PageContext context) 
    {
        try 
        {
            out.print(END_STATEMENT);
            out.print(SCRIPT_END);
        } 
        catch (Exception e) 
        {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Q70DHTMLCascadeMenuDisplayer: Throwable recogida en metodo end():" + e.getMessage());
			}          	
        }
    }

    /**
     * Metodo recursivo que construye el arbol de menus y submenus.
     * @param menu
     * @param sb
     * @param allowed
     * @param pageContext
     * @throws JspException
     */
    protected void buildMenuString(Q70MenuComponent menu, StringBuffer sb, boolean allowed,PageContext pageContext) throws JspException
    {
    	super.displayComponents(menu,pageContext);
		
        try{
    		setPageLocation(menu);
    	}catch (MalformedURLException m)
    	 {	                    
			if (tr.isTraceActive())	{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Action o forward incorrecto: " + m.getMessage());
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Estableciendo location a #");
			} 																			                    
            menu.setLocation("#");
        }
    	sb.append(menuMessage.format(getArgs(menu, allowed)));
        sb.append(",'");
        sb.append((menu.getOnclick() == null) ? EMPTY : menu.getOnclick());
        sb.append("')\n");

        Q70MenuComponent[] subMenus;
		try {
			subMenus = menu.getMenuComponents();
		} catch (Q70FrameworkException e) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Error en la obtención de los menus. Q70CascadeMenuDisplayer");
			}
			RequestUtils.saveException(pageContext, e);
			throw new JspException("Error en la obtención de los menus. Q70CascadeMenuDisplayer",e);

		}

        if (subMenus.length > 0) 
        {
            for (int i = 0; i < subMenus.length; i++) 
            {
				subMenus[i].setI18nKey(menu.getI18nKey());
				super.setSecureId(subMenus[i].getSecureId());
				subMenus[i].setPageContext(pageContext);
				subMenus[i].setListaI18nKey(this.getListaI18nKey());
												
				boolean subMenuAllowed =(Q70Constants.MODE_NOTDISPLAYED!=super.getDisplayMode()?true:false);
				buildMenuString(subMenus[i], sb, subMenuAllowed,pageContext);                
            }
        }
    }

    /**
     * @param menu
     * @param allowed
     * @return
     * @throws JspException
     */
    protected String[] getArgs(Q70MenuComponent menu, boolean allowed) throws JspException{
        String[] args = new String[10];
        args[0] = menu.getName().indexOf("null")==0?obtenerNombreFuncional(menu):menu.getName();
        args[1] = getParentName(menu);
        args[2] = getTitle(menu);
        args[3] = (menu.getUrl() == null) ? EMPTY : ((allowed) ? menu.getUrl() : EMPTY);
        args[4] = getTarget(menu);
        args[5] = EMPTY;
        args[6] = EMPTY;
        return args;
    }

    /**
     * Metodo para obtener un nombre de menu aleatorio, ya que en el script de construcción de cascade menus, no 
     * se puede repetir ningún nombre de menu
     * @return
     */
    private String obtenerNombreFuncional(Q70MenuComponent menu){
    	Pattern patron = Pattern.compile("null{1}");
    	Matcher matcher = patron.matcher(menu.getName());
    	return getParentName(menu)+matcher.replaceAll("item");
    }
    
    /**
     * Return a translated title for the menu item that will contain
     * the <code>TOP_IMAGE</code> javscript variable if it is a parent
     * menu with sub menus, or the <code>SUB_IMAGE</code> variable if it
     * is a sub menu with sub menus.
     * @param menu
     * @throws JspException
     */
    protected String getTitle(Q70MenuComponent menu) throws JspException{
        return getMessage(menu.getListaI18nKey(), menu.getTitle());
    }

    /**
     * @param menu
     * @return String 
     */
    protected String getParentName(Q70MenuComponent menu) {
        String name = null;

        if (menu.getParentMenu() == null) {
            name = "";
        } else {
            name = menu.getParentMenu().getName();
        }
        
        return name;
    }

    /**
     * @param menu
     * @return String 
     */
    protected String getTarget(Q70MenuComponent menu) {
        String theTarget = super.getTarget(menu);

        if (target == null) {
            theTarget = EMPTY;
        }

        return theTarget;
    }

}
