// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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.devtools.build.android.xml;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSortedMap;
import com.google.devtools.build.android.DataResourceXml;
import com.google.devtools.build.android.XmlResourceValue;
import com.google.devtools.build.android.XmlResourceValues;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;

/**
 * Represents a collection of xml namespaces.
 *
 * <p>Each &lt;resources&gt; can have xmlns declarations. Since the merging process generates the
 * resources tag to combining multiple {@link DataResourceXml}s, the Namespaces must be tracked and
 * kept with each value.
 */
public class Namespaces implements Iterable<Map.Entry<String, String>> {
  private static final Logger logger = Logger.getLogger(Namespaces.class.getCanonicalName());
  private static final Namespaces EMPTY_INSTANCE =
      new Namespaces(ImmutableSortedMap.<String, String>of());

  /** Collects prefix and uri pairs from elements. */
  public static class Collector {
    private Map<String, String> prefixToUri = new LinkedHashMap<>();

    public Namespaces toNamespaces() {
      return Namespaces.from(prefixToUri);
    }

    /**
     * Collects all the prefix and uri pairs from a start element.
     *
     * <p>Since {@link Namespaces} represents top level declarations, collectFrom ignores any prefix
     * that is declared on the element. Those will be handled by the {@link XmlResourceValue}
     * individually.
     *
     * @param start The element to collect prefix and uris from.
     * @return The current namespace builder.
     */
    public Collector collectFrom(StartElement start) {
      Iterator<Attribute> attributes = XmlResourceValues.iterateAttributesFrom(start);
      Iterator<Namespace> localNamespaces = XmlResourceValues.iterateNamespacesFrom(start);
      // Collect the local prefixes to make sure a prefix isn't declared locally.
      Set<String> prefixes = new LinkedHashSet<>();
      while (localNamespaces.hasNext()) {
        prefixes.add(localNamespaces.next().getPrefix());
      }
      collectFrom(start.getName(), prefixes);
      while (attributes.hasNext()) {
        collectFrom(attributes.next().getName(), prefixes);
      }
      return this;
    }

    void collectFrom(QName name, Set<String> localPrefixes) {
      String prefix = name.getPrefix();
      if (!prefix.isEmpty() && !localPrefixes.contains(prefix)) {
        // If the prefix exists and is not a locally declared prefix, add the prefix and uri.
        prefixToUri.put(prefix, name.getNamespaceURI());
      }
    }
  }

  public static Collector collector() {
    return new Collector();
  }

  public static Namespaces from(Map<String, String> prefixToUri) {
    if (prefixToUri.isEmpty()) {
      return empty();
    }
    return new Namespaces(ImmutableSortedMap.copyOf(prefixToUri));
  }

  /**
   * Create a {@link Namespaces} containing the singular namespace used by the name, or an empty
   * one.
   */
  public static Namespaces from(QName name) {
    if (name.getPrefix().isEmpty()) {
      return empty();
    }
    return new Namespaces(ImmutableSortedMap.of(name.getPrefix(), name.getNamespaceURI()));
  }

  public static Namespaces empty() {
    return EMPTY_INSTANCE;
  }

  // Keep the prefixes in a sorted map so that when this object is iterated over, the order is
  // deterministic.
  private final ImmutableSortedMap<String, String> prefixToUri;

  private Namespaces(ImmutableSortedMap<String, String> prefixToUri) {
    this.prefixToUri = prefixToUri;
  }

  /** Combines two {@link Namespaces} into a new instance and returns it. */
  public Namespaces union(Namespaces other) {
    // No prefixes to add, return the other.
    if (prefixToUri.isEmpty()) {
      return other;
    }
    // TODO(corysmith): Issue error when prefixes are mapped to different uris.
    // Keeping behavior for backwards compatibility.
    Map<String, String> combinedNamespaces = new LinkedHashMap<>();
    combinedNamespaces.putAll(other.prefixToUri);
    for (Map.Entry<String, String> namespace : prefixToUri.entrySet()) {
      String prefix = namespace.getKey();
      String namespaceUri = namespace.getValue();
      if (combinedNamespaces.containsKey(prefix)
          && !combinedNamespaces.get(prefix).equals(namespaceUri)) {
        logger.warning(
            String.format(
                "%s has multiple namespaces: %s and %s. Using %s."
                    + " This will be an error in the future.",
                prefix, namespaceUri, combinedNamespaces.get(prefix), namespaceUri));
      }
      combinedNamespaces.put(prefix, namespaceUri);
    }
    return Namespaces.from(combinedNamespaces);
  }

  @Override
  public Iterator<Map.Entry<String, String>> iterator() {
    return prefixToUri.entrySet().iterator();
  }

  public Map<String, String> asMap() {
    return prefixToUri;
  }

  @Override
  public int hashCode() {
    return prefixToUri.hashCode();
  }

  @Override
  public String toString() {
    return MoreObjects.toStringHelper(getClass()).add("prefixToUri", prefixToUri).toString();
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Namespaces) {
      Namespaces other = (Namespaces) obj;
      return Objects.equals(prefixToUri, other.prefixToUri);
    }
    return false;
  }
}
