/*

 * Copyright 2011 Steven Gribble

 *

 *  This file is the solution to an exercise problem posed during

 *  one of the UW CSE 333 lectures (333exercises).

 *

 *  333exercises is free software: you can redistribute it and/or modify

 *  it under the terms of the GNU General Public License as published by

 *  the Free Software Foundation, either version 3 of the License, or

 *  (at your option) any later version.

 *

 *  333exercises is distributed in the hope that it will be useful,

 *  but WITHOUT ANY WARRANTY; without even the implied warranty of

 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

 *  GNU General Public License for more details.

 *

 *  You should have received a copy of the GNU General Public License

 *  along with 333exercises.  If not, see <http://www.gnu.org/licenses/>.

 */



#include <algorithm>



#include "./Histogram.h"



using std::sort;

using std::endl;

using std::cout;  // for debugging



// lec 12 exercise 1



// Add a word occurrence to the histogram.  Converts the word to

// lowercase before incorporating.

void Histogram::AddWord(string word) {

  // std::map overrides the [] operator, and does a nice thing: if the

  // key is not in the hashtable yet, it is created as a side-effect

  // of the lookup and initialized with a zero-equivalent.  So, this

  // lookup does exactly the right thing (return zero) if the word

  // isn't yet in the table!

  std::transform(word.begin(), word.end(), word.begin(), ::tolower);

  uint32_t oldval = histogram_data_[word];

  histogram_data_[word] = oldval + 1;

}



// This utility function is passed as an argument to std::sort from

// #include <algorithm> as a comparator.  It is used inside

// GetSortedData().

static bool CompareHistPair(pair<string, uint32_t> a,

                            pair<string, uint32_t> b) {

  // Deliberately reverse the comparison so we can sort in descending

  // order, instead sort()'s default of ascending order.

  return a.second > b.second;

}



// Return a vector of <word,count> pairs, sorted in descending order

// of count.

vector<pair<string, uint32_t> > Histogram::GetSortedData() const {

  vector<pair<string, uint32_t> > data;



  // Iterate through the map, inserting pairs into the "data" vector.

  // This is horrific, but because we declared GetSortedData() to be

  // a const function, the compiler prevents us from constructing a

  // regular iterator to a member variable, and instead we need to

  // construct a const_iterator.  Wow!!

  map<string, uint32_t>::const_iterator it = histogram_data_.begin();

  map<string, uint32_t>::const_iterator endit = histogram_data_.end();

  for (it = histogram_data_.begin(); it != histogram_data_.end(); it++) {

    pair<string, uint32_t> nextpair(it->first, it->second);

    data.push_back(nextpair);

  }



  // Sort the "data" vector.

  sort(data.begin(), data.end(), &CompareHistPair);

  return data;

}



// Override "<<" for std::ostream.

ostream &operator<<(ostream &out, const Histogram &pt) {

  vector<pair<string, uint32_t> > data = pt.GetSortedData();

  for (uint32_t i = 0; i < data.size(); i++) {

    string word = data[i].first;

    uint32_t count = data[i].second;

    out << word << " " << count << endl;

  }

  return out;

}