/*
 * The_xmloperator_project Software License, Version 1.7
 *
 * Copyright (c) 2000 - 2003 The_xmloperator_project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *      "This product includes or uses software developped
 *       by The_xmloperator_project (http://www.xmloperator.net/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. Products derived from this software may not be called "xmloperator",
 *    nor may "xmloperator" appear in their name, without prior written
 *    permission. For written permission, please contact
 *    the xmloperator project administrator.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE_XMLOPERATOR_PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * Further information can be found on the project's site
 * (http://www.xmloperator.net/).
 */
package xmltorng.i2s;

import java.io.FileNotFoundException;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.io.PrintWriter;

import base.*;

import xmltorng.framework.document.relaxng.Name;
import xmltorng.framework.document.relaxng.Pattern;
import xmltorng.framework.document.relaxng.ElementDefinition;
import xmltorng.framework.document.relaxng.Schema;
import xmltorng.document.relaxng.impl.NameImpl;
import xmltorng.document.relaxng.impl.ElementDefinitionImpl;
import xmltorng.document.relaxng.impl.SchemaImpl;
import xmltorng.i2s.framework.RepeatableName;
import xmltorng.i2s.framework.PatternHandler;
import xmltorng.i2s.framework.PatternCategory;
import xmltorng.i2s.framework.ChoicePatternCategory;
import xmltorng.i2s.framework.GroupPatternCategory;
import xmltorng.i2s.impl.ElementPatternCategory;
import xmltorng.i2s.util.PatternExtractor;
import xmltorng.i2s.util.SchemaWriter;
import xmltorng.i2s.PatternCategoryFactory;

public final class SchemaGenerator implements PatternHandler {

    private ElementPatternCategory startPatternCategory = null;
    private final Map fromNameToPatternCategory = new HashMap();

    public static void GenerateXMLtoRNG(String xmlfilepath) {
        SchemaGenerator schemaGenerator = new SchemaGenerator();
        try {
            PatternExtractor.extractPatterns(xmlfilepath, (PatternHandler) schemaGenerator);
            //schemaGenerator.convertStat();
            schemaGenerator.printSchema();
        //System.exit(0);
        } catch (Exception ex) {
            MainWindow.ShowMessage("ERROR!", "Error while generating Relax NG schema!");
        }
    }

    public SchemaGenerator() {
    }

    private void printSchema() {

        Map fromNameToElementDefinition = new HashMap();
        Set nameSet = this.fromNameToPatternCategory.keySet();
        ElementDefinition[] elementDefinitions =
                new ElementDefinition[nameSet.size()];
        {
            Iterator iterator = nameSet.iterator();
            int index = 0;
            while (iterator.hasNext()) {
                Name name = (Name) iterator.next();
                PatternCategory patternCategory =
                        (PatternCategory) this.fromNameToPatternCategory.get(name);
                Pattern fullPattern;
                while (true) {
                    fullPattern =
                            patternCategory.fullPattern(fromNameToElementDefinition);
                    if (fullPattern != null) {
                        break;
                    }
                    patternCategory =
                            PatternCategoryFactory.generalizePatternCategory(patternCategory);
                    fullPattern =
                            patternCategory.fullPattern(fromNameToElementDefinition);
                }
                ElementDefinitionImpl elementDefinition =
                        (ElementDefinitionImpl) fromNameToElementDefinition.get(name);
                if (elementDefinition == null) {
                    elementDefinition = new ElementDefinitionImpl(name);
                    fromNameToElementDefinition.put(name, elementDefinition);
                }
                elementDefinition.setPattern(fullPattern);
                elementDefinitions[index++] = elementDefinition;
            }
        }
        SchemaImpl schema = new SchemaImpl(elementDefinitions);
        schema.setStart(
                this.startPatternCategory.fullPattern(fromNameToElementDefinition));
        try {
            PrintWriter out = new PrintWriter(MainWindow.XSDvirtualfilerng);
            SchemaWriter.printSchema(out, schema);
            out.close();
        } catch (FileNotFoundException ex) {
            MainWindow.ShowMessage("ERROR!", "Error while generating Relax NG schema!");
        }

    }

    ////////////////////////////////
    // PatternHandler implementation
    ////////////////////////////////
    public void pattern(
            boolean isRoot, Name containerName, Name[] attributeNames,
            boolean hasText, RepeatableName[] contentRepeatableNames) {
        PatternCategory patternCategory =
                (PatternCategory) this.fromNameToPatternCategory.get(containerName);
        PatternCategory newPatternCategory = patternCategory != null ? PatternCategoryFactory.addPatternToPatternCategory(
                patternCategory, attributeNames, hasText, contentRepeatableNames) : PatternCategoryFactory.createPatternCategory(
                attributeNames, hasText, contentRepeatableNames);
        if (newPatternCategory != patternCategory) {
            this.fromNameToPatternCategory.put(containerName, newPatternCategory);
        }
        if (isRoot) {
            if (this.startPatternCategory == null) {
                startPatternCategory = new ElementPatternCategory(containerName);
            } else {
                this.startPatternCategory.addElementName(containerName);
            }
        }

    }
}
