#include <QtGui>

 #include "mainwindow.h"
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include "C:\Users\user\Desktop\qt\Task2\liblinear-1.8\linear.h"

#define Malloc(type,n) (type *)malloc((n)*sizeof(type))
  const int NUM_FEATURES = 2000;

MainWindow::MainWindow()
{
    window = new QWidget;
    mainLayout= new QVBoxLayout;
    labelIm = new QLabel;
    layout1 = new QHBoxLayout;
    layout2 = new QHBoxLayout;
    button0 = new QPushButton("&Use Previous Model");
    button1 = new QPushButton("&Train");
    button2 = new QPushButton("&Searching in the directory");
    button3 = new QPushButton("&Searching in an image");
    button4 = new QPushButton("&Exit");
    button5 = new QPushButton("&Retrain");


    layout2->addWidget(button0, 8);
    layout2->addWidget(button1, 8);
    //layout1->addWidget(labelIm);
    mainLayout->addLayout(layout2);
    mainLayout->addLayout(layout1);
    //curFile = QFileDialog::getOpenFileName(this);
    window->setLayout(mainLayout);
    setCentralWidget(window);

    createActions();
    createStatusBar();
}

MainWindow::~MainWindow()
{

}

void MainWindow::training()
{
    msg1 = "Input the directory with training Images";
    msg2 = "Input the file with locations";
    msg3 = "Output the file with model";
    files(true ,true ,true, false);
    getFilesTr();
    statusBar()->showMessage("Training Completed", 2000);
    inFile->close();
    outFile->close();
    menu2();
}

void MainWindow::usingModel()
{
    msg3 = "Input the file with model";
    files(false ,false ,true ,false);
    menu2();
}

void MainWindow::menu2()
{
    delete button1;
    delete button0;
    layout1->addWidget(labelIm);
    layout2->addWidget(button2, 8);
    layout2->addWidget(button3, 8);
    layout2->addWidget(button5, 8);
    layout2->addWidget(button4, 8);
}

void MainWindow::getFilesTr()
{
    inFile = new QFile(curInFile);
    inFile->open(QIODevice::ReadOnly);
    char temp2[200];
    int Num, Xmin, Ymin, Xmax, Ymax;
    //inFile->readLine(temp2, 200);
    outFile = new QFile(curOutFile);
    outFile->open(QIODevice::ReadWrite | QIODevice::Truncate);
    int cnt = 0;
    curHist = new int[2000];
    while ((inFile->readLine(temp2, 200)) > 0)
    {
        sscanf(temp2, "%d %d %d %d %d", &Num, &Ymin, &Xmin, &Ymax, &Xmax);
        //Num = 1;
        getFileNameFromInt(Num);
        if (cnt > 0)
        {
            delete image;
            delete curImage;
        }
        image = new QPixmap;
        image->load(*curFile);
        labelIm->setPixmap(*image);
        curImage = new QImage(image->toImage());
        for (int j = 0; j <= 1999; j++)
            curHist[j] = 0;
        makeHOG(Ymin, Xmin, Ymax, Xmax);
        trainModel(true);
        int t = curImage->width();
        for (int m = 0; m < t - 80; m += 10)
        {
            if ((m < (Xmin - 60)) || (m > (Xmax - 20)))
            {
                for (int j = 0; j <= 1999; j++)
                    curHist[j] = 0;
                makeHOG(Ymin, m, Ymax, m + 80);
                trainModel(false);
            }
        }
        /*if (Xmin > 100)
        {
            dec = 0;
            int Xmin2 = inc++;
            int Xmax2 = Xmin2 + 80;
            makeHOG(Ymin, Xmin2, Ymax, Xmax2);
            trainModel(false);
            for (int j = 0; j < 2000; j++)
            {
                qint64 to;
                int ty = curHist[j];
                sprintf(temp2, "%d,", ty);
                to = outFile->write(temp2);
            }
            outFile->write("false\n");
        }
        //outFile->flush();
        for (int j = 0; j <= 1999; j++)
            curHist[j] = 0;
        if (Xmax < curImage->height() - 100)
        {
            inc = 0;
            int Xmax1 = curImage->height() - dec++;
            int Xmin1 = Xmax1 - 80;
            makeHOG(Ymin, Xmin1, Ymax, Xmax1);
            trainModel(false);*/
        //}


        cnt++;

    }
    delete[] curHist;
    makeModel();
}

