/*
 * (C) Copyright IBM Corp. 1997-1998  All rights reserved.
 *
 * US Government Users Restricted Rights Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 * The program is provided "as is" without any warranty express or
 * implied, including the warranty of non-infringement and the implied
 * warranties of merchantibility and fitness for a particular purpose.
 * IBM will not be liable for any damages suffered by you as a result
 * of using the Program. In no event will IBM be liable for any
 * special, indirect or consequential damages or lost profits even if
 * IBM has been advised of the possibility of their occurrence. IBM
 * will not be liable for any third party claims against you.
 */

package com.ibm.xml.sample;

import com.ibm.xml.parser.*;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

/**
 * A sample of `Validating Generation'.
 *
 * @version 1.1
 * @author TAMURA Kent &lt;kent@trl.ibm.co.jp&gt;
 */
public class GeneratingSample extends WindowAdapter implements Runnable {
    static final String S_EOC = "******* End of content *******";
    static final String S_TEXT = "**** any text ****";

    public static void main(String[] argv) {
        new GeneratingSample(argv);
    }

    DTD m_dtd;
    Hashtable m_hash;
    Frame m_frame;
    Vector m_allel;
    TextArea m_text;
    TXElement m_root;

    GeneratingSample(String[] argv) {
        try {
            String fname = null;
            for (int i = 0;  i < argv.length;  i ++) {
                if ('-' != argv[i].charAt(0)) {
                    fname = argv[i];            // DTD filename
                } else {
                    System.err.println("Warning: Unknown option: "+argv[i]);
                }
            }
                                                // Load DTD without a document
            Parser pc = new Parser(fname);
            m_dtd = pc.readDTDStream(pc.getInputStream(fname, null, fname));

            if (null == m_dtd) {
                System.err.println("no DTD");
            } else {
                m_allel = new Vector();
                Enumeration en = m_dtd.getElementDeclarations();
                while (en.hasMoreElements()) {
                    ElementDecl ed = (ElementDecl)en.nextElement();
                    m_allel.addElement(ed.getName());
                } // v has all names of declared elements.

                                                // Make hash which has all elements.
                m_hash = m_dtd.prepareTable((String)m_allel.elementAt(0));
                en = m_allel.elements();
                while (en.hasMoreElements()) {
                    String n = (String)en.nextElement();
                    m_hash.put(n, new InsertableElement(n));
                }

                m_frame = new Frame("Generating Sample");
                m_frame.addWindowListener(this);
                m_frame.add(m_text = new TextArea(), "Center");
                m_frame.pack();
                m_frame.setSize(384, 512);
                Dimension di = Toolkit.getDefaultToolkit().getScreenSize();
                m_frame.setLocation((di.width-384)/2, (di.height-512)/2);
                m_frame.show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

                                                // WindowAdapter
    public void windowOpened(WindowEvent e) {
        new Thread(this).start();
    }
                                                // WindowAdapter
    public void windowClosing(WindowEvent e) {
        m_frame.dispose();
        System.exit(0);
    }

    void out() {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        Format.printElement(m_root, pw, null, 0, 2);
        pw.close();
        m_text.setText(sw.toString());
    }

                                                // Runnable
    public void run() {
        m_text.setText("Select root element name from the list on the dialog.");
        String rootname = choice(m_frame, "Select root element", sortStringVector(m_allel));
        m_root = new TXElement(rootname);
        out();
        construct(m_root);
        System.err.println("Complete.");
    }

    void construct(TXElement parent) {
        switch (m_dtd.getContentType(parent.getName())) {
          case -1:
            System.err.println("This element "+parent.getName()+" is not declared.");
            break;
          case ElementDecl.EMPTY:
            System.err.println("This element "+parent.getName()+" is declared as EMPTY.");
            break;
          case ElementDecl.ANY:
            System.err.println("This element "+parent.getName()+" is declared as ANY.");
            break;

          case ElementDecl.MODEL_GROUP:
            while (true) {
                Vector vec = makeAvailables(m_dtd, parent, m_hash);
                if (0 == vec.size())  break;
                if (1 == vec.size() && S_EOC.equals((String)vec.elementAt(0)))
                    break;

                vec = sortNames(m_dtd.makeContentElementList(parent.getName()), vec);

                String chi = choice(m_frame, "Select next child of "+parent.getName(), vec);
                if (chi.equals(DTD.CM_PCDATA) || chi.equals(S_TEXT)) {
                    parent.addElement(new TXText("Some text"));
                    out();
                } else if (chi.equals(S_EOC)) {
                    break;
                } else {
                    TXElement child = new TXElement(chi);
                    parent.addElement(child);
                    out();
                    construct(child);
                }
            }
            break;
          default:
            System.err.println("Internal Error.");
        }
    }

    static Vector makeAvailables(DTD dtd, TXElement el, Hashtable hash) {
        Vector v = new Vector();
        dtd.getAppendableElements(el, hash);
        if (((InsertableElement)hash.get(DTD.CM_ERROR)).status) {
            System.err.println("Element has wrong structure.");
        } else {
            Enumeration en = hash.elements();
            while (en.hasMoreElements()) {
                InsertableElement ie = (InsertableElement)en.nextElement();
                if (!ie.name.equals(DTD.CM_ERROR)
                    && ie.status) {
                    if (ie.name.equals(DTD.CM_EOC))
                        v.addElement(S_EOC);
                    else
                        v.addElement(ie.name);
                }
            }
        }
        return v;
    }

    static String choice(Frame parent, String tit, Vector v) {
        final Dialog f = new Dialog(parent, tit, true);
        final List list = new List();
        //v = sortStringVector(v);
        Enumeration en = v.elements();
        while (en.hasMoreElements()) {
            String el = (String)en.nextElement();
            list.add(el.equals(DTD.CM_PCDATA) ? S_TEXT : el);
        }
        Button btok = new Button("OK");
        f.add(list, "Center");
        f.add(btok, "South");
        btok.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (null != list.getSelectedItem())
                    f.dispose();//setVisible(false);
                else
                    System.err.println("Select 1 item!");
            }
        });
        f.pack();
        f.setSize(256, 384);
        f.show();

        System.err.println("SELECTED: "+list.getSelectedItem());
        return list.getSelectedItem();
    }




