#include "mainwindow.h"
#include "ui_mainwindow.h"


/// \fn MainWindow::MainWindow(QWidget *parent)
/// \~English
/// \brief Constructor
/// \~Spanish
/// \brief Constructor
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    vector<string> devices ;
    ui->setupUi(this);

    /* Starts the sniffer thread and connect the signals between
       the sniffer and the GUI
       Comienza el hilo del sniffer y conecta las sinales entre
       el sniffer y el GUI
    */
    pause = 0;
    sniff = new Sniffer(&wait_pause, &mutex, &pause) ;
    sniff->moveToThread(&sniff_thread);
    connect(&sniff_thread, SIGNAL(started()), sniff, SLOT(process()));
    connect(sniff, SIGNAL(resultReady(unsigned long)), this, SLOT(handleResults(unsigned long))) ;
    connect(&sniff_thread, SIGNAL(finished()), sniff, SLOT(deleteLater()));

    /* Sets the display of the payload fonts to courier */
    /* Ajusta el tipo de letra para desplegar la carga a courier */
    ui->packetSummary->setFont (QFont ("Courier", 13));
    ui->resetButton->setEnabled(false);

    /* Fill the devices box with the machine devices
       Llena la caja de los devices con los devices de la maquina.
    */
    sniff->find_devices(devices);
    for(unsigned int i = 0; i < devices.size(); i++)
        ui->selDevices->addItem(QString::fromStdString(devices[i]));

    /* Set Network manager to search for images */
    /* Ajusta al manejador de red para buscar las imagenes */
    netManager = new QNetworkAccessManager(this) ;
    connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(slot_netwManagerFinished(QNetworkReply*))) ;
}

/// \fn void MainWindow::slot_netwManagerFinished(QNetworkReply *reply)
/// \~English
/// \brief This slot is called when an image is successfuly retreived.
/// The image is then added to the GUI display.
/// \param reply object that contains the reply to our request.
/// \~Spanish
/// \brief Este "slot" es llamado cuando se recibe una imagen con exito.
/// La imagen entonces es anadida a la vizualizacion en el GUI.
/// \param reply objeto que contiene la respuesta a nuestra solicitud
void MainWindow::slot_netwManagerFinished(QNetworkReply *reply)
{
    if (reply->error() != QNetworkReply::NoError) {
        qDebug() << "Error in" << reply->url() << ":" << reply->errorString();
        return;
    }
    QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    if (attribute.isValid()) {
        QUrl url = attribute.toUrl();
        //qDebug() << "must go to:" << url;
        return;
    }
    //qDebug() << "ContentType:" << reply->header(QNetworkRequest::ContentTypeHeader).toString();
    QByteArray jpegData = reply->readAll();
    QPixmap pixmap;
    pixmap.loadFromData(jpegData);
    ui->imageDisplayList->setIconSize(QSize(ui->imageDisplayList->width(),ui->imageDisplayList->width()));
    ui->imageDisplayList->addItem(new QListWidgetItem(QIcon(pixmap),""));

}

/// \fn MainWindow::~MainWindow()
/// \~English
/// \brief Destructor
/// \~Spanish
/// \brief Destructor
MainWindow::~MainWindow()
{
    delete ui;
}

/// \fn void MainWindow::on_capture_clicked()
/// \~English
/// \brief Signal that starts or pause the capture of the packets in the sniffer.
/// \~Spanish
/// \brief Senal que inicial o pausa la captura de paquetes en el sniffer
void MainWindow::on_capture_clicked()
{
    /* if is running then it is not the first time it is sent to capture. */
    /* si esta corriendo entonces no es la primra ves que se envia a
       capturar. */
    if(sniff_thread.isRunning()){
        if(ui->capture->text() == "Capture"){
            qDebug() << "Now Capture" ;
            sniff->setDevice(ui->selDevices->currentText().toStdString()) ;
            mutex.lock();
            pause = 0 ;
            wait_pause.wakeAll();
            mutex.unlock();
            ui->capture->setText("Stop");
            ui->resetButton->setEnabled(true);
            ui->resetButton->setEnabled(false);
        }
        else{
            mutex.lock();
            pause = 1 ;
            mutex.unlock();
            qDebug() << "Now Stop" ;
            ui->capture->setText("Capture") ;
            ui->resetButton->setEnabled(true);

        }
    }
    else{
        //qDebug() << "First time\n" ;
        sniff->setDevice(ui->selDevices->currentText().toStdString()) ;
        //sniff->setFilter(ui->filterText->toPlainText().toStdString()) ;
        sniff_thread.start() ;
        ui->capture->setText("Stop");
    }
}

