#include <fstream>
using std::ifstream;
using std::ios;

#include "BMP.h"

#include "type_image.h"

//////////////////////////////////////////////////////////////////////
//                                                                  //
//  Cette fonction sert à charger la matrice des couleurs d'une     //
//  fichier en format .bmp et retourne vrai en cas de succès, faux  //
//  autrement.                                                      //
//                                                                  //
////////////////////////////////////////////////////////////////////// 

bool type_image::ChargeBMP(const string &NomFic)
{
	Width = Height = 0;

	delete []PtrImage;

	bmpfileheader bmfh;
	bmpinfoheader bmih;
	ifstream FicImage;
	int i, j;
	unsigned char CouleurTemp;

	// On test l'ouverture du fichier
	FicImage.open(NomFic.c_str(), ios::binary);
	if (FicImage.fail())
		return false;

	// Lecture des entêtes du fichier
	FicImage.read( (char *) &bmfh.bfType, sizeof(unsigned short));
	FicImage.read( (char *) &bmfh.bfSize, sizeof(unsigned long));
	FicImage.read( (char *) &bmfh.bfReserved1, sizeof(unsigned short));
	FicImage.read( (char *) &bmfh.bfReserved2, sizeof(unsigned short));
	FicImage.read( (char *) &bmfh.bfOffBits, sizeof(unsigned long));
	
	FicImage.read( (char *) &bmih, sizeof(bmpinfoheader));

	// Vérifie le type du fichier
	if (bmfh.bfType != 'MB')
		return false;

	Width = bmih.biWidth;
	Height = bmih.biHeight;

	PtrImage = new float[Width*Height*3];

	if (!PtrImage)
		return false;

	// On vérifie s'il y a une table des couleurs
	if (bmih.biBitCount == 24)
	{
		for (j = bmih.biHeight; j > 0; j--)
		{
			for (i = 0; i < bmih.biWidth; i++)
			{
				FicImage.read( (char *) &CouleurTemp, sizeof(char));
				(*this)(i, (j-1), BLEU) = CouleurTemp / 255.0f;
				FicImage.read( (char *) &CouleurTemp, sizeof(char));
				(*this)(i, (j-1), VERT) = CouleurTemp / 255.0f;
				FicImage.read( (char *) &CouleurTemp, sizeof(char));
				(*this)(i, (j-1), ROUGE) = CouleurTemp / 255.0f;
			}

			// On passe par-dessus le offset des fins de lignes
			FicImage.seekg((4 - ((bmih.biWidth * 3) % 4)) % 4, ios::cur);
		}
	}
	else if (bmih.biBitCount == 32)
	{
		for (j = bmih.biHeight; j > 0; j--)
		{
			for (i = 0; i < bmih.biWidth; i++)
			{
				FicImage.read( (char *) &CouleurTemp, sizeof(char));
				(*this)(i, (j-1), BLEU) = CouleurTemp / 255.0f;
				FicImage.read( (char *) &CouleurTemp, sizeof(char));
				(*this)(i, (j-1), VERT) = CouleurTemp / 255.0f;
				FicImage.read( (char *) &CouleurTemp, sizeof(char));
				(*this)(i, (j-1), ROUGE) = CouleurTemp / 255.0f;

				FicImage.seekg(sizeof(char), ios::cur);
			}
		}
	}
	else// Il y une table de couleurs
	{
		// Nombre de couleurs est égal à 2^(BitPerPixel) si l'autre valeur est zéro
		int NbCouleurs = (bmih.biClrUsed) ? bmih.biClrUsed : (1 << bmih.biBitCount);

		unsigned char *CoulTable;
		CoulTable = new unsigned char[4*NbCouleurs];

		if (!CoulTable)
			return false;

		// Lecture de la table de couleurs
		for (i = 0; i < NbCouleurs; i++)
		{
			FicImage.read( (char *) &CoulTable[4*i + BLEU], sizeof(char));
			FicImage.read( (char *) &CoulTable[4*i + VERT], sizeof(char));
			FicImage.read( (char *) &CoulTable[4*i + ROUGE], sizeof(char));
			FicImage.read( (char *) &CoulTable[4*i + 3], sizeof(char));
		}

		// On détermine s'il y a de la compression
		if (!bmih.biCompression) // Pas de compression
		{
			switch (bmih.biBitCount)
			{
			case (1):
				for (j = Height; j > 0; j--)
				{
					for (i = 0; i < Width; i++)
					{
						if (!(i % 8))
							FicImage.read( (char *) &CouleurTemp, sizeof(char));

						(*this)(i, j-1, ROUGE) = 
							CoulTable[4*( (CouleurTemp >> (7 - (i % 8))) & 1) + ROUGE] / 255.0f;
						(*this)(i, j-1, VERT) = 
							CoulTable[4*( (CouleurTemp >> (7 - (i % 8))) & 1) + VERT] / 255.0f;
						(*this)(i, j-1, BLEU) = 
							CoulTable[4*( (CouleurTemp >> (7 - (i % 8))) & 1) + BLEU] / 255.0f;
						
					}

					FicImage.seekg( (4 - ((Width + 7) / 8) % 4) % 4, ios::cur);
				}
				break;

			case (4):
				for (j = Height; j > 0; j--)
				{
					for (i = 0; i < Width; i++)
					{
						if (!(i % 2))
						{
							FicImage.read( (char *) &CouleurTemp, sizeof(char));
							
							(*this)(i, j-1, ROUGE) = 
								CoulTable[4*((CouleurTemp >> 4) & 15) + ROUGE] / 255.0f;
							(*this)(i, j-1, VERT) = 
								CoulTable[4*((CouleurTemp >> 4) & 15) + VERT] / 255.0f;
							(*this)(i, j-1, BLEU) = 
								CoulTable[4*((CouleurTemp >> 4) & 15) + BLEU] / 255.0f;
						}
						else
						{
							(*this)(i, j-1, ROUGE) = 
								CoulTable[4*(CouleurTemp & 15) + ROUGE] / 255.0f;
							(*this)(i, j-1, VERT) = 
								CoulTable[4*(CouleurTemp & 15) + VERT] / 255.0f;
							(*this)(i, j-1, BLEU) = 
								CoulTable[4*(CouleurTemp & 15) + BLEU] / 255.0f;
						}
					}

					FicImage.seekg((4 - ((Width + 1) / 2) % 4) % 4, ios::cur);
				}
				break;

			case (8):
				for (j = Height; j > 0; j--)
				{
					for (i = 0; i < Width; i++)
					{
						FicImage.read( (char *) &CouleurTemp, sizeof(char));

						(*this)(i, j-1, ROUGE) = CoulTable[4*CouleurTemp + ROUGE] / 255.0f;
						(*this)(i, j-1, VERT) = CoulTable[4*CouleurTemp + VERT] / 255.0f;
						(*this)(i, j-1, BLEU) = CoulTable[4*CouleurTemp + BLEU] / 255.0f;
					}

					FicImage.seekg((4 - (Width % 4)) % 4, ios::cur);
				}
				break;

			default: exit(0);
			}



		}
		else // S'il y a de la compression
		{}






		delete [] CoulTable;
	}

	FicImage.close();

	return true;
}