// Copyright 2010 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.
//
// Author: jmarantz@google.com (Joshua Marantz)

#ifndef PAGESPEED_KERNEL_BASE_STRING_MULTI_MAP_H_
#define PAGESPEED_KERNEL_BASE_STRING_MULTI_MAP_H_

#include <algorithm>
#include <set>
#include <utility>
#include <vector>

#include "base/logging.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"

namespace net_instaweb {

// Implements an ordered string map, providing case-sensitive and case
// insensitive versions.  The order of insertion is retained and
// names/value pairs can be accessed by index or looked up by name.
//
// The keys and values in the map may contain embedded NUL characters.
// The values can also be the NULL pointer, which the API retains
// distinctly from empty strings.
template<class StringCompare> class StringMultiMap {
 public:
  StringMultiMap() { }
  ~StringMultiMap() {
    Clear();
  }

  bool empty() const {
    return vector_.empty();
  }

  void Clear() {
    for (int i = 0, n = vector_.size(); i < n; ++i) {
      delete vector_[i].second;
    }
    set_.clear();
    vector_.clear();
  }

  // Returns the number of distinct names
  int num_names() const { return set_.size(); }

  // Returns the number of distinct values, which can be larger than num_names
  // if Add is called twice with the same name.
  int num_values() const { return vector_.size(); }

  // Find the value(s) associated with a variable.  Note that you may
  // specify a variable multiple times by calling Add multiple times
  // with the same variable, and each of these values will be returned
  // in the vector.
  bool Lookup(const StringPiece& name, ConstStringStarVector* values) const {
    SetEntry lookup_entry(name);
    typename Set::const_iterator p = set_.find(lookup_entry);
    bool ret = false;
    if (p != set_.end()) {
      ret = true;
      const SetEntry& stored_entry = *p;
      *values = stored_entry.values();
    }
    return ret;
  }

  // Looks up a single value.  Returns NULL if the name is not found or more
  // than one value is found.
  const GoogleString* Lookup1(const StringPiece& name) const {
    ConstStringStarVector v;
    if (Lookup(name, &v) && v.size() == 1) {
      return v[0];
    }
    return NULL;
  }

  bool Has(const StringPiece& name) const {
    SetEntry lookup_entry(name);
    return set_.find(lookup_entry) != set_.end();
  }

  // Remove all variables by name.  Returns true if anything was removed.
  bool RemoveAll(const StringPiece& key) {
    return RemoveAllFromSortedArray(&key, 1);
  }

  // Remove all variables by name.  Returns true if anything was removed.
  //
  // The 'names' vector must be sorted based on StringCompare.
  bool RemoveAllFromSortedArray(const StringPiece* names, int names_size) {
#ifndef NDEBUG
    for (int i = 1; i < names_size; ++i) {
      StringCompare compare;
      // compare implements <, and we want <= to allow for for
      // duplicate entries, such as the two Set-Cookie entries that
      // occur in ResponseHeadersTest.TestUpdateFrom.  We could also
      // require call-sites to de-dup but this seems easier.  We can
      // implement a<=b via !compare(b, a).
      DCHECK(!compare(names[i], names[i - 1]))
          << "\"" << names[i - 1] << "\" vs \"" << names[i];
    }
#endif

    // Keep around dummy entry for stuffing in keys and doing lookups.
    // The values field for this instance is unused.
    SetEntry lookup_entry;

    // First, see if any of the names are in the map.  This way we'll avoid
    // making any allocations if there is no work to be done.  We cannot
    // actually remove the map entries, though, until we rebuild the vector,
    // since the map owns the StringPiece key storage used by the vector.
    const int kNotFound = -1;
    int index_of_first_match = kNotFound;
    typename Set::iterator set_entry_of_first_match;
    for (int i = 0; i < names_size; ++i) {
      lookup_entry.set_key(names[i]);
      set_entry_of_first_match = set_.find(lookup_entry);
      if (set_entry_of_first_match != set_.end()) {
        index_of_first_match = i;
        break;
      }
    }

    if (index_of_first_match == kNotFound) {
      return false;
    } else {
      StringPairVector temp_vector;  // Temp variable for new vector.
      temp_vector.reserve(vector_.size() - 1);
      StringCompare compare;
      for (int i = 0; i < num_values(); ++i) {
        if (std::binary_search(names, names + names_size, name(i), compare)) {
          delete vector_[i].second;
        } else {
          temp_vector.push_back(vector_[i]);
        }
      }

      vector_.swap(temp_vector);

      set_.erase(set_entry_of_first_match);
      for (int i = index_of_first_match + 1; i < names_size; ++i) {
        lookup_entry.set_key(names[i]);
        set_.erase(lookup_entry);
      }
    }
    return true;
  }

  StringPiece name(int index) const { return vector_[index].first; }

  // Note that the value can be NULL.
  const GoogleString* value(int index) const { return vector_[index].second; }

  // Add a new variable.  The value can be null.
  void Add(const StringPiece& key, const StringPiece& value) {
    SetEntry lookup_entry(key);
    std::pair<typename Set::iterator, bool> iter_inserted =
        set_.insert(lookup_entry);
    typename Set::iterator iter = iter_inserted.first;

    // To avoid letting you corrupt the comparison sanity of an STL set,
    // the 'insert' method returns an iterator that returns you only a
    // const reference to the stored entry.  However, the mutation we are
    // going to do here is to change the key to point to storage we'll
    // own in the entry, which we want to allocate only the first time
    // it is added.
    //
    // We also need to be able to mutate the entry to allow adding new
    // value entries.
    SetEntry& entry = const_cast<SetEntry&>(*iter);
    if (iter_inserted.second) {
      // The first time we insert, make a copy of the key in storage we own.
      entry.SaveKey();
    }
    GoogleString* value_copy = NULL;
    if (value.data() != NULL) {
      value_copy = new GoogleString(value.as_string());
    }
    entry.AddValue(value_copy);
    vector_.push_back(StringPair(iter->key(), value_copy));
  }

  // Parse and add from a string of name-value pairs.
  // For example,
  //   "name1=value1,name2=value2,name3="
  // where separators is "," and value_separator is '='.
  // If omit_if_no_value is true, a name-value pair with an empty value will
  // not be added.
  void AddFromNameValuePairs(const StringPiece& name_value_list,
                             const StringPiece& separators,
                             char value_separator,
                             bool omit_if_no_value) {
    StringPieceVector pairs;
    SplitStringPieceToVector(name_value_list, separators, &pairs, true);
    for (int i = 0, n = pairs.size(); i < n; ++i) {
      StringPiece& pair = pairs[i];
      StringPiece::size_type pos = pair.find(value_separator);
      if (pos != StringPiece::npos) {
        Add(pair.substr(0, pos), pair.substr(pos + 1));
      } else if (!omit_if_no_value) {
        Add(pair, StringPiece(NULL, 0));
      }
    }
  }

  void CopyFrom(const StringMultiMap& string_multi_map) {
    Clear();
    for (int i = 0; i < string_multi_map.num_values(); ++i) {
      const GoogleString* value = string_multi_map.value(i);
      if (value != NULL) {
        Add(string_multi_map.name(i), *value);
      } else {
        Add(string_multi_map.name(i), NULL);
      }
    }
  }

 private:
  // We are creating a map-like object using a std::set to make it clearer
  // how we are managing key storage within the entry.
  class SetEntry {
   public:
    SetEntry() { }
    SetEntry(StringPiece key) : key_(key) { }
    SetEntry(const SetEntry& src)
        : key_(src.key_) {
      // Note that a copy-construction does occur in Add, but only of
      // the lookup_entry, which will not have a saved key.
      DCHECK(src.values_.empty());
    }

    SetEntry& operator=(const SetEntry& src) {
      if (&src != this) {
        DCHECK(src.values_.empty());
        key_ = src.key_;
      }
      return *this;
    }

    void set_key(StringPiece key) {
      key_ = key;
    }

    void AddValue(const GoogleString* value) {
      values_.push_back(value);
    }

    // During lookups, key will point to the passed-in StringPiece.
    // However, the persistent entry we put in the map must duplicate
    // the key into key_storage and change key to point to that.
    void SaveKey() {
      key_.CopyToString(&key_storage_);
      key_ = key_storage_;
    }

    StringPiece key() const { return key_; }
    const ConstStringStarVector& values() const { return values_; }

   private:
    GoogleString key_storage_;
    StringPiece key_;
    ConstStringStarVector values_;
  };

  struct EntryCompare {
    bool operator()(const SetEntry& a, const SetEntry& b) const {
      return compare(a.key(), b.key());
    }

    StringCompare compare;
  };

  // We are keeping two structures, conceptually map<String,vector<String>> and
  // vector<pair<String,String>>, so we can do associative lookups and
  // also order-preserving iteration and easy indexed access.
  //
  // To avoid duplicating the strings and superfluous string-allocations on
  // lookups, we implement this via a set, whose entries own the keys.  A
  // separate string-pair-vector owns the values as new'd GoogleString*.  We
  // use a pointer here to avoid the cost of string-copies as the vector is
  // resized.
  typedef std::pair<StringPiece, GoogleString*> StringPair;  // owns the value
  typedef std::set<SetEntry, EntryCompare> Set;
  typedef std::vector<StringPair> StringPairVector;

  Set set_;
  StringPairVector vector_;

  DISALLOW_COPY_AND_ASSIGN(StringMultiMap);
};

class StringMultiMapInsensitive
    : public StringMultiMap<StringCompareInsensitive> {
 public:
  StringMultiMapInsensitive() { }
 private:
  DISALLOW_COPY_AND_ASSIGN(StringMultiMapInsensitive);
};

class StringMultiMapSensitive : public StringMultiMap<StringCompareSensitive> {
 public:
  StringMultiMapSensitive() { }
 private:
  DISALLOW_COPY_AND_ASSIGN(StringMultiMapSensitive);
};

}  // namespace net_instaweb

#endif  // PAGESPEED_KERNEL_BASE_STRING_MULTI_MAP_H_
