// Programación en C++ para Ingenieros, Ed. Thomson Paraninfo, 2006
// Capítulo 10: Ficheros



// Inclusión de las librerías
#include <iostream>
#include <fstream>
#include <math.h>

using namespace std;


// Color RGB
typedef struct{
     float red, green, blue;
}tColRGB;

// Imagen
typedef struct{
     tColRGB* pixels;
     int sizex, sizey;
}tImagen;


// Prototipos
void saltarComentarios(ifstream& imgFile);
void blanco(tColRGB& col);
void oscurecer(tColRGB& col);
bool coincideColor(tColRGB& col1, tColRGB& col2);
void writeImageFilePPM(char* filenam, tImagen& img);
void writeImageFilePPM(char* filenam, int* img, int sizex, int sizey);



void readImageFilePPM(char* filenam, tImagen& img)
{
    char c, type, buf[1024];
    int* imaAux;

    ifstream imgFile;
    imgFile.open( filenam );
    if( !imgFile )
    {
        cout << "No se puede abrir " << filenam << endl;
        exit( 1 );
    }
    imgFile >> c >> type;

    if( !((c=='P') && (type == '3')))
    {
        cout << "No puedo leer este tipo de fichero." << endl;
        exit(1);
    }

    // Salto el resto de la línea
    imgFile.getline(buf, 1000);
    saltarComentarios(imgFile);

    imgFile >> img.sizex;
    saltarComentarios(imgFile);

    imgFile >> img.sizey;
    saltarComentarios(imgFile);

    int depth;
    imgFile >> depth; // No la necesitamos

    // Reservamos espacio
    imaAux = new int [img.sizex * img.sizey * 3];
    img.pixels = new tColRGB [img.sizex * img.sizey ];
    if (!imaAux || !img.pixels)
    {
        cout << "No puedo reservar espacio." << endl;
        exit(1);
    }

    long i;
    for (i = 0; i < img.sizey * img.sizex * 3; i++)
    {
        imgFile >> imaAux[i];
        if (imaAux[i] < 0 || imaAux[i] > 255 )
            cout << "Em passo " << imaAux[i]<< endl;
    }
    imgFile.close();


    // Una vez leída, copiamos la imagen, aprovechamos para girarla
    // porque normalmente el sistema de coordenadas que se usa está cambiado
    for(i= 0; i< img.sizey ; i++ )
        for(int j= 0 ; j< img.sizex ; j++ )
        {
            img.pixels[i*img.sizex + j].red =
                (float)(imaAux[((img.sizey-1-i)*img.sizex+j)*3])/255.;
            img.pixels[i*img.sizex + j].green =
                (float)(imaAux[((img.sizey-1-i)*img.sizex+j)*3+1])/255.;
            img.pixels[i*img.sizex + j].blue =
                (float)(imaAux[((img.sizey-1-i)*img.sizex+j)*3+2])/255.;
        }
}



int main()
{
    int ii, jj;
    tImagen ima;
    tColRGB buscado;

    cout << "Introduce el color a buscar: ";
    cin >> buscado.red >> buscado.green >> buscado.blue;

    readImageFilePPM("Ficheroascii.ppm", ima);

    for (ii = 0; ii < ima.sizex; ii++)
    {
        for (jj = 0; jj < ima.sizey; jj++)
        {
            if (coincideColor(ima.pixels[ii*ima.sizex + jj], buscado))
            {
                // Ponemos a blanco los pixels que encontramos
                blanco(ima.pixels[ii*ima.sizex + jj]);
            }
            else
            {
                // Oscurecemos si no es el color buscado
                oscurecer(ima.pixels[ii*ima.sizex + jj]);
            }
        }
    }

    writeImageFilePPM("FicheroModificado.ppm", ima);

    return 0;
}



void blanco(tColRGB& col)
{
    col.red = 1.0;
    col.green = 1.0;
    col.blue = 1.0;
}


void oscurecer(tColRGB& col)
{
    col.red = __max (col.red - 0.2, 0.0);
    col.green = __max (col.green - 0.2, 0.0);
    col.blue = __max (col.blue - 0.2, 0.0);
}


bool coincideColor(tColRGB& col1, tColRGB& col2)
{
    bool resu;
    const float epsilon = 0.001f;

    resu = (fabs(col1.red - col2.red) < epsilon)
        && (fabs(col1.green - col2.green) < epsilon)
        && (fabs(col1.blue - col2.blue) < epsilon);

    return resu;
}


void saltarComentarios(ifstream& imgFile)
{
    char c, buf[1024];
    c = imgFile.peek();
    while (c == '#')
    {
        imgFile.getline(buf, 1000);
        c = imgFile.peek();
    }
}


void writeImageFilePPM(char* filenam, tImagen& img)
{
    int i, j, R, G, B;
    ofstream imgFile;

    imgFile.open( filenam);
    if( !imgFile )
    {
        cout << "No puedo abrir el fichero " << filenam << endl;
        exit( 1 );
    }

    imgFile << "P3 " << endl;
    imgFile << "# Fichero de imagen" << endl;

    imgFile << img.sizex << " " << img.sizey << endl << "255" << endl;


    for( i= img.sizey-1 ; i>=0; i--)
    {
        for( j= 0 ; j< img.sizex; j++ )
        {
            R = (int) (255 * img.pixels[(i*img.sizex + j)].red);
            G = (int) (255 * img.pixels[(i*img.sizex + j)].green);
            B = (int) (255 * img.pixels[(i*img.sizex + j)].blue);
            imgFile << R << " " << G << " " << B << " ";
        }
        imgFile << "\n";
    }
    imgFile.close( );
}

void writeImageFilePPM(char* filenam, int* im, int sizex, int sizey)
{
    ofstream imgFile;

    imgFile.open( filenam);
    if( !imgFile )
    {
        cout << "No puedo abrir el fichero " << filenam << endl;
        exit( 1 );
    }

    imgFile << "P3 " << endl;
    imgFile << "# Fichero de imagen" << endl;

    imgFile << sizex << " " << sizey << endl << "255" << endl;


    for (long int i = 0; i < sizey; i++)
    {
        for(long int j= 0 ; j< sizex; j++ )
        {
            int aux = (int) (255 * im[(i*sizey + j)*3]);
            imgFile << aux << " ";
            aux = (int) (255 * im[(i*sizey + j)*3+1]);
            imgFile << aux << " ";
            aux = (int) (255 * im[(i*sizey + j)*3+2]);
            imgFile << aux << " ";
        }
    }
    imgFile.close( );
}