#pragma once
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <fstream>
using namespace std;



struct Settings
{
	//��������� ��� bmp �����
	unsigned int imgWidth = 500, imgHeight = 500;
	unsigned char signature[2] = { 'B', 'M' };
	unsigned int fileSize = 14 + 40 + imgWidth * imgHeight * 3;
	unsigned int reserved = 0;
	unsigned int offset = 14 + 40;

	unsigned int headerSize = 40;
	unsigned int dimensions[2] = { imgWidth, imgHeight };
	unsigned short colorPlanes = 1;
	unsigned short bpp = 32;
	unsigned int compression = 0;
	unsigned int imgSize = imgWidth * imgHeight * 3;
	unsigned int resolution[2] = { 2795, 2795 };
	unsigned int pltColors = 0;
	unsigned int impColors = 0;
	int lineImgSize;
};



 class Pixel
{
	//������� �������
	public:
		int r;
		int g;
		int b;
		int a;

		Pixel()
		{
			this->r = 10;
			this->g = 10;
			this->b = 10;
			this->a = 0;
		};
		Pixel(int r, int g, int b, int a)
		{
			this->r = r;
			this->g = g;
			this->b = b;
			this->a = a;
		}
		Pixel(int r, int g, int b)
		{
			this->r = r;
			this->g = g;
			this->b = b;
			this->a = -1;
		}
};

 template <class T> class Row
{
	//������ ��������
	public:
		int width;
		T** pixel;
		Row() {};
		Row(int width)
		{
			this->width = width;
			pixel = new T*[width];
			for (int i = 0; i < width; i++)
			{
				pixel[i] = new T();
			}
		}
		T* operator[](int n) 
		{ 
			return pixel[n];
		}
};

 template <class T> class Img
{
	//����������� ����� �������
	public:
		int width, height, amount;
		Row <T>  *data;
		Settings settings;
		Img() {};
		Img(int width, int height, int amount)
		{
			this->width = width;
			this->height = height;
			this->amount = amount;

			init();
		}

		void init()
		{
			data = new Row <T>[height];
			for (int i = 0; i < height; i++)
			{
				data[i] = Row<T>(width);
			}
		}
		Row <T> operator[](int n)
		{
			return data[n];
		}	

};

class BMP : public Img <Pixel>
{
	//bmp ��������
	public:
		BMP() {};

		void read(string filename)
		{
			ifstream os(filename);

			os.read(reinterpret_cast<char*>(settings.signature), sizeof(settings.signature));
			os.read(reinterpret_cast<char*>(&settings.fileSize), sizeof(settings.fileSize));
			os.read(reinterpret_cast<char*>(&settings.reserved), sizeof(settings.reserved));
			os.read(reinterpret_cast<char*>(&settings.offset), sizeof(settings.offset));

			os.read(reinterpret_cast<char*>(&settings.headerSize), sizeof(settings.headerSize));
			os.read(reinterpret_cast<char*>(&settings.dimensions), sizeof(settings.dimensions));

			settings.imgHeight = settings.dimensions[1];
			settings.imgWidth = settings.dimensions[0];

			this->width = settings.imgWidth;
			this->height = settings.imgHeight;
			this->amount = 3;

			os.read(reinterpret_cast<char*>(&settings.colorPlanes), sizeof(settings.colorPlanes));
			os.read(reinterpret_cast<char*>(&settings.bpp), sizeof(settings.bpp));
			os.read(reinterpret_cast<char*>(&settings.compression), sizeof(settings.compression));
			os.read(reinterpret_cast<char*>(&settings.imgSize), sizeof(settings.imgSize));
			os.read(reinterpret_cast<char*>(settings.resolution), sizeof(settings.resolution));
			os.read(reinterpret_cast<char*>(&settings.pltColors), sizeof(settings.pltColors));
			os.read(reinterpret_cast<char*>(&settings.impColors), sizeof(settings.impColors));

			this->init();	
			unsigned char b = 0, g = 0, r = 0, a = 0;
			for (int i = 0; i < this->height; i++)
			{
				for (int j = 0; j < this->width; j++)
				{
					os >> b;
					os >> g;
					os >> r;
					
				//	cout << (int)b << " - " << (int)g << " - " << (int)r << endl;
					//system("pause");
					(*this)[i][j]->b = (int)b;
					(*this)[i][j]->g = (int)g;
					(*this)[i][j]->r = (int)r;

				}
			}
		}

		void write(string filename)
		{
			ofstream os(filename);

			os.write(reinterpret_cast<char*>(settings.signature), sizeof(settings.signature));
			os.write(reinterpret_cast<char*>(&settings.fileSize), sizeof(settings.fileSize));
			os.write(reinterpret_cast<char*>(&settings.reserved), sizeof(settings.reserved));
			os.write(reinterpret_cast<char*>(&settings.offset), sizeof(settings.offset));

			os.write(reinterpret_cast<char*>(&settings.headerSize), sizeof(settings.headerSize));
			os.write(reinterpret_cast<char*>(settings.dimensions), sizeof(settings.dimensions));
			os.write(reinterpret_cast<char*>(&settings.colorPlanes), sizeof(settings.colorPlanes));
			os.write(reinterpret_cast<char*>(&settings.bpp), sizeof(settings.bpp));
			os.write(reinterpret_cast<char*>(&settings.compression), sizeof(settings.compression));
			os.write(reinterpret_cast<char*>(&settings.imgSize), sizeof(settings.imgSize));
			os.write(reinterpret_cast<char*>(settings.resolution), sizeof(settings.resolution));
			os.write(reinterpret_cast<char*>(&settings.pltColors), sizeof(settings.pltColors));
			os.write(reinterpret_cast<char*>(&settings.impColors), sizeof(settings.impColors));

			for (int i = 0; i < this->height; i++)
			{
				for (int j = 0; j < this->width; j++)
				{
					os << (unsigned char)(*this)[i][j]->b;
					os << (unsigned char)(*this)[i][j]->g;
					os << (unsigned char)(*this)[i][j]->r;
				}
			}
		}

};