/**
 * @file symbol_sort.cpp
 * Sorting symbols
 *
 * @remark Copyright 2002, 2003 OProfile authors
 * @remark Read the file COPYING
 *
 * @author Philippe Elie
 * @author John Levon
 */

#include "symbol_sort.h"
#include "symbol_functors.h"

#include "name_storage.h"
#include "op_exception.h"

#include <algorithm>
#include <sstream>

using namespace std;

namespace {

bool long_filenames;

int image_compare(image_name_id l, image_name_id r)
{
	if (long_filenames)
		return image_names.name(l).compare(image_names.name(r));
	return image_names.basename(l).compare(image_names.basename(r));
}


int debug_compare(debug_name_id l, debug_name_id r)
{
	if (long_filenames)
		return debug_names.name(l).compare(debug_names.name(r));
	return debug_names.basename(l).compare(debug_names.basename(r));
}


int compare_by(sort_options::sort_order order,
               symbol_entry const & lhs, symbol_entry const & rhs)
{
	switch (order) {
		case sort_options::sample:
			if (lhs.sample.counts[0] < rhs.sample.counts[0])
				return 1;
			if (lhs.sample.counts[0] > rhs.sample.counts[0])
				return -1;
			return 0;

		case sort_options::symbol:
			return symbol_names.demangle(lhs.name).compare(
				symbol_names.demangle(rhs.name));

		case sort_options::image:
			return image_compare(lhs.image_name, rhs.image_name);

		case sort_options::app_name:
			return image_compare(lhs.app_name, rhs.app_name);

		case sort_options::vma:
			if (lhs.sample.vma < rhs.sample.vma)
				return -1;
			if (lhs.sample.vma > rhs.sample.vma)
				return 1;
			return 0;

		case sort_options::debug: {
			file_location const & f1 = lhs.sample.file_loc;
			file_location const & f2 = rhs.sample.file_loc;
			int ret = debug_compare(f1.filename, f2.filename);
			if (ret == 0)
				ret = f1.linenr - f2.linenr;
			return ret;
		}

		default: {
			// static_cast<> to shut up g++ 2.91.66 which warn
			// about ambiguity between <<(int) and <<(long int)
			ostringstream os;
			os << "compare_by(): unknown sort option: "
			   << static_cast<int>(order) << endl;
			throw op_fatal_error(os.str());
		}
	}

	return 0;
}


struct symbol_compare {
	symbol_compare(vector<sort_options::sort_order> const & order,
	               bool reverse)
		: compare_order(order), reverse_sort(reverse) {}

	bool operator()(symbol_entry const * lhs,
			symbol_entry const * rhs) const {
		return operator()(*lhs, *rhs);
	}

	bool operator()(symbol_entry const & lhs,
			symbol_entry const & rhs) const;

protected:
	vector<sort_options::sort_order> const & compare_order;
	bool reverse_sort;
};


bool symbol_compare::operator()(symbol_entry const & lhs,
				symbol_entry const & rhs) const
{
	for (size_t i = 0; i < compare_order.size(); ++i) {
		int ret = compare_by(compare_order[i], lhs, rhs);

		if (reverse_sort)
			ret = -ret;
		if (ret != 0)
			return ret < 0;
	}
	return false;
}


} // anonymous namespace


void sort_options::
sort(symbol_collection & syms, bool reverse_sort, bool lf) const
{
	long_filenames = lf;

	vector<sort_order> sort_option(options);
	for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
		if (find(sort_option.begin(), sort_option.end(), cur) ==
		    sort_option.end())
			sort_option.push_back(cur);
	}

	stable_sort(syms.begin(), syms.end(),
	            symbol_compare(sort_option, reverse_sort));
}


void sort_options::
sort(cg_collection & syms, bool reverse_sort, bool lf) const
{
	long_filenames = lf;

	vector<sort_order> sort_option(options);
	for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
		if (find(sort_option.begin(), sort_option.end(), cur) ==
		    sort_option.end())
			sort_option.push_back(cur);
	}

	stable_sort(syms.begin(), syms.end(),
	            symbol_compare(sort_option, reverse_sort));
}


void sort_options::
sort(diff_collection & syms, bool reverse_sort, bool lf) const
{
	long_filenames = lf;

	vector<sort_order> sort_option(options);
	for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
		if (find(sort_option.begin(), sort_option.end(), cur) ==
		    sort_option.end())
			sort_option.push_back(cur);
	}

	stable_sort(syms.begin(), syms.end(),
	            symbol_compare(sort_option, reverse_sort));
}


void sort_options::add_sort_option(string const & name)
{
	if (name == "vma") {
		options.push_back(vma);
	} else if (name == "sample") {
		options.push_back(sample);
	} else if (name == "symbol") {
		options.push_back(symbol);
	} else if (name == "debug") {
		options.push_back(debug);
	} else if (name == "image") {
		options.push_back(image);
	} else if (name == "app-name") {
		options.push_back(app_name);
	} else {
		ostringstream os;
		os << "unknown sort option: " << name << endl;
		throw op_fatal_error(os.str());
	}
}


void sort_options::add_sort_option(sort_options::sort_order order)
{
	options.push_back(order);
}
