/*
 * Copyright 2008 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.cfg;

import com.google.gwt.core.ext.linker.PropertyProviderGenerator;
import com.google.gwt.dev.util.collect.IdentityHashSet;
import com.google.gwt.dev.util.collect.Lists;
import com.google.gwt.dev.util.collect.Sets;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.regex.Pattern;

/**
 * Represents a single named deferred binding or configuration property that can
 * answer with its value. The BindingProperty maintains two sets of values, the
 * "defined" set and the "allowed" set. The allowed set must always be a subset
 * of the defined set.
 */
public class BindingProperty extends Property {
  public static final String GLOB_STAR = "*";
  private static final String EMPTY = "";

  private List<SortedSet<String>> collapsedValues = Lists.create();
  private final Map<Condition, SortedSet<String>> conditionalValues = new LinkedHashMap<Condition, SortedSet<String>>();
  private final SortedSet<String> definedValues = new TreeSet<String>();
  private PropertyProvider provider;
  private Class<? extends PropertyProviderGenerator> providerGenerator;
  private String fallback;
  private HashMap<String,LinkedList<LinkedHashSet<String>>> fallbackValueMap;
  private HashMap<String,LinkedList<String>> fallbackValues = new HashMap<String,LinkedList<String>>();
  private final ConditionAll rootCondition = new ConditionAll();

  {
    conditionalValues.put(rootCondition, new TreeSet<String>());
  }

  public BindingProperty(String name) {
    super(name);
    fallback = EMPTY;
  }

  /**
   * Add an equivalence set of property values.
   */
  public void addCollapsedValues(String... values) {

    // Sanity check caller
    for (String value : values) {
      if (value.contains(GLOB_STAR)) {
        // Expanded in normalizeCollapsedValues()
        continue;
      } else if (!definedValues.contains(value)) {
        throw new IllegalArgumentException(
            "Attempting to collapse unknown value " + value);
      }
    }

    // We want a mutable set, because it simplifies normalizeCollapsedValues
    SortedSet<String> temp = new TreeSet<String>(Arrays.asList(values));
    collapsedValues = Lists.add(collapsedValues, temp);
  }

  public void addDefinedValue(Condition condition, String newValue) {
    definedValues.add(newValue);
    SortedSet<String> set = conditionalValues.get(condition);
    if (set == null) {
      set = new TreeSet<String>();
      set.addAll(conditionalValues.get(rootCondition));
      conditionalValues.put(condition, set);
    }
    set.add(newValue);
  }

  /**
   * Adds fall back value to given property name. 
   * @param value the property value.
   * @param fallbackValue the fall back value for given property value.
   */
  public void addFallbackValue(String value, String fallbackValue) {
    LinkedList<String> values = fallbackValues.get(fallbackValue);
    if (values == null) {
      values = new LinkedList<String>();
      fallbackValues.put(fallbackValue, values);
    }
    values.addFirst(value);
  }

  /**
   * Returns the set of allowed values in sorted order when a certain condition
   * is satisfied.
   */
  public String[] getAllowedValues(Condition condition) {
    Set<String> allowedValues = conditionalValues.get(condition);
    return allowedValues.toArray(new String[allowedValues.size()]);
  }

  public List<SortedSet<String>> getCollapsedValues() {
    return collapsedValues;
  }

  public Map<Condition, SortedSet<String>> getConditionalValues() {
    return Collections.unmodifiableMap(conditionalValues);
  }

  /**
   * If the BindingProperty has exactly one value across all conditions and
   * permutations, return that value otherwise return <code>null</code>.
   */
  public String getConstrainedValue() {
    String constrainedValue = null;
    for (SortedSet<String> allowedValues : conditionalValues.values()) {
      if (allowedValues.size() != 1) {
        return null;
      } else if (constrainedValue == null) {
        constrainedValue = allowedValues.iterator().next();
      } else if (!constrainedValue.equals(allowedValues.iterator().next())) {
        return null;
      }
    }
    return constrainedValue;
  }

  /**
   * Returns the set of defined values in sorted order.
   */
  public String[] getDefinedValues() {
    return definedValues.toArray(new String[definedValues.size()]);
  }

  /**
   * Returns the fallback value for this property, or the empty string if none.
   * 
   * @return the fallback value
   */
  public String getFallback() {
    return fallback;
  }

  /**
   * Returns the map of values to fall back values. the list of fall
   * back values is in decreasing order of preference.
   * @return map of property value to fall back values.
   */
  public Map<String,? extends List<? extends Set<String>>> getFallbackValuesMap() {
    if (fallbackValueMap == null) {
      HashMap<String,LinkedList<LinkedHashSet<String>>> valuesMap = new HashMap<String,LinkedList<LinkedHashSet<String>>>();
      // compute closure of fall back values preserving order
      for (Entry<String, LinkedList<String>> e : fallbackValues.entrySet()) {
        String from = e.getKey();
        LinkedList<LinkedHashSet<String>> alternates = new LinkedList<LinkedHashSet<String>>();
        valuesMap.put(from, alternates);
        LinkedList<String> childList = fallbackValues.get(from);
        LinkedHashSet<String> children = new LinkedHashSet<String>();
        children.addAll(childList);
        while (children != null && children.size() > 0) 
        {
          alternates.add(children);
          LinkedHashSet<String> newChildren = new LinkedHashSet<String>();
          for (String child : children) {
            childList = fallbackValues.get(child);
            if (null == childList) {
              continue;
            }
            for (String val : childList) {
              newChildren.add(val);
            }
          }
          children = newChildren;
        }
      }
      fallbackValueMap = valuesMap;
    }
    return fallbackValueMap;
  }
  
