//----------------------------------------------------------------------------
//
// Module:      ContentDocumentHandler.java      
//
// Description: Handle all non container, non menu elements of a frame or dialog
//
// FESI Copyright (c) Jean-Marc Lugrin, 2000
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//----------------------------------------------------------------------------

package FesiForm;

import org.xml.sax.*;
import FESI.jslib.*;

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.rtf.RTFEditorKit;
import java.awt.*;
import java.util.Vector;
import java.io.IOException;


public class ContentDocumentHandler extends DefaultDocumentHandler 
                                    implements DocumentHandler {

    DocumentHandler previousDocumentHandler;
    String contentType = null;
    Container container = null;
    Component component = null; // for inside components as menu items
    String containerName;       // to match end
    String containedName = null;
    Container menuContainer;
    ButtonGroup buttonGroup = null;
    int limited;          // > 0 limit the number of item which can be added to current container
    int numberOfComponents = -1; // First one is the container and will increase it to 0 
     
    
    public ContentDocumentHandler(String cn,
                                    DocumentHandler pdh,
                                    Container mc,
                                    Container ct, 
                                    GuiContext gc, 
                                    boolean trace,
                                    int l) {
        super(gc, trace);
        this.containerName = cn;
        this.previousDocumentHandler = pdh;
        this.menuContainer = mc;
        this.container = ct;
        this.limited = l;
    }
  
      
    // Receive notification of the beginning of an element.
    public void startElement(String name, AttributeList atts) throws SAXException {
        if (trace) System.out.println("CONTENT START_ELEMENT: <" + name + ">, " + 
                                         atts.getLength() + " attribute(s)");
        // <!ELEMENT JFrame (JMenuBar|JPanel|JTextField|JPasswordField|JLabel|JButton|JCheckBox|JRadioButton)* >
        // <!ELEMENT JPanel (JMenuBar|JPanel|JTextField|JPasswordField|JLabel|JButton|JCheckBox|JRadioButton)* >
        numberOfComponents ++;
        if (limited>0 && numberOfComponents>limited) {
            throw new SAXException("Container " + containerName + " only accepts " + limited + " components");
        }
        if (name.equals(containerName)) {
            // nothing                            
        } else if (name.equals("JComponent")) {
            String creationScript = getAttribute("creationScript", atts);
            if (creationScript == null) {
                throw new SAXException("Missing creation script in JComponent");
            }
            Object o;
            try {
                 o = guiContext.global.evalAsFunction(creationScript); 
            } catch (JSException ex) {
                 throw new SAXException("Cannot evaluate CreationScript: " + ex.getMessage(), ex);
            }
            if (! (o instanceof JComponent)) {
                throw new SAXException("creationScript did not return a JSComponent");
            }
            JComponent jl = (JComponent)o;
            processOptionalId(jl, atts);
            processComponentAttributes(jl, atts);
            processJComponentAttributes(jl, atts);
            addConstrained(container, jl, atts);
            processScript(jl, saveScript(jl, atts));
            
        } else if (name.equals("JLabel")) {
            JLabel jl = (JLabel) createComponent(JLabel.class, atts);
            processOptionalId(jl, atts);
            processComponentAttributes(jl, atts);
            processJComponentAttributes(jl, atts);
            processLabelAttributes(jl, atts);
            addConstrained(container, jl, atts);
            processScript(jl, saveScript(jl, atts));
            
        } else if (name.equals("JButton")) {
            JButton jb = (JButton) createComponent(JButton.class, atts);
            processOptionalId(jb, atts);
            processComponentAttributes(jb, atts);
            processJComponentAttributes(jb, atts);
            processAbstractButtonAttributes(jb, atts);
            addConstrained(container, jb, atts);
            processScript(jb, saveScript(jb, atts));
            
        } else if (name.equals("JRadioButton")) {
            JRadioButton jb = (JRadioButton) createComponent(JRadioButton.class, atts);
            processOptionalId(jb, atts);
            processComponentAttributes(jb, atts);
            processJComponentAttributes(jb, atts);
            processAbstractButtonAttributes(jb, atts);
            if (buttonGroup==null) buttonGroup = new ButtonGroup();
            buttonGroup.add(jb);
            addConstrained(container, jb, atts);
            processScript(jb, saveScript(jb, atts));
            
        } else if (name.equals("JCheckBox")) {
            JCheckBox jb = (JCheckBox) createComponent(JCheckBox.class, atts);
            processOptionalId(jb, atts);
            processComponentAttributes(jb, atts);
            processJComponentAttributes(jb, atts);
            processAbstractButtonAttributes(jb, atts);
            addConstrained(container, jb, atts);
            processScript(jb, saveScript(jb, atts));
            
        } else if (name.equals("JList")) {
            JList jl = (JList) createComponent(JList.class, atts);
            processOptionalId(jl, atts);
            processComponentAttributes(jl, atts);
            processJComponentAttributes(jl, atts);
            processListAttributes(jl, atts);
            addConstrained(container, jl, atts);
            processScript(jl, saveScript(jl, atts));

        } else if (name.equals("JComboBox")) {
            JComboBox jl = (JComboBox) createComponent(JComboBox.class, atts);
            processOptionalId(jl, atts);
            processComponentAttributes(jl, atts);
            processJComponentAttributes(jl, atts);
            processComboBoxAttributes(jl, atts);
            addConstrained(container, jl, atts);
            processScript(jl, saveScript(jl, atts));

        } else if (name.equals("JMenuBar")) {
                DocumentHandler dh = 
                    new JMenuBarDocumentHandler(name, 
                                     this, 
                                     (menuContainer == null) ? container : menuContainer, 
                                     guiContext, 
                                     trace);
                guiContext.parser.setDocumentHandler(dh);
                containedName = name;
                dh.startElement(name, atts);
            
        } else if (name.equals("JPanel")) {
                DocumentHandler dh = 
                    new JPanelDocumentHandler(name, this, container, guiContext, trace);
                guiContext.parser.setDocumentHandler(dh);
                containedName = name;
                dh.startElement(name, atts);
            
        } else if (name.equals("JToolBar")) {
                DocumentHandler dh = 
                    new JToolBarDocumentHandler(name, this, container, guiContext, trace);
                guiContext.parser.setDocumentHandler(dh);
                containedName = name;
                dh.startElement(name, atts);

        } else if (name.equals("JScrollPane")) {
                DocumentHandler dh = 
                    new JScrollPaneDocumentHandler(name, this, container, guiContext, trace);
                guiContext.parser.setDocumentHandler(dh);
                containedName = name;
                dh.startElement(name, atts);

        } else if (name.equals("JSplitPane")) {
                DocumentHandler dh = 
                    new JSplitPaneDocumentHandler(name, this, container, guiContext, trace);
                guiContext.parser.setDocumentHandler(dh);
                containedName = name;
                dh.startElement(name, atts);

        } else if (name.equals("JTextField")) {
            JTextField jtf = (JTextField) createComponent(JTextField.class, atts);
            processOptionalId(jtf, atts);
            processComponentAttributes(jtf, atts);
            processJComponentAttributes(jtf, atts);
            processTextComponentAttributes(jtf, atts);
            processHALIGN(jtf, atts);
            processCOLUMNStf(jtf, atts);
            addConstrained(container, jtf, atts);
            processScript(jtf, saveScript(jtf, atts));

        } else if (name.equals("JPasswordField")) {
            JPasswordField jtf = (JPasswordField) createComponent(JPasswordField.class, atts);
            processOptionalId(jtf, atts);
            processComponentAttributes(jtf, atts);
            processJComponentAttributes(jtf, atts);
            processTextComponentAttributes(jtf, atts);
            processHALIGN(jtf, atts);
            processCOLUMNStf(jtf, atts);
            addConstrained(container, jtf, atts);
            processScript(jtf, saveScript(jtf, atts));

        } else if (name.equals("JTextArea")) {
            JTextArea jtf = (JTextArea) createComponent(JTextArea.class, atts);
            processOptionalId(jtf, atts);
            processComponentAttributes(jtf, atts);
            processJComponentAttributes(jtf, atts);
            processTextComponentAttributes(jtf, atts);
            processCOLUMNSta(jtf, atts);
            addConstrained(container, jtf, atts);
            processScript(jtf, saveScript(jtf, atts));

        } else if (name.equals("JEditorPane")) {
            JEditorPane jtf = (JEditorPane) createComponent(JEditorPane.class, atts);
            processOptionalId(jtf, atts);
            processComponentAttributes(jtf, atts);
            processJComponentAttributes(jtf, atts);
            processTextComponentAttributes(jtf, atts);
            processEDITORKIT(jtf, atts);
            processCONTENTTYPE(jtf, atts);
            processPAGE(jtf, atts);
            addConstrained(container, jtf, atts);
            processScript(jtf, saveScript(jtf, atts));

        } else {
             throw new SAXException("Unexpected ELEMENT in content ignored: " + name);
        }
    }

    // Receive notification of the end of an element. 
    public void endElement(String name) throws SAXException {
        if (trace) System.out.println("CONTENT END_ELEMENT: </" + name + ">");
        if (name.equals(containerName)) {
            previousDocumentHandler.endElement(name);
        } else if (containedName != null && name.equals(containedName)) {
            containedName = null;
            guiContext.parser.setDocumentHandler(this);
        }
    }


    protected void processTextComponentAttributes(JTextComponent jl, AttributeList atts) throws SAXException {
         processTEXTtc(jl, atts);
         processEDITABLEtc(jl, atts);
         processDISABLEDTEXTCOLOR(jl, atts);
         processSELECTEDTEXTCOLOR(jl, atts);
         processSELECTIONCOLOR(jl, atts);
         processFOCUSACCELERATOR(jl, atts);
    }
    
    
    protected void processListAttributes(JList jl, AttributeList atts) throws SAXException {
         processFIXEDCELLWIDTH(jl, atts);
         processSELECTIONBACKGOUND(jl, atts);
         processSELECTIONFOREGOUND(jl, atts);
    }

    
    protected void processLabelAttributes(JLabel jl, AttributeList atts) throws SAXException{
         processTEXTl(jl, atts);
         processJLabelICON(jl, atts);
         processLABELFOR(jl, atts);
         processDISPLAYEDMNEMONIC(jl, atts);
    }
    
    protected void processComboBoxAttributes(JComboBox jl, AttributeList atts) throws SAXException {
         processEDITABLEcb(jl, atts);
         processMAXIMUMROWCOUNT(jl, atts);
    }

    protected char processFOCUSACCELERATOR(JTextComponent cp, AttributeList atts) throws SAXException {
         String s = getAttribute("focusAccelerator", atts);
         char c = '\0';
         if (s != null && s.length()>0) {
             c = s.charAt(0);
             if (trace) System.out.println("  FOCUSACCELERATOR: " + c);         
             cp.setFocusAccelerator(c);
         }
         return c;
    }

    protected char processDISPLAYEDMNEMONIC(JLabel cp, AttributeList atts) throws SAXException {
         String s = getAttribute("displayedMnemonic", atts);
         char c = '\0';
         if (s != null && s.length()>0) {
             c = s.charAt(0);
             if (trace) System.out.println("  DISPLAYEDMNEMONIC: " + c);         
             cp.setDisplayedMnemonic(c);
         }
         return c;
    }

     protected Component processLABELFOR(JLabel jl, AttributeList atts) throws SAXException {
         String id = getAttribute("labelFor", atts);
         Component cp = null;
         if (id != null) {
             Object o = guiContext.getById(id);
             if (id==null) {
                 throw new SAXException("Component '" + id + "' not defined");
             }
             if (!(o instanceof Component)) {
                 throw new SAXException("Object '" + id + "' is not a componenr");
             }
             cp = (Component) o;
             if (trace) System.out.println("  LABELFOR: " + id);         
             jl.setLabelFor(cp);
         }
         return cp;
    }


     protected Color processDISABLEDTEXTCOLOR(JTextComponent cp, AttributeList atts) throws SAXException {
         String c = getAttribute("disabledTextColor", atts);
         Color color = null;
         if (c != null) {
             color = colorByName(c);
             if (trace) System.out.println("  DISABLEDTEXTCOLOR: " + c);         
             if (color != null) cp.setDisabledTextColor(color);
         }
         return color;
    }

    protected Color processSELECTEDTEXTCOLOR(JTextComponent cp, AttributeList atts) throws SAXException {
         String c = getAttribute("selectedTextColor", atts);
         Color color = null;
         if (c != null) {
             color = colorByName(c);
             if (trace) System.out.println("  SELECTEDTEXTCOLOR: " + c);         
             if (color != null) cp.setSelectedTextColor(color);
         }
         return color;
    }

    protected Color processSELECTIONCOLOR(JTextComponent cp, AttributeList atts) throws SAXException {
         String c = getAttribute("selectionColor", atts);
         Color color = null;
         if (c != null) {
             color = colorByName(c);
             if (trace) System.out.println("  SELECTIONCOLOR: " + c);         
             if (color != null) cp.setSelectionColor(color);
         }
         return color;
     }


     protected Color processSELECTIONFOREGOUND(JList cp, AttributeList atts) throws SAXException {
         String c = getAttribute("selectionForeground", atts);
         Color color = null;
         if (c != null) {
             color = colorByName(c);
             if (trace) System.out.println("  processSELECTIONFOREGOUND: " + c);         
             if (color != null) cp.setSelectionForeground(color);
         }
         return color;
     }


     protected Color processSELECTIONBACKGOUND(JList cp, AttributeList atts) throws SAXException {
         String c = getAttribute("selectionBackground", atts);
         Color color = null;
         if (c != null) {
             color = colorByName(c);
             if (trace) System.out.println("  processSELECTIONBACKGOUND: " + c);         
             if (color != null) cp.setSelectionBackground(color);
         }
         return color;
     }

     protected String processTEXTl(JLabel jl, AttributeList atts) {
         String text = getAttribute("text", atts);
         if (text != null) {
             if (trace) System.out.println("  TEXT: "+text);
             jl.setText(text);
         }
         return text;
     }

     protected String processTEXTtc(JTextComponent jl, AttributeList atts) {
         String text = getAttribute("text", atts);
         if (text != null) {
             if (trace) System.out.println("  TEXT: "+text);
             jl.setText(text);
         }
         return text;
     }

     protected Icon processJLabelICON(JLabel jb, AttributeList atts) {
         int halign = JTextField.LEFT;
         Icon icon = null;
         String iconString = getAttribute("icon", atts);
         if (iconString != null) {
             icon = new ImageIcon(iconString);
             if (trace) System.out.println("  ICON: "+iconString);
             jb.setIcon(icon);
         }
         return icon;
     }

     protected int processCOLUMNStf(JTextField jtf, AttributeList atts) throws SAXException {
         int columns = 0;
         String columnsString = getAttribute("columns", atts);
         if (columnsString != null) {
             try {
                 columns = Integer.parseInt(columnsString);
                 if (trace) System.out.println("  COLUMNS: "+columns);
                 jtf.setColumns(columns);
             } catch (NumberFormatException ignore) {
                 throw new SAXException("Bad columns integer: " + columnsString);
             }
         }
         return columns;

     }

     protected int processFIXEDCELLWIDTH(JList jtf, AttributeList atts) throws SAXException {
         int columns = 0;
         String columnsString = getAttribute("fixedCellWidth", atts);
         if (columnsString != null) {
             try {
                 columns = Integer.parseInt(columnsString);
                 if (trace) System.out.println("  FIXEDCELLWIDTH: "+columns);
                 jtf.setFixedCellWidth(columns);
             } catch (NumberFormatException ignore) {
                 throw new SAXException("Bad width integer: " + columnsString);
             }
         }
         return columns;
     }
     
     protected int processMAXIMUMROWCOUNT(JComboBox jtf, AttributeList atts) throws SAXException {
         int columns = 0;
         String columnsString = getAttribute("maximumRowCount", atts);
         if (columnsString != null) {
             try {
                 columns = Integer.parseInt(columnsString);
                 if (trace) System.out.println("  MAXIMUMROWCOUNT: "+columns);
                 jtf.setMaximumRowCount(columns);
             } catch (NumberFormatException ignore) {
                 throw new SAXException("Bad row count integer: " + columnsString);
             }
         }
         return columns;
     }

     protected int processCOLUMNSta(JTextArea jtf, AttributeList atts) throws SAXException {
         int columns = 0;
         String columnsString = getAttribute("columns", atts);
         if (columnsString != null) {
             try {
                 columns = Integer.parseInt(columnsString);
                 if (trace) System.out.println("  COLUMNS: "+columns);
                 jtf.setColumns(columns);
             } catch (NumberFormatException ignore) {
                 throw new SAXException("Bad columns integer: " + columnsString);
             }
         }
         return columns;
     }
     
     protected float processHALIGN(JTextField jtf, AttributeList atts) throws SAXException {
         int halign = JTextField.LEFT;
         String halignString = getAttribute("halign",atts);
         if (halignString != null) {
             halign = jTextFieldAlignmentByName(halignString);
             if (trace) System.out.println("  HALIGN: "+halign);
             jtf.setHorizontalAlignment(halign);
         }
         return halign;
     }


     protected boolean processEDITABLEtc(JTextComponent jb, AttributeList atts) throws SAXException {
         boolean editable = false;
         String tf = getAttribute("editable", atts);
         if (tf != null) {
             tf = tf.toLowerCase();
             if (trace) System.out.println("  EDITABLE: " + tf);
             if (tf.equals("true")) {
                 editable = true;
             } else if (!tf.equals("false")) {
                 throw new SAXException("Bad true/false value for editable: " + tf);
             }
             jb.setEditable(editable);
         }
         return editable;
     }

     protected boolean processEDITABLEcb(JComboBox jb, AttributeList atts) throws SAXException {
         boolean editable = false;
         String tf = getAttribute("editable", atts);
         if (tf != null) {
             tf = tf.toLowerCase();
             if (trace) System.out.println("  EDITABLE: " + tf);
             if (tf.equals("true")) {
                 editable = true;
             } else if (!tf.equals("false")) {
                 throw new SAXException("Bad true/false value for editable: " + tf);
             }
             jb.setEditable(editable);
         }
         return editable;
     }

     
     protected String processEDITORKIT(JEditorPane ep, AttributeList atts) throws SAXException {
         String value = getAttribute("editorKit", atts);
         if (value != null) {
             if (trace) System.out.println("  EDITORKIT: "+value);
             value=value.toLowerCase();
             if (value.equals("default")) {
                 ep.setEditorKit(new DefaultEditorKit());
             } else if (value.equals("styled")) {
                 ep.setEditorKit(new StyledEditorKit());
             } else if (value.equals("html")) {
                 ep.setEditorKit(new HTMLEditorKit());
             } else if (value.equals("rtf")) {
                 ep.setEditorKit(new RTFEditorKit());
             } else {
                 throw new SAXException("Unrecognized editor kit: "+ value);
             }
         }
         return value;
     }

     protected String processCONTENTTYPE(JEditorPane ep, AttributeList atts) {
         String value = getAttribute("contentType", atts);
         if (value != null) {
             if (trace) System.out.println("  CONTENTTYPE: "+value);
             ep.setContentType(value);
         }
         return value;
     }

     protected String processPAGE(JEditorPane ep, AttributeList atts) {
         String value = getAttribute("page", atts);
         if (value != null) {
             if (trace) System.out.println("  PAGE: "+value);
             try {
                 ep.setPage(value);
             } catch (IOException ex) {
                 ep.setText("Could not load page '" + value + "'\nIOException: " + ex.toString());
             }
         }
         return value;
     }

 }