/*
File: UTILS.CPP
Description: Defines all C++ functions used
*/

#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <stdio.h>
#include <iostream>
#include <string>

using namespace cv;
using namespace std;

int width = 50;
int height = 50;


extern "C" int row_size_cpp (char imageName[]) {
    Mat img = imread(imageName,CV_LOAD_IMAGE_COLOR);
    int rows = img.rows;
    return rows;
}


extern "C" int* dbl_arr_cpp () {
    int* foo = new int[2];
    foo[0] = 1;
    foo[1] = 2;
    return foo;
}


extern "C" double* dim_cpp (char imageName[]) {
    Mat img = imread(imageName,CV_LOAD_IMAGE_COLOR);
    double* output = new double[2];
    output[0] = (double) img.rows;
    output[1] = (double) img.cols;
    return output;
}


extern "C" double* load_cpp(char imageName[]) {
    Mat img = imread(imageName,CV_LOAD_IMAGE_COLOR);

    unsigned char* input = (unsigned char*)(img.data);
    double* output = new double[3*height*width];

    double r,g,b;
    int rows = img.rows;
    int cols = img.cols;
    int k = 0;
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            if ( i >= rows || j >= cols ) {
          	  b = 0;
          		output[k++] = b;
          		g = 0;
          		output[k++] = g;
          		r = 0;
          		output[k++] = r;
	           } else {
      	    	b = input[img.step * i + j*img.channels()] ;
      	    	output[k++]=b;
      	    	g = input[img.step * i + j*img.channels() + 1];
            	output[k++]=g;
            	r = input[img.step * i + j*img.channels() + 2];
            	output[k++]=r;
	           }
        }
    }
    return output;
}


extern "C" double* blur_cpp(char imageName[]) {
    Mat src = imread(imageName,CV_LOAD_IMAGE_COLOR);
    Mat img;

    blur(src, img, Size(10,10));

    unsigned char* input = (unsigned char*)(img.data);
    double* output = new double[3*height*width];

    double r,g,b;
    int rows = img.rows;
    int cols = img.cols;
    int k = 0;
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            if ( i >= rows || j >= cols ) {
                b = 0;
                output[k++] = b;
                g = 0;
                output[k++] = g;
                r = 0;
                output[k++] = r;
            } else {
                b = input[img.step * i + j*img.channels()] ;
                output[k++]=b;
                g = input[img.step * i + j*img.channels() + 1];
                output[k++]=g;
                r = input[img.step * i + j*img.channels() + 2];
                output[k++]=r;
            }
        }
    }
    return output;
}


extern "C" double* brighten_cpp(char imageName[])
{
    Mat src = imread(imageName,CV_LOAD_IMAGE_COLOR);
    Mat img;

    bilateralFilter(src, img, 15, 80, 80, BORDER_DEFAULT);

    unsigned char* input = (unsigned char*)(img.data);
    double* output = new double[3*height*width];

    double r,g,b;
    int rows = img.rows;
    int cols = img.cols;
    int k = 0;
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            if ( i >= rows || j >= cols ) {
                b = 0;
                output[k++] = b;
                g = 0;
                output[k++] = g;
                r = 0;
                output[k++] = r;
            } else {
                b = input[img.step * i + j*img.channels()] ;
                output[k++]=b;
                g = input[img.step * i + j*img.channels() + 1];
                output[k++]=g;
                r = input[img.step * i + j*img.channels() + 2];
                output[k++]=r;
            }
        }
    }
    return output;
}


extern "C" double* grayscale_cpp(char imageName[])
{
    Mat src = imread(imageName,CV_LOAD_IMAGE_COLOR);
    Mat img;

    cvtColor(src, img, COLOR_RGB2GRAY);

    unsigned char* input = (unsigned char*)(img.data);
    double* output = new double[3*height*width];

    double r,g,b;
    int rows = img.rows;
    int cols = img.cols;
    int k = 0;
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            if ( i >= rows || j >= cols ) {
                b = 0;
                output[k++] = b;
                g = 0;
                output[k++] = g;
                r = 0;
                output[k++] = r;
            } else {
                b = input[img.step * i + j*img.channels()] ;
                output[k++]=b;
                g = input[img.step * i + j*img.channels() + 1];
                output[k++]=g;
                r = input[img.step * i + j*img.channels() + 2];
                output[k++]=r;
            }
        }
    }
    return output;
}


extern "C" double* edgedetect_cpp(char imageName[])
{
    Mat src = imread(imageName,CV_LOAD_IMAGE_COLOR);
    Mat mid;
    Mat img;

    cvtColor(src, mid, COLOR_RGB2GRAY);
    Canny(mid, img, 60, 60*3);

    unsigned char* input = (unsigned char*)(img.data);
    double* output = new double[3*height*width];

    double r,g,b;
    int rows = img.rows;
    int cols = img.cols;
    int k = 0;
    for(int i = 0; i < width; i++){
        for(int j = 0; j < height; j++){
            if ( i >= rows || j >= cols ) {
                b = 0;
                output[k++] = b;
                g = 0;
                output[k++] = g;
                r = 0;
                output[k++] = r;
            }
            else {
                b = input[img.step * i + j*img.channels()] ;
                output[k++]=b;
                g = input[img.step * i + j*img.channels() + 1];
                output[k++]=g;
                r = input[img.step * i + j*img.channels() + 2];
                output[k++]=r;
            }
        }
    }
    return output;
}


extern "C" void save_cpp(double r[height][width], double g[height][width], double b[height][width]) {
	int h = height;
	int w = width;
	double* data = new double[3*h*w];

	for (int i = 0; i < w; i++) {
		for (int j = 0; j < h; j++) {
			data[3*(h*i+j)] = b[i][j];
			data[3*(h*i+j)+1] = g[i][j];
			data[3*(h*i+j)+2] = r[i][j];
		}
	}

	Mat image = cv::Mat(h, w, CV_64FC3, data);
    	imwrite("image_out.jpg",image);
    	return ;
}