    //
    //  utility methods
    //
    static private void fall(String[] pd, int n, int i) {
        int j = 2*i+1;
        if (j < n) {				// left exists
            if (j+1 < n) {			// right exists too 
	    					// j: bigger
                if (0 > pd[j].compareTo(pd[j+1]))
                    j = 2*i+2;
            } else {				// only left
            }
            if (0 > pd[i].compareTo(pd[j])) {
                                                // the child is bigger
                String t = pd[i];
                pd[i] = pd[j];
                pd[j] = t;
                fall(pd, n, j);
            }
        }
    }
    static void heapSort(String[] pd) {
        int i;
        for (i = pd.length/2;  i >= 0;  i--) {  // Make heap
            fall(pd, pd.length, i);
        }
        for (i = pd.length-1;  i > 0;  i--) {
            String t = pd[0];
            pd[0] = pd[i];
            pd[i] = t;
            fall(pd, i, 0);
        }
    }

    static Vector sortStringVector(Vector v) {
        String[] as = new String[v.size()];
        v.copyInto(as);
        heapSort(as);
        v.removeAllElements();
        v.ensureCapacity(as.length);
        for (int i = 0;  i < as.length;  i ++)
            v.addElement(as[i]);
        return v;
    }

    static Vector sortNames(Vector base, Vector v) {
        if (null == base) {
            return sortStringVector(v);
        }
        Vector ret = new Vector();
        for (int i = 0;  i < base.size();  i ++) {
            String n = (String)base.elementAt(i);
            int ind = v.indexOf(n);
            if (0 <= ind) {
                ret.addElement(n);
                v.removeElementAt(ind);
            }
        }
        for (int i = 0;  i < v.size();  i ++) {
            ret.addElement(v.elementAt(i));
        }
        return ret;
    }
}