  public PropertyProvider getProvider() {
    return provider;
  }

  /**
   * @return the the provider generator class, or null if none.
   */
  public Class<? extends PropertyProviderGenerator> getProviderGenerator() {
    return providerGenerator;
  }

  public Set<String> getRequiredProperties() {
    Set<String> toReturn = Sets.create();
    for (Condition cond : conditionalValues.keySet()) {
      toReturn = Sets.addAll(toReturn, cond.getRequiredProperties());
    }
    return toReturn;
  }

  public ConditionAll getRootCondition() {
    return rootCondition;
  }

  /**
   * Returns true if the supplied value is legal under some condition.
   */
  public boolean isAllowedValue(String value) {
    for (Set<String> values : conditionalValues.values()) {
      if (values.contains(value)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Returns <code>true</code> if the value was previously provided to
   * {@link #addDefinedValue(Condition,String)}.
   */
  public boolean isDefinedValue(String value) {
    return definedValues.contains(value);
  }

  /**
   * Returns <code>true</code> if the value of this BindingProperty is always
   * derived from other BindingProperties. That is, for each Condition in the
   * BindingProperty, there is exactly one allowed value.
   */
  public boolean isDerived() {
    for (Set<String> allowedValues : conditionalValues.values()) {
      if (allowedValues.size() != 1) {
        return false;
      }
    }
    return true;
  }

  /**
   * Set the currently allowed values. The values provided must be a subset of
   * the currently-defined values.
   * 
   * @throws IllegalArgumentException if any of the provided values were not
   *     provided to {@link #addDefinedValue(Condition,String)}.
   */
  public void setAllowedValues(Condition condition, String... values) {
    SortedSet<String> temp = new TreeSet<String>(Arrays.asList(values));
    if (!definedValues.containsAll(temp)) {
      throw new IllegalArgumentException(
          "Attempted to set an allowed value that was not previously defined");
    }

    // XML has a last-one-wins semantic which we reflect in our evaluation order
    if (condition == rootCondition) {
      /*
       * An unconditional set-property would undo any previous conditional
       * setters, so we can just clear out this map.
       */
      conditionalValues.clear();
    } else {
      /*
       * Otherwise, we'll just ensure that this condition is moved to the end.
       */
      conditionalValues.remove(condition);
    }
    conditionalValues.put(condition, temp);
  }

  public void setFallback(String token) {
    fallback = token;
  }

  public void setProvider(PropertyProvider provider) {
    this.provider = provider;
  }

  /**
   * Set a provider generator for this property.
   * 
   * @param generator
   */
  public void setProviderGenerator(Class<? extends PropertyProviderGenerator> generator) {
    providerGenerator = generator;
  }

  /**
   * Create a minimal number of equivalence sets, expanding any glob patterns.
   */
  void normalizeCollapsedValues() {
    if (collapsedValues.isEmpty()) {
      return;
    }

    // Expand globs
    for (Set<String> set : collapsedValues) {
      // Compile a regex that matches all glob expressions that we see
      StringBuilder pattern = new StringBuilder();
      for (Iterator<String> it = set.iterator(); it.hasNext();) {
        String value = it.next();
        if (value.contains(GLOB_STAR)) {
          it.remove();
          if (pattern.length() > 0) {
            pattern.append("|");
          }

          // a*b ==> (a.*b)
          pattern.append("(");
          // We know value is a Java ident, so no special escaping is needed
          pattern.append(value.replace(GLOB_STAR, ".*"));
          pattern.append(")");
        }
      }

      if (pattern.length() == 0) {
        continue;
      }

      Pattern p = Pattern.compile(pattern.toString());
      for (String definedValue : definedValues) {
        if (p.matcher(definedValue).matches()) {
          set.add(definedValue);
        }
      }
    }

    // Minimize number of sets

    // Maps a value to the set that contains that value
    Map<String, SortedSet<String>> map = new HashMap<String, SortedSet<String>>();

    // For each equivalence set we have
    for (SortedSet<String> set : collapsedValues) {
      // Examine each original value in the set
      for (String value : new LinkedHashSet<String>(set)) {
        // See if the value was previously assigned to another set
        SortedSet<String> existing = map.get(value);
        if (existing == null) {
          map.put(value, set);
        } else {
          // If so, merge the existing set into this one and update pointers
          set.addAll(existing);
          for (String mergedValue : existing) {
            map.put(mergedValue, set);
          }
        }
      }
    }

    // The values of the maps will now contain the minimal number of sets
    collapsedValues = new ArrayList<SortedSet<String>>(
        new IdentityHashSet<SortedSet<String>>(map.values()));

    // Sort the list
    Lists.sort(collapsedValues, new Comparator<SortedSet<String>>() {
      public int compare(SortedSet<String> o1, SortedSet<String> o2) {
        String s1 = o1.toString();
        String s2 = o2.toString();
        assert !s1.equals(s2) : "Should not have seen equal sets";
        return s1.compareTo(s2);
      }
    });
  }
}
