#include "my_image.h"
//konstruktory:
my_image::my_image(IplImage *img)
{
    if(img==NULL)
        return;

    this->width=img->width;
    this->height=img->height;
    this->depth=img->depth;
    this->nChannels=img->nChannels;

    //std::cout<<"depth: "<<this->depth<<" nchannels: "<<this->nChannels<<"\n";

    this->data=this->alocate_mem();

    CvScalar color;
    for(int x=0;x<this->width;x++)
        for(int y=0;y<this->height;y++)
        {
            color=cvGet2D(img,y,x);
            this->data[x][y]=(uchar)color.val[0];
        }

}


my_image::my_image(my_image *img){
this->width=img->width;
this->height=img->height;
this->depth=img->depth;
this->nChannels=img->nChannels;

this->data=this->alocate_mem();

for(int x=0;x<this->width;x++)
    for(int y=0;y<this->height;y++)
        this->data[x][y]=img->data[x][y];

}

my_image::my_image(uchar *data, int width, int height,int Channels){

    this->width=width;
    this->height=height;
    this->depth=8;
    this->nChannels=Channels;

    this->data=this->alocate_mem();

    int k=0;
    for(int y=0;y<height;y++)
        for(int x=0;x<width;x++)
        {
            this->data[x][y]=data[k];
            k+=Channels;
        }
}


uchar my_image::get(BOD bod){
return this->get(bod.x,bod.y );
}


uchar my_image::get(int x, int y){
    if(this->data==NULL){
        // throw "Neni nacten obraz, nemuzes pouzit metodu my_image.get()";
        std::cout<<"Neni nacten obraz, nemuzes pouzit metodu my_image.get() \n";
        return 0;
    }
    if(x<0 || x>=this->width){
       // throw "Sahas mimo obraz my_image.get() couradnice x";
        std::cout<<"Sahas mimo obraz my_image.get() couradnice x: "<<x<<"ale sirka je "<<this->width<<" \n"<<std::endl;
        return 0;
    }

    if(y<0 || y>=this->height){
      //  throw "Sahas mimo obraz my_image.get() couradnice y";
        std::cout<<"Sahas mimo obraz my_image.get() couradnice y: "<<y<<"ale vyska je "<<this->height<<" \n"<<std::endl;

        return 0;
    }
    return data[x][y];;
}



void my_image::set(int x, int y,uchar color){
    if(this->data==NULL){
        // throw "Neni nacten obraz, nemuzes pouzit metodu my_image.set()";
        std::cout<<"Neni nacten obraz, nemuzes pouzit metodu my_image.set() \n";
        return;
    }
    if(x<0 || x>=this->width){
       // throw "Sahas mimo obraz my_image.set() couradnice x";
        std::cout<<"Sahas mimo obraz my_image.set() couradnice x: "<<x<<"ale sirka je "<<this->width<<" \n";
        return;
    }

    if(y<0 || y>=this->height){
      //  throw "Sahas mimo obraz my_image.set() couradnice y";
        std::cout<<"Sahas mimo obraz my_image.set() couradnice y: "<<y<<"ale vyska je "<<this->height<<" \n";

        return;
    }
    data[x][y]=color;
}



IplImage * my_image::get_cv_image()
{

    if(this->data==NULL){
        std::cout<<"nenacten zadny obraz :-/";
        return NULL;
    }

    CvScalar color;
   IplImage * img= cvCreateImage( cvSize(this->width,this->height ),this->depth,this->nChannels);


for(int x=0;x<this->width;x++)
    for(int y=0;y<this->height;y++)
    {
        color.val[0]=this->data[x][y];
        color.val[1]=color.val[0];
        color.val[2]=color.val[0];

        cvSet2D(img,y,x,color); // set the (i,j) pixel value
    }

   return img;
}


uchar ** my_image::alocate_mem(){
    //alokace pameti
    uchar **d=NULL;
    d=(uchar **)calloc((this->width),sizeof(uchar*));
    if(d==NULL){
        std::cout<<"NEMAM PAMET my_image\n";
        return NULL;
    }
    for(int i=0;i<this->width;i++){
        d[i]=NULL;
        d[i]=(uchar *)calloc(this->height,sizeof(uchar));
        if(d[i]==NULL)  {
            std::cout<<"NEMAM PAMET my_image\n";
            return NULL;
        }
    }

    return d;
}

int my_image::Width(){
    return this->width;
}
int my_image::Height(){
    return this->height;
}

void my_image::clean_all(){
    for(int x=0;x<this->width;x++)
        for(int y=0;y<this->height;y++)
        {
            this->data[x][y]=0;
        }
}


void my_image::white_all(){
    for(int x=0;x<this->width;x++)
        for(int y=0;y<this->height;y++)
        {
            this->data[x][y]=255;
        }
}


void my_image::norm_gradiend(){
    //1)vypocet gradiendu,zjisteni maxima
    //2)normalizace mopoci maxima , nahradi normalizace do obrazu

    //gradient pocitam pomoci masky  -1 0 1


    uchar a,b;
    int gradiend,max =0;
    //a,b,gradiend jsou hodnoty jasu v kazdem kroku
    //max je maximalni gradiend v obraze

    char *buffer=new char[this->width*this->height];
    //buffer pole gradiendu,usporadane po sloupcich->
    //prvky v poli vedle sebe == v obraze pod sebou

    //vypocet gradiendu (ulozeni do buffer) ,z jisteni maxima
    for(int x=0;x<this->width;x++){
        for(int y=0;y<this->height;y++)
        {
            if(x<=0 || x>=(this->width-1) ){//zde nemohu vypocitat gradiend
                buffer[(x*this->height)+y]=0;
                continue;
            }
            a=this->get(x-1,y);
            b=this->get(x+1,y);
            gradiend=a-b;
            if(gradiend<0)
                gradiend=gradiend*-1;
            buffer[(x*this->height)+y]=gradiend;
            if(gradiend>max)
                max=gradiend;
        }
    }

    std::cout<<"maximum gradiendu je "<<max<<"\n";

    //normalizace gradiendu (podeleni gradiendu  maximem a  ulozeni do obrazu)
    float norma;
    for(int x=0;x<this->width;x++){
        for(int y=0;y<this->height;y++){
            norma=(float)buffer[(x*this->height)+y]/(float)max;
    /*        if(norma>0.1)
                img->set(x,y,255);
            else
                img->set(x,y,0);
    */
            this->set(x,y,norma*255);
        }
    }



delete []buffer;
}



void my_image::delete_memory(uchar** memory){
    for(int i=0;i<this->width;i++)
        free (memory[i]);
    free(memory);
}

my_image::~my_image()
{
    this->delete_memory(this->data);
    /*for(int i=0;i<this->width;i++)
        free (this->data[i]);
    free(this->data);*/
}



void my_image::invert_color(){
    if(data==NULL){
        std::cout<<"obraz je nulovy!!!";
        return;
    }
    for(int x=0;x<this->width;x++)
        for(int y=0;y<this->height;y++)
        {
            this->data[x][y]=255-this->data[x][y];
        }
return ;
}


void my_image::prahuj(uchar prah,bool blackNwhite){
    if(data==NULL){
        std::cout<<"obraz je nulovy!!!";
        return;
    }
    for(int x=0;x<this->width;x++)
        for(int y=0;y<this->height;y++){
            if(this->data[x][y]>=prah){
                this->data[x][y]=255;
            }
            else{
                if(blackNwhite){this->data[x][y]=0;}
            }
        }
return ;
}

