#include "DataSet.hpp"
#include <algorithm>
#include "Constants.hpp"

/*
   Function: CompareEntriesLess

     Global 'less' compare function for data entries by their values.

   Parameters:

     pFirstEntry - The first data entry to be compared.
     pSecondEntry - The second data entry to be compared.

   Returns:

     A boolean value indicating if the first entry's value is smaller than the second entry's.
*/
bool CompareEntriesLess(DataEntry* pFirstEntry, DataEntry* pSecondEntry) {
  return pFirstEntry->GetValue() < pSecondEntry->GetValue();
}

/*
   Function: CompareEntriesGreater

     Global 'greater' compare function for data entries by their values.

   Parameters:

     pFirstEntry - The first data entry to be compared.
     pSecondEntry - The second data entry to be compared.

   Returns:

     A boolean value indicating if the first entry's value is greater than the second entry's.
*/
bool CompareEntriesGreater(DataEntry* pFirstEntry, DataEntry* pSecondEntry) {
  return pFirstEntry->GetValue() > pSecondEntry->GetValue();
}

/*
   Function: CompareGroupsLess

     Global 'less' compare function for data groups by their summed values.

   Parameters:

     pFirstGroup - The first data group to be compared.
     pSecondGroup - The second data group to be compared.

   Returns:

     A boolean value indicating if the first group's summed value is smaller than the second group's.
*/
bool CompareGroupsLess(DataGroup* pFirstGroup, DataGroup* pSecondGroup) {
  return pFirstGroup->SumValues() < pSecondGroup->SumValues();
}

/*
   Function: CompareGroupsGreater

     Global 'greater' compare function for data groups by their summed values.

   Parameters:

     pFirstGroup - The first data group to be compared.
     pSecondGroup - The second data group to be compared.

   Returns:

     A boolean value indicating if the first group's summed value is greater than the second group's.
*/
bool CompareGroupsGreater(DataGroup* pFirstGroup, DataGroup* pSecondGroup) {
  return pFirstGroup->SumValues() > pSecondGroup->SumValues();
}

DataSet::DataSet(std::string sName, std::string sUnit) {
  this->sName = sName;
  this->sUnit = sUnit;
  bDescending = true;
  bShowAll = true;
}

DataSet::~DataSet() {
  while (vDataGroups.size() > 0) {
    std::vector<DataGroup*>::iterator it = vDataGroups.begin();

    if (it != vDataGroups.end()) {
      delete *it;
      vDataGroups.erase(it);
    }
  }
}

void DataSet::AddDataGroup(DataGroup* pDataGroup) {
  vDataGroups.push_back(pDataGroup);
}

std::string DataSet::GetName() {
  return sName;
}

std::string DataSet::GetUnit() {
  return sUnit;
}

void DataSet::SetSortingOrder(bool bDescending) {
  this->bDescending = bDescending;
}

bool DataSet::GetSortingOrder() {
  return bDescending;
}

double DataSet::GetHighestGroupValue() {
  double dHighestValue = 0.0;

  for (unsigned int i = 0; i < vDataGroups.size(); i++) {
    double dSummedValues = vDataGroups.at(i)->SumValues();

    if (dSummedValues > dHighestValue) {
      dHighestValue = dSummedValues;
    }
  }

  return dHighestValue;
}

void DataSet::SetFiltering(bool bShowAll) {
  this->bShowAll = bShowAll;
}

bool DataSet::GetFiltering() {
  return bShowAll;
}

std::vector<DataEntry*> DataSet::GetAllDataEntries() {
  std::vector<DataEntry*> vAllDataEntries;

  for (unsigned int i = 0; i < vDataGroups.size(); i++) {
    std::vector<DataEntry*> vDataEntriesOfGroup = vDataGroups.at(i)->GetDataEntries();

    for (unsigned int j = 0; j < vDataEntriesOfGroup.size(); j++) {
      vAllDataEntries.push_back(vDataEntriesOfGroup.at(j));
    }
  }

  if (bDescending) {
    std::sort(vAllDataEntries.begin(), vAllDataEntries.end(), CompareEntriesGreater);

    if (!bShowAll) {
      std::vector<DataEntry*> vFilteredDataEntries(vAllDataEntries.begin(), vAllDataEntries.begin() + FILTER_SIZE);

      return vFilteredDataEntries;
    }
  }
  else {
    std::sort(vAllDataEntries.begin(), vAllDataEntries.end(), CompareEntriesLess);

    if (!bShowAll) {
      std::vector<DataEntry*> vFilteredDataEntries(vAllDataEntries.end() - FILTER_SIZE, vAllDataEntries.end());

      return vFilteredDataEntries;
    }
  }

  return vAllDataEntries;
}

std::vector<DataGroup*> DataSet::GetDataGroups() {
  if (bDescending) {
    std::sort(vDataGroups.begin(), vDataGroups.end(), CompareGroupsGreater);
  }
  else {
    std::sort(vDataGroups.begin(), vDataGroups.end(), CompareGroupsLess);
  }

  return vDataGroups;
}