/*
 *
 *   Ophcrack is a Lanmanager/NTLM hash cracker based on the faster time-memory
 *   trade-off using rainbow tables.
 *
 *   Created with the help of: Maxime Mueller, Luca Wullschleger, Claude
 *   Hochreutiner, Andreas Huber and Etienne Dysli.
 *
 *   Copyright (c) 2009 Philippe Oechslin, Cedric Tissieres, Bertrand Mesot
 *
 *   Ophcrack 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 2 of the License, or
 *   (at your option) any later version.
 *
 *   Ophcrack 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 Ophcrack; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *   This program is released under the GPL with the additional exemption
 *   that compiling, linking, and/or using OpenSSL is allowed.
 *
 *
 *
 *
*/
#include <math.h>
#include <QtCharts/QBarSeries>
#include "graphdialog.h"
//---------------------------------------------------------------------------
GraphDialog::GraphDialog(QWidget *parent) : QDialog(parent) {
  setupUi(this);

  lengthHistogram = 0;
  categoryHistogram = 0;
  timeCurve = 0;
}
//---------------------------------------------------------------------------
void GraphDialog::plot(ophstat_t *stats, int crack_time) {

  this->plotHistoLength(stats->length, lengthChartView);
  this->plotHistoCategory(stats->category, categoryChartView);
  this->plotCurve(stats->time, crack_time, timeChartView);
}
//---------------------------------------------------------------------------
void GraphDialog::initBarGraph(const int numValues, QChart *chart, QBarSet *set, QValueAxis *axisX, QValueAxis *axisY, QString title, const QColor color) {

  int i;
  uint32_t max = 1;

  set->setColor(color);
  for ( i = 0; i < numValues; i++ )
    set->append(0);
  QBarSeries *series = new QBarSeries();
  series->setBarWidth(0.9);
  series->append(set);

  chart->addSeries(series);

  axisX->setRange(0, numValues-1);
  axisX->setLabelFormat("%i");
  axisX->setTickCount(numValues);
  chart->setAxisX(axisX, series);

  axisY->setRange(0, max);
  axisY->setLabelFormat("%i");
  axisY->setTickCount(2);
  chart->setAxisY(axisY, series);

  chart->legend()->setVisible(false);
  chart->setTitle(title);
}

//---------------------------------------------------------------------------
void GraphDialog::plotHistoLength(uint32_t *val, QChartView *view) {

  int i;
  const int numValues = 16;
  uint32_t max = 1;
  static const QColor green = QColor(143, 196, 66);

  if (lengthHistogram == 0) {
    lengthHistogram = new QChart();
    lengthSet = new QBarSet("");
    lengthAxisX = new QValueAxis();
    lengthAxisY = new QValueAxis();
    initBarGraph(numValues, lengthHistogram, lengthSet, lengthAxisX, lengthAxisY, "Distribution of length", green);
    view->setChart(lengthHistogram);
  }

  for ( i = 0; i < numValues; i++ ) {
    lengthSet->replace(i, val[i]);
    if (val[i] > max)
      max = val[i];
  }
  lengthAxisY->setRange(0, max);
  lengthAxisY->setTickCount((max > 5) ? 5 : max+1);
  lengthAxisY->applyNiceNumbers();

}
//---------------------------------------------------------------------------
void GraphDialog::plotHistoCategory(uint32_t *val, QChartView *view) {

  int i;
  const int numValues = 6;
  uint32_t max = 1;
  static const QColor red = QColor(169, 52, 52);

  if (categoryHistogram == 0) {
    categoryHistogram = new QChart();
    categorySet = new QBarSet("");
    categoryAxisX = new QValueAxis();
    categoryAxisY = new QValueAxis();
    initBarGraph(numValues, categoryHistogram, categorySet, categoryAxisX, categoryAxisY, "Category of passwords", red);
    view->setChart(categoryHistogram);
  }

  for ( i = 0; i < numValues; i++ ) {
    categorySet->replace(i, val[i]);
    if (val[i] > max)
      max = val[i];
  }
  categoryAxisY->setRange(0, max);
  categoryAxisY->setTickCount((max > 5) ? 5 : max+1);
  categoryAxisY->applyNiceNumbers();

}
//---------------------------------------------------------------------------
void GraphDialog::plotCurve(list_t *list, int crack_time, QChartView *view) {
  int i;
  list_nd_t *lnd;
  int hsh_time;
  int numValues = (128 > list->size) ? 128 : list->size;
  QVector<float> tempX(QVector<float>(numValues, 0.0));
  QVector<float> tempY(QVector<float>(numValues, 0.0));

  if (timeCurve == 0) {
    timeVector = new QVector<QPointF>();
    timeVector->append(QPointF(0.0, 0.0));
    timeCurve = new QChart();
    timeSeries = new QLineSeries();
    timeAxisX = new QValueAxis();
    timeAxisY = new QValueAxis();

    timeCurve->addSeries(timeSeries);

    timeAxisX->setRange(0.0, crack_time);
    timeAxisX->setLabelFormat("%i");
    timeCurve->setAxisX(timeAxisX, timeSeries);

    timeAxisY->setRange(0.0, 1.0);
    timeAxisY->setLabelFormat("%i");
    timeCurve->setAxisY(timeAxisY, timeSeries);

    timeCurve->legend()->setVisible(false);
    timeCurve->setTitle("Cracking time");
    view->setChart(timeCurve);
    view->setRenderHint(QPainter::Antialiasing);
  }

  timeVector->resize(numValues);

  for (i=0; i<numValues; i++ )
    tempX[i] = (double)(i * crack_time) / numValues;

  if (crack_time == 0) crack_time = 1;

  for (lnd = list->head; lnd != 0; lnd = lnd->next) {
    hsh_time = *(int*)(lnd->data);
    i = (int)floor(hsh_time * numValues / crack_time);
    tempY[(i >= numValues) ? numValues-1 : i] += 1.0;
  }

  for (i=1; i<numValues; i++) {
    tempY[i] += tempY[i-1];
    timeVector->replace(i, QPointF(tempX[i], tempY[i]));
  }

  timeSeries->replace(timeVector->mid(0, numValues));
  if (crack_time > 1) {
    timeAxisX->setRange(0, crack_time);
    timeAxisY->setRange(0, tempY[numValues-1]);
  } 
  timeAxisX->applyNiceNumbers();
  timeAxisY->applyNiceNumbers();

}
