/*
 * Copyright 2006 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.dev.util.xml;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.util.tools.Utility;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import java.io.IOException;
import java.io.Reader;
import java.util.Stack;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

/**
 * Somewhat general-purpose SAX-style XML parser that uses reflection and calls
 * into your "schema" classes. For example, the element
 * <code>&lt;server-name&gt;</code> maps to the method
 * <code>server_name</code>. Note that the mapping is one-way, hyphens become
 * underscores, but then you don't really want to use underscores in XML tag
 * names anyway, do you? Also, all mixed content text (that is, text inside
 * elements) is ignored, so think attributes.
 */
public final class ReflectiveParser {
  
  private static SAXParserFactory saxParserFactory;

  private static synchronized SAXParser createNewSaxParser() throws ParserConfigurationException,
      SAXException {
    if (saxParserFactory == null) {
      Thread currentThread = Thread.currentThread();
      ClassLoader oldClassLoader = currentThread.getContextClassLoader();
      try {
        // use system ClassLoader to avoid using expensive GWT ClassLoader
        currentThread.setContextClassLoader(ClassLoader.getSystemClassLoader());
        saxParserFactory = SAXParserFactory.newInstance();
        saxParserFactory.setFeature(
            "http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
      } finally {
        currentThread.setContextClassLoader(oldClassLoader);
      }
    }
    return saxParserFactory.newSAXParser();
  }

  private static final class Impl extends DefaultHandler {

    private Locator locator;

    private Reader reader;

    private Stack<Schema> schemaLevels = new Stack<Schema>();

    private Stack<Object[]> argStack = new Stack<Object[]>();

    private Schema defaultSchema;

    @Override
    public void characters(char[] ch, int start, int length)
        throws SAXException {
      int lineNumber = locator.getLineNumber();

      // Get the active schema level.
      //
      Schema schemaLevel = getTopSchemaLevel();

      if (schemaLevel == null) {
        // It is legitimate to run out of schemaLevels if there is an empty node
        // in the XML. Otherwise, it indicates that the user has specified
        // extra stuff in the body of the XML tag that we don't understand.
        //
        for (int i = 0; i < length; i++) {
          if (!Character.isWhitespace(ch[i + start])) {
            throw new SAXException("Unexpected XML data found: "
                + String.valueOf(ch, start, length));
          }
        }
        // This is okay. Nothing special to do.
        //
        return;
      }
      // Find the precomputed handler class info.
      //
      Class<? extends Schema> slc = schemaLevel.getClass();
      HandlerClassInfo classInfo = HandlerClassInfo.getClassInfo(slc);
      assert (classInfo != null); // would've thrown if unregistered
      HandlerMethod method = classInfo.getTextMethod();
      if (method == null) {
        // This is okay. Nothing special to do.
        //
        return;
      }

      // Call the handler.
      //
      try {
        // The line number is at the end of the text; subtract however many
        // newlines the text contains.
        for (int i = start, e = start + length, l = e - 1; i < e; ++i) {
          switch (ch[i]) {
            case '\r':
              if (i < l && ch[i + 1] == '\n') {
                continue;
              }
              // Intentional fall-through
            case '\n':
              --lineNumber;
          }
        }
        final String text = String.valueOf(ch, start, length);
        method.invokeText(lineNumber, text, schemaLevel);
      } catch (UnableToCompleteException e) {
        throw new SAXException(e);
      }
    }

    @Override
    public void endElement(String namespaceURI, String localName, String elem)
        throws SAXException {
      int lineNumber = locator.getLineNumber();

      // Get the active schema level.
      //
      Schema schemaLevel = popLevel();
      if (schemaLevel == null) {
        // This was an unexpected child, but we already informed the schema
        // about it during startElement(), so we can just return.
        //
        return;
      }

      // Find the precomputed handler class info.
      //
      Class<? extends Schema> slc = schemaLevel.getClass();
      HandlerClassInfo classInfo = HandlerClassInfo.getClassInfo(slc);
      assert (classInfo != null); // would've thrown if unregistered
      HandlerMethod method = classInfo.getEndMethod(elem);
      if (method == null) {
        // This is okay. Nothing special to do.
        //
        return;
      }

      Object[] args = getCurrentArgs();
      if (args != null) {
        // Call the handler using the same arguments we send to the "begin"
        // handler.
        //
        try {
          method.invokeEnd(lineNumber, elem, schemaLevel, args);
        } catch (UnableToCompleteException e) {
          throw new SAXException(e);
        }
      }
    }

    @Override
    public void setDocumentLocator(Locator locator) {
      this.locator = locator;
    }

    @Override
    public void startElement(String namespaceURI, String localName,
        String elemName, Attributes atts) throws SAXException {
      int lineNumber = locator.getLineNumber();

      // Get the active schema level.
      //
      Schema schemaLevel = getTopSchemaLevel();
      if (schemaLevel == null) {
        // This means that children should not appear at this level.
        //
        Schema nextToTop = getNextToTopSchemaLevel();

        // Push another null since this child shouldn't have children either.
        //
        setArgsAndPushLevel(null, null);

        // Inform the next-to-top schema level about this.
        //
        try {
          nextToTop.onUnexpectedChild(lineNumber, elemName);
        } catch (UnableToCompleteException e) {
          throw new SAXException(e);
        }

        return;
      }

      // Find the precomputed handler class info.
      //
      Class<? extends Schema> slc = schemaLevel.getClass();
      HandlerClassInfo classInfo = HandlerClassInfo.getClassInfo(slc);
      HandlerMethod method = classInfo.getStartMethod(elemName);

      if (method == null) {
        // This is not okay. The schema has to at least have a stub
        // to indicate that a particular tag is allowed.
        //
        try {
          schemaLevel.onUnexpectedElement(lineNumber, elemName);
        } catch (UnableToCompleteException e) {
          throw new SAXException(e);
        }

        // Since we don't know about this element, assume it should not have
        // children either.
        //
        setArgsAndPushLevel(null, null);

        return;
      }

      HandlerArgs args = method.createArgs(schemaLevel, lineNumber, elemName);

      // For each attribute found, try to match it up to a parameter.
      //
      for (int i = 0, n = atts.getLength(); i < n; ++i) {
        String attrName = atts.getQName(i);
        String attrValue = atts.getValue(i);

        if (!args.setArg(attrName, attrValue)) {
          // Inform the handler that the attribute was unknown.
          //
          try {
            schemaLevel.onUnexpectedAttribute(lineNumber, elemName, attrName,
                attrValue);
          } catch (UnableToCompleteException e) {
            throw new SAXException(e);
          }
        }
      }

      // Check for unset parameters.
      //
      int missingCount = 0;
      for (int i = 0, n = args.getArgCount(); i < n; ++i) {
        if (!args.isArgSet(i)) {
          // Inform the handler that the required attribute was not set.
          // It might throw, but it also might not.
          //
          try {
            schemaLevel.onMissingAttribute(lineNumber, elemName,
                args.getArgName(i));
          } catch (UnableToCompleteException e) {
            throw new SAXException(e);
          }

          ++missingCount;
        }
      }

      if (missingCount > 0) {
        // Do not invoke the handler.
        //

        // Assume that children shouldn't be recognized either since the
        // handler wasn't invoked.
        //
        setArgsAndPushLevel(null, null);

        return;
      }

      // Invoke the handler method, which will internally
      // convert all the args to their respective parameter types
      // (or warn if there is a problem doing so).
      //
      Object[] invokeArgs = new Object[method.getParamCount()];
      Schema childSchemaLevel;
      try {
        childSchemaLevel = method.invokeBegin(lineNumber, elemName,
            schemaLevel, args, invokeArgs);
      } catch (UnableToCompleteException e) {
        throw new SAXException(e);
      }

      // childSchemaLevel can be null and that's okay -- it means no children
      // are expected. Same for invokeArgs[0] -- it means that the "begin"
      // handler was not called, so neither will we call the "end" handler.
      //
      setArgsAndPushLevel(invokeArgs, childSchemaLevel);
    }

    private Object[] getCurrentArgs() {
      return argStack.peek();
    }

    private Schema getNextToTopSchemaLevel() {
      return schemaLevels.get(schemaLevels.size() - 2);
    }

    private Schema getTopSchemaLevel() {
      return schemaLevels.peek();
    }

    private void parse(TreeLogger logger, Schema topSchema, Reader reader)
        throws UnableToCompleteException {
      // Set up the parentmost schema which is used to find default converters
      // and handlers (but isn't actually on the schema stack.)
      //
      defaultSchema = new DefaultSchema(logger);

      // Tell this schema level about the default schema, which is initialized
      // with
      // converters for basic types.
      //
      topSchema.setParent(defaultSchema);

      // Make a slot for the document element's args.
      //
      argStack.push(null);

      // Push the first schema.
      //
      setArgsAndPushLevel(null, topSchema);

      Throwable caught = null;
      try {
        this.reader = reader;
        SAXParser parser = createNewSaxParser();
        InputSource inputSource = new InputSource(this.reader);
        XMLReader xmlReader = parser.getXMLReader();
        xmlReader.setContentHandler(this);
        xmlReader.parse(inputSource);
      } catch (SAXException e) {
        // If it's an exception wrapped in a SAXException, rip off the outer SAX
        // exception.
        //
        caught = e;

        Exception inner = e.getException();
        if (inner instanceof RuntimeException) {
          throw (RuntimeException) inner;
        } else if (inner != null) {
          caught = inner;
        }

      } catch (ParserConfigurationException e) {
        caught = e;
      } catch (IOException e) {
        caught = e;
      } finally {
        Utility.close(reader);
      }

      if (caught != null) {
        Messages.XML_PARSE_FAILED.log(logger, caught);
        throw new UnableToCompleteException();
      }
    }

    private Schema popLevel() {
      argStack.pop();
      schemaLevels.pop();
      return getTopSchemaLevel();
    }

    private void setArgsAndPushLevel(Object[] handlerArgs, Schema schemaLevel) {
      // Set the args on the current schema level.
      argStack.set(argStack.size() - 1, handlerArgs);
      // A slot for the args at the childrens' depth.
      argStack.push(null);
      if (!schemaLevels.isEmpty()) {
        // Tell this schema level about its parent.
        //
        Schema maybeParent = null;
        for (int i = schemaLevels.size() - 1; i >= 0; --i) {
          maybeParent = schemaLevels.get(i);
          if (maybeParent != null) {
            break;
          }
        }
        if (maybeParent == null) {
          throw new IllegalStateException("Cannot find any parent schema");
        }
        if (schemaLevel != null) {
          schemaLevel.setParent(maybeParent);
        }
      }
      // The schema for children.
      schemaLevels.push(schemaLevel);
    }
  }

  public static void parse(TreeLogger logger, Schema schema, Reader reader)
      throws UnableToCompleteException {

    // Register the schema level.
    //
    registerSchemaLevel(schema.getClass());

    // Do the parse.
    //
    Impl impl = new Impl();
    impl.parse(logger, schema, reader);
  }

  /**
   * Can safely register the same class recursively.
   */
  public static void registerSchemaLevel(Class<? extends Schema> schemaLevelClass) {
    HandlerClassInfo.registerClass(schemaLevelClass);

    // Try to register nested classes.
    //
    Class<?>[] nested = schemaLevelClass.getDeclaredClasses();
    for (int i = 0, n = nested.length; i < n; ++i) {
      Class<?> nestedClass = nested[i];
      if (Schema.class.isAssignableFrom(nestedClass)) {
        registerSchemaLevel(nestedClass.asSubclass(Schema.class));
      }
    }
  }
}
