#!/usr/bin/env python
#
# Copyright 2007 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.
#
"""Directly processes text of web.xml.

WebXmlParser is called with Xml string to produce a WebXml object containing
the data from that string.

WebXmlParser: Converts xml to AppEngineWebXml object.
WebXml: Contains relevant information from web.xml.
SecurityConstraint: Contains information about specified security constraints.

"""

from xml.etree import ElementTree

from google.appengine.tools import xml_parser_utils
from google.appengine.tools.app_engine_config_exception import AppEngineConfigException
from google.appengine.tools.basic_equality_mixin import BasicEqualityMixin


class WebXmlParser(object):
  """Provides logic for walking down XML tree and pulling data."""

  def ProcessXml(self, xml_str):
    """Parses XML string and returns object representation of relevant info.

    Uses ElementTree parser to return a tree representation of XML.
    Then walks down that tree and extracts important info and adds it to the
    object.

    Args:
      xml_str: The XML string itself.

    Returns:
      If there is well-formed but illegal XML, returns a list of
      errors. Otherwise, returns an AppEngineWebXml object containing
      information from XML.

    Raises:
      AppEngineConfigException: In case of malformed XML or illegal inputs.
    """
    try:
      self.web_xml = WebXml()
      self.errors = []
      xml_root = ElementTree.fromstring(xml_str)
      for node in xml_root.getchildren():
        self.ProcessSecondLevelNode(node)

      if self.errors:
        raise AppEngineConfigException('\n'.join(self.errors))

      return self.web_xml

    except ElementTree.ParseError:
      raise AppEngineConfigException('Bad input -- not valid XML')

  def ProcessSecondLevelNode(self, node):
    element_name = xml_parser_utils.GetTag(node)
    if element_name in ['servlet', 'filter', 'display-name', 'taglib']:


      return
    camel_case_name = ''.join(part.title() for part in element_name.split('-'))
    method_name = 'Process%sNode' % camel_case_name
    if (hasattr(self, method_name) and
        method_name is not 'ProcessSecondLevelNode'):
      getattr(self, method_name)(node)
    else:
      self.errors.append('Second-level tag not recognized: %s' % element_name)

  def ProcessServletMappingNode(self, node):
    self._ProcessUrlMappingNode(node)

  def ProcessFilterMappingNode(self, node):
    self._ProcessUrlMappingNode(node)

  def _ProcessUrlMappingNode(self, node):
    """Parses out URL and possible ID for filter-mapping and servlet-mapping.

    Pulls url-pattern text out of node and adds to WebXml object. If url-pattern
    has an id attribute, adds that as well. This is done for <servlet-mapping>
    and <filter-mapping> nodes.

    Args:
      node: An ElementTreeNode which looks something like the following:

        <servlet-mapping>
          <servlet-name>redteam</servlet-name>
          <url-pattern>/red/*</url-pattern>
        </servlet-mapping>
    """
    url_pattern_node = xml_parser_utils.GetChild(node, 'url-pattern')
    if url_pattern_node is not None:
      self.web_xml.patterns.append(url_pattern_node.text)
      id_attr = xml_parser_utils.GetAttribute(url_pattern_node, 'id')
      if id_attr:
        self.web_xml.pattern_to_id[url_pattern_node.text] = id_attr

  def ProcessErrorPageNode(self, node):