void MainWindow::getFilesSDir()
{
    inFile = new QFile(curInFile);
    inFile->open(QIODevice::ReadOnly);
    char temp2[200];
    int Num;

    while (inFile->readLine(temp2, 200) > 0)
    {
        sscanf(temp2, "%d", &Num);
        getFileNameFromInt(Num);
        useImage(Num);

    }
    delete[] curHist;
}

void MainWindow::getFilesSImg()
{
    int Num = 0;
    curFile = new QString(curInFile);
    useImage(Num);
    delete[] curHist;
}

void MainWindow::useImage(int Num)
{
    char temp2[200];
    image = new QPixmap;
    image->load(*curFile);
    outFile->open(QIODevice::WriteOnly);
    labelIm->setPixmap(*image);
    curImage = new QImage(image->toImage());;
    curHist = new int[2000];
    for (int j = 0; j <= 1999; j++)
        curHist[j] = 0;
    for (int X = 0; X < (curImage->width() - 80); X += 5)
    {
        makeHOG(0, X, 200, X + 80);
        bool b = testModel();
        if (b)
        {
            sprintf(temp2, "%d, %d, %d, %d, %d \n", Num, 0, X, 200 ,X + 80);
            paint(0, X, 200, X + 80);
            outFile->write(temp2);
            outFile->flush();
        }
    }
    image->convertFromImage(*curImage);
    outFile->close();
    repaint();
}

void MainWindow::paint(int Ymin, int Xmin, int Ymax, int Xmax)
{
    int i , k;
    for (i = Xmin + 2; i <  Xmax - 2; i++)
        for (k = (-1); k <  2; k++)
        {
            curImage->setPixel(i + k , Ymin, qRgb(0 ,255 ,0));
            curImage->setPixel(i + k , Ymax, qRgb(0 ,255 ,0));
        }
    for (i = Ymin + 1; i <  Ymax - 2; i++)
        for (k = (-1); k <  2; k++)
        {
            curImage->setPixel(Xmin , i + k, qRgb(0 ,255 ,0));
            curImage->setPixel(Xmax , i + k, qRgb(0 ,255 ,0));
        }

}

void MainWindow::getFileNameFromInt(int i)
{
    int tc , td  , te;
    char c , d , e , f = '\\';
    QString ras = ".png";
    int k = 4;
    tc = i / 100;
    td = (i - tc * 100) / 10;
    te = i - tc * 100 - td * 10;
    if (tc == 0)
    {
        c = '0';
        k--;
    }
     else c = '0' + tc;
    if ((td == 0) && (tc == 0))
    {
        d = '0';
        k--;
    }
     else d = '0' + td;
    e = '0' + te;
    curFile = new QString(curCat);
    *curFile +=  f;
    if (k > 3) *curFile += c;
    if (k > 2) *curFile += d;
    *curFile += e;
    *curFile += ras;

    char temp[8];
    temp[0] = c;
    temp[1] = d;
    temp[2] = e;
    temp[3] = '.';
    temp[4] = 'p';
    temp[5] = 'n';
    temp[6] = 'g';
    temp[7] = '\0';
    statusBar()->showMessage(temp, 2000);
}