/// \fn void MainWindow::handleResults(unsigned long index)
/// \~English
/// \brief A signal was received from the sniffer that a packet of the form
/// Ethernet -> IP -> (TCP|UDP) has to be displayed in the GUI.
/// Also checks if the packet is an http image request to display.
/// \param index number of the packet in the table
/// \~Spanish
/// \brief Una senal es recibida desde el sniffer que un paquete de la forma
/// Ethernet ->IP -> (TCP|UDP) tiene que ser desplegado en el GUI.
/// Tambien revisa si el paquete es una solicitud a una imagen en http
/// para desplegar.
/// \param index numero de el paquete en la tabla
void MainWindow::handleResults(unsigned long index){

 vector<ip_packet> *pkt  = sniff->getPacketList() ;

 /* Packet is added to the GUI packet list */
 /* Se anade el paquete al la lista de paquete el GUI */
 ui->packetDisplay->insertRow(ui->packetDisplay->rowCount());
 ui->packetDisplay->setItem(ui->packetDisplay->rowCount()-1, 0, new QTableWidgetItem(QString::fromStdString(pkt->at(index-1).getIPSAddress()))) ;
 ui->packetDisplay->setItem(ui->packetDisplay->rowCount()-1, 1, new QTableWidgetItem(QString::fromStdString(pkt->at(index-1).getIPDAddress()))) ;
 ui->packetDisplay->setItem(ui->packetDisplay->rowCount()-1, 2, new QTableWidgetItem(QString::number(pkt->at(index-1).getIPSPort()))) ;
 ui->packetDisplay->setItem(ui->packetDisplay->rowCount()-1, 3, new QTableWidgetItem(QString::number(pkt->at(index-1).getIPDPort()))) ;
 ui->packetDisplay->setItem(ui->packetDisplay->rowCount()-1, 4, new QTableWidgetItem(QString::number(pkt->at(index-1).getIPProto()))) ;

 /* Check if the packet is an http image request */
 /* Revisa si el paquete es una solicitud de imagen en http */
 imagepacket hrI ;
 if(pkt->at(index-1).getIPDPort() == 80){
     if(hrI.isImage(pkt->at(index-1).getPayload())){
        if(!imageList.contains(hrI.getImage())){
            QUrl url(QStringLiteral("http://")+hrI.getImage());
            QNetworkRequest request(url);
            netManager->get(request);
            imageList << hrI.getImage() ;
        }
        else{
            imageList.removeOne(hrI.getImage()) ;
        }
     }
 }
}

/// \fn void MainWindow::on_packetDisplay_itemClicked(QTableWidgetItem *item)
/// \~English
/// \brief When a line of the packets captured is selected from the GUI
/// a summary of the payload in ascii is presented in the summary box.
/// \param item item selected in the GUI
/// \~Spanish
/// \brief Cuando una linea de los paquetes es seleccionada desde el GUI
/// un resumen de la carga en ascii es presentado en la caja de resumen.
/// \param item articulo seleccionado en el GUI
void MainWindow::on_packetDisplay_itemClicked(QTableWidgetItem *item)
{
    vector<ip_packet> *pkt  = sniff->getPacketList() ;
    string payload = pkt->at(item->row()).getPayload() ;
    QString summary = "Source Hardware Address: " + QString::fromStdString(pkt->at(item->row()).getEtherSHost()) +
                    "\nDestin Hardware Address: " + QString::fromStdString(pkt->at(item->row()).getEtherDHost()) +
                    "\nSource IP Address: " + QString::fromStdString(pkt->at(item->row()).getIPSAddress()) +
                    "\nSource IP Address: " + QString::fromStdString(pkt->at(item->row()).getIPDAddress()) +
                    "\nTransport Proto: " + QString::number(pkt->at(item->row()).getIPProto()) +
                    "\nSource Port: " + QString::number(pkt->at(item->row()).getIPSPort()) +
                    "\nDestin Port: " + QString::number(pkt->at(item->row()).getIPDPort()) +
                    "\n" + QString::fromStdString(sniff->format_payload(payload.c_str(), payload.size())) ;
    ui->packetSummary->setText(summary);
}

/// \fn void MainWindow::on_resetButton_clicked()
/// \~English
/// \brief Empties the packets vector, resets the GUI packet table and
/// summary
/// \~Spanish
/// \brief Vacia el vector de paquetes, reajusta la tabla de paquetes y
/// el resumen del GUI.
void MainWindow::on_resetButton_clicked()
{
    vector<ip_packet> *pkt = sniff->getPacketList() ;
    pkt->clear() ;
    ui->packetDisplay->setRowCount(0);
    ui->packetSummary->setText("");
}