void MainWindow::makeHOG(int Ymin, int Xmin, int Ymax, int Xmax)
{
    int N = 3;
    int **wind1;
    wind1 = new int*[3];
    for (int i = 0; i < 3; i++)
                wind1[i] = new int[3];
    wind1[0][0] = 1;
    wind1[1][0] = 2;
    wind1[2][0] = 1;
    wind1[0][1] = 0;
    wind1[1][1] = 0;
    wind1[2][1] = 0;
    wind1[0][2] = -1;
    wind1[1][2] = -2;
    wind1[2][2] = -1;

    int **tempXred;
    tempXred = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tempXred[i] = new int[curImage->height()];

    int **tempXgreen;
    tempXgreen = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tempXgreen[i] = new int[curImage->height()];

    int **tempXblue;
    tempXblue = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tempXblue[i] = new int[curImage->height()];

    int **tempYred;
    tempYred = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tempYred[i] = new int[curImage->height()];

    int **tempYgreen;
    tempYgreen = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tempYgreen[i] = new int[curImage->height()];

    int **tempYblue;
    tempYblue = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tempYblue[i] = new int[curImage->height()];


    int **tw;
    tw = new int*[curImage->width()];
    for (int i = 0; i < curImage->width(); i++)
            tw[i] = new int[curImage->height()];


    for (int i = 0; i < curImage->width(); i++)
    {
        for (int j = 0; j < curImage->height(); j++)
        {
            tempXred[i][j] = qRed(curImage->pixel(i , j));
            tw[i][j] = tempXred[i][j];
        }
    }
    wash(tw, tempXred, Ymin, Xmin, Ymax, Xmax, N, wind1 , true);

    for (int i = 0; i < curImage->width(); i++)
    {
        for (int j = 0; j < curImage->height(); j++)
        {
            tempXgreen[i][j] = qGreen(curImage->pixel(i , j));
            tw[i][j] = tempXgreen[i][j];
        }
    }
    wash(tw, tempXgreen, Ymin, Xmin, Ymax, Xmax, N, wind1 , true);

    for (int i = 0; i < curImage->width(); i++)
    {
        for (int j = 0; j < curImage->height(); j++)
        {
            tempXblue[i][j] = qBlue(curImage->pixel(i , j));
            tw[i][j] = tempXblue[i][j];
        }
    }
    wash(tw, tempXblue, Ymin, Xmin, Ymax, Xmax, N, wind1 , true);

    for (int i = 0; i < curImage->width(); i++)
    {
        for (int j = 0; j < curImage->height(); j++)
        {
            tempYred[i][j] = qRed(curImage->pixel(i , j));
            tw[i][j] = tempYred[i][j];
        }
    }
    wash(tw, tempYred, Xmin, Ymin, Xmax, Ymax, N, wind1 , false);

    for (int i = 0; i < curImage->width(); i++)
    {
        for (int j = 0; j < curImage->height(); j++)
        {
            tempYgreen[i][j] = qGreen(curImage->pixel(i , j));
            tw[i][j] = tempYgreen[i][j];
        }
    }

    wash(tw, tempYblue, Xmin, Ymin, Xmax, Ymax, N, wind1 , false);

    for (int i = 0; i < curImage->width(); i++)
    {
        for (int j = 0; j < curImage->height(); j++)
        {
            tempYblue[i][j] = qBlue(curImage->pixel(i , j));
            tw[i][j] = tempYblue[i][j];
        }
    }
    wash(tw, tempYblue, Xmin, Ymin, Xmax, Ymax, N, wind1 , false);
    //image->fromImage(*Temp0);
    //TempY->save(*curFile);
    double Angle, green, blue, red;
    int Num;
    for (int i = Xmin; i < Xmax; i++)
    {
        for (int j = Ymin; j < Ymax; j++)
        {
            double PI = asin(1) * 2;
            Num = (((j - Ymin) / 8) * 10 + ((i - Xmin) / 8)) * 8;
            if (tempXred[i][j]) red = atan((double)tempYred[i][j] / tempXred[i][j]) + PI / 2;
            else red = PI / 2;
            if (tempXgreen[i][j]) green = atan((double)tempYgreen[i][j] / tempXgreen[i][j]) + PI / 2;
            else green = PI / 2;
            if (tempXblue[i][j]) blue = atan((double)tempYblue[i][j] / tempXblue[i][j]) + PI / 2;
            else blue = PI / 2;
            if (red > blue) Angle = red;
            else Angle = blue;
            if (green > Angle) Angle = green;
            //Num += trunc(Angle / PI * 8 );
            //curHist[Num + (int)trunc(red / PI * 8 )]++;
            //curHist[Num + (int)trunc(green / PI * 8 )]++;
            //curHist[Num + (int)trunc(blue / PI * 8 )]++;
            curHist[Num + (int)trunc(Angle / PI * 8 )]++;
        }
    }


    for (int i = 0; i < curImage->width(); i++)
            delete[] tempXred[i];
    delete[] tempXred;

    for (int i = 0; i < curImage->width(); i++)
            delete[] tempXgreen[i];
    delete[] tempXgreen;

    for (int i = 0; i < curImage->width(); i++)
            delete[] tempXblue[i];
    delete[] tempXblue;

    for (int i = 0; i < curImage->width(); i++)
            delete[] tempYred[i];
    delete[] tempYred;

    for (int i = 0; i < curImage->width(); i++)
            delete[] tempYgreen[i];
    delete[] tempYgreen;

    for (int i = 0; i < curImage->width(); i++)
            delete[] tempYblue[i];
    delete[] tempYblue;

    for (int i = 0; i < curImage->width(); i++)
            delete[] tw[i];
    delete[] tw;

    return;
}

void MainWindow::trainModel(const bool t)
{

  // PARSE INPUT and split into train and test data

    std::vector<double> features(NUM_FEATURES);
    for (int j = 0; j < NUM_FEATURES; j++)
        features[j] = curHist[j];

    int intLab;
    if (t) intLab = 1;
     else intLab = (-1);

    // odd cnt => instance goes to test set, even => to train set
    trainFeatures.push_back(features);
    trainLabels.push_back(intLab);

  assert(trainLabels.size() == trainFeatures.size());
}


void MainWindow::makeModel()
{
  // FILL TRAIN STRUCTURE AND TRAIN
  struct problem prob;
  prob.l = int(trainLabels.size()); // number of instances
  prob.bias = -1; // bias feature
  prob.n = NUM_FEATURES; // number of features + one for bias if needed

  prob.y = Malloc(int, prob.l); // allocate space for labels
  prob.x = Malloc(struct feature_node *, prob.l); // allocate space for features

  for (size_t i = 0; i < trainLabels.size(); i++)
  {
    prob.x[i] = Malloc(struct feature_node, NUM_FEATURES+1);
    prob.x[i][NUM_FEATURES].index = -1;  // -1 marks the end of list
    for (int j = 0; j < NUM_FEATURES; j++)
    {
      prob.x[i][j].index = 1+j; // 1-based feature number
      prob.x[i][j].value = trainFeatures[i][j];
    }
    prob.y[i] = trainLabels[i];
  }


  // default values of params. don't change them if not sure (unless param.C)
  struct parameter param;
  param.solver_type = L2R_L2LOSS_SVC_DUAL;
  param.C = 1;
  param.eps = 1e-4;
  param.nr_weight = 0;
  param.weight_label = NULL;
  param.weight = NULL;

  struct model* myModel = train(&prob, &param);

  // SAVE MODEL FOR PREDICTION

  if(save_model(qPrintable(curModelFile), myModel))
  {
    std:: cerr << "can't save model to file " << std::endl;
    return;
  }

  free_and_destroy_model(&myModel);
  destroy_param(&param);
  free(prob.y);
  for (int i = 0; i < prob.l; i++) free(prob.x[i]);
  free(prob.x);
  return;
}


bool MainWindow::testModel()
{
  //int corr = 0;
  struct feature_node* x = Malloc(struct feature_node, NUM_FEATURES+1);
  x[NUM_FEATURES].index = -1;  // -1 marks the end of list

    for (int j = 0; j < NUM_FEATURES; j++)
    {
      x[j].index = 1+j; // 1-based feature number
      x[j].value = curHist[j];
    }

    int predict_label = predict(myModel,x);
    /*if (predict_label == testLabels[i])
    {
      ++corr;
    }*/
  free(x);

  //std::cout << "Accuracy is " << double(corr) / testLabels.size() << std::endl;


  /*// PREDICTION WITH CONFIDENCE
  std::cout << "Confidences of prediction for Iris-setosa: ";
  {
  //int corr = 0;
  struct feature_node* x = Malloc(struct feature_node, NUM_FEATURES+1);
  x[NUM_FEATURES].index = -1;  // -1 marks the end of list
  double prob_estimates[1];
  for (size_t i = 0; i < testLabels.size(); i++)
  {
    for (int j = 0; j < NUM_FEATURES; j++)
    {
      x[j].index = 1+j; // 1-based feature number
      x[j].value = testFeatures[i][j];
    }

    predict_values(myModel,x,prob_estimates);
    std::cout << prob_estimates[0] << " "; // confidence for the first class (+1, in our case)
  }
  free(x);
  }*/

  if (predict_label >= 0) return (true);
  else return (false);
}

void MainWindow::wash(int **temp1,int **Temp,int koef1, int koef2, int koef3, int koef4, int N, int **wind, bool a)
{
    int i , j , k, l;
    double d;

    for (i = koef1; i < koef3; i++)
        for (j = koef2; j < koef4; j++)
        {
            d = 0;
            for (k = (-1) ; k < N - 1 ; k++)
                for (l = (-1) ; l < N - 1 ; l++)
                    if (((j + k) >= koef2) && ((j + k) < koef4) && ((i + l) >= koef1) && ((i + l) < koef3))
                    {
                        if (a)
                        {
                            d +=temp1[j + k][i + l] * wind[k + 1][l + 1];
                        }
                        else
                        {
                            d +=temp1[i + l][j + k] * wind[k + 1][l + 1];
                        }
                    }
            if (a)
                Temp[j][i]= d;
            else
                Temp[i][j] = d;
        }
}

void MainWindow::serIn()
{
    msg2 = "Input the Image";
    msg4 = "Output the file with locations";
    files(false ,true ,false ,true);

    outFile = new QFile(curOutFile);
    outFile->open(QIODevice::ReadWrite | QIODevice::Truncate);
    outFile->close();
    // NOW LOAD MODEL AND CLASSIFY
    if((myModel=load_model(qPrintable(curModelFile)))!=0)
    {
        getFilesSImg();
        statusBar()->showMessage("Searching in the Image Completed", 2000);
    }
    else statusBar()->showMessage("can't load model from file", 2000);
    free_and_destroy_model(&myModel);
}

void MainWindow::serDir()
{
    msg1 = "Input the directory with testing Images";
    msg2 = "Input the file with names of images";
    msg4 = "Output the file with locations";
    files(true ,true, false, true);

    outFile = new QFile(curOutFile);
    outFile->open(QIODevice::ReadWrite | QIODevice::Truncate);
    outFile->close();
    // NOW LOAD MODEL AND CLASSIFY
    if((myModel=load_model(qPrintable(curModelFile)))!=0)
    {
        getFilesSDir();
        statusBar()->showMessage("Searching in the directory Completed", 2000);
    }
    else statusBar()->showMessage("can't load model from file", 2000);
    free_and_destroy_model(&myModel);
}

void MainWindow::files(bool a , bool b , bool c , bool d)
{
    QMessageBox msgBox;
    if (a)
    {

        msgBox.setWindowTitle("Message");
        msgBox.setText(msg1);
        msgBox.exec();
        QString newCat;
        do
            newCat = QFileDialog::getExistingDirectory(this);
        while (newCat.isEmpty());
        curCat = newCat;
    }

    if (b)
    {
        msgBox.setWindowTitle("Message");
        msgBox.setText(msg2);
        msgBox.exec();
        QString newInFile;
        do
            newInFile = QFileDialog::getOpenFileName(this);
        while (newInFile.isEmpty());
        curInFile = newInFile;
    }

    if (c)
    {
        msgBox.setWindowTitle("Message");
        msgBox.setText(msg3);
        msgBox.exec();
        QString newModelFile;
        do
            newModelFile = QFileDialog::getOpenFileName(this);
        while (newModelFile.isEmpty());
        curModelFile = newModelFile;

    }

    if (d)
    {
        msgBox.setWindowTitle("Message");
        msgBox.setText(msg4);
        msgBox.exec();
        QString newOutFile;
        do
            newOutFile = QFileDialog::getOpenFileName(this);
        while (newOutFile.isEmpty());
        curOutFile = newOutFile;
    }

}

void MainWindow::exit()
{
    QMessageBox msgBox;
    msgBox.setWindowTitle("Exit");
    msgBox.setText("Thank you for using my Program)) Goodbye!!");
    msgBox.exec();
    close();
}

void MainWindow::createActions()
{
    useAct = new QAction(tr("&Use the Model..."), this);
    useAct->setStatusTip(tr("Use the Model"));
    connect(button0, SIGNAL(pressed()), this, SLOT(usingModel()));

    trainAct = new QAction(tr("&train..."), this);
    trainAct->setStatusTip(tr("train"));
    connect(button1, SIGNAL(pressed()), this, SLOT(training()));

    retrainAct = new QAction(tr("&retrain..."), this);
    retrainAct->setStatusTip(tr("retrain"));
    connect(button5, SIGNAL(pressed()), this, SLOT(training()));

    serDirAct = new QAction(tr("&tra..."), this);
    serDirAct->setStatusTip(tr("tra"));
    connect(button2, SIGNAL(pressed()), this, SLOT(serDir()));

    serImAct = new QAction(tr("&tr..."), this);
    serImAct->setStatusTip(tr("tr"));
    connect(button3, SIGNAL(pressed()), this, SLOT(serIn()));

    exitAct = new QAction(tr("&in..."), this);
    exitAct->setStatusTip(tr("in"));
    connect(button4, SIGNAL(pressed()), this, SLOT(exit()));


}

void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}
