 /*File Name: PicturMatrix.cpp
  Author: Betti Österholz ; Date: 25.08.2003
  System: C++
  
*/

#include "PicturMatrix.h"


PicturMatrix::PicturMatrix():NumberOfColorComponents(0),NumberOfPositionComponents(0)
//standart constructor constructs a blank object
{

Depth=new unsigned int[1];;
Depth[0]=0;

Matrix=new Color****[0];
Matrix[0]=new Color***[0];
Matrix[0][0]=new Color**[0];
Matrix[0][0][0]=new Color*[0];
Matrix[0][0][0][0]=0;
Size=new unsigned long[4];
for (int a=0;a<4;a++)
	Size[a]=1;
Background=new Color(1);
Background->setValueToValue(1,0);
}

PicturMatrix::PicturMatrix(unsigned long* sz,unsigned int ncc,unsigned int* dep)
//parameter constructor
//constructs a matrix sz great with everywher 0 pointer(no entry)
//pre: the size sz the new matrix should have
//  the number of components of the color vectors and the depth of
//  each of this components
{
unsigned short npc=0;
for (unsigned short i=0;i<4;i++)
{
	if (sz[i]!=0) npc++;
}
NumberOfPositionComponents=npc;
NumberOfColorComponents=ncc;
Depth=new unsigned int[NumberOfColorComponents];
for (unsigned int i=0;i<ncc;i++)
	{Depth[i]=dep[i];}
Size=new unsigned long[4];
for (int a=0;a<4;a++)
	Size[a]=sz[a];
Matrix=new Color****[Size[0]];
unsigned long i[4];
for (i[0]=0;i[0]<Size[0];i[0]++)
{
	Matrix[i[0]]=new Color***[Size[1]];
	for (i[1]=0;i[1]<Size[1];i[1]++)
	{
		Matrix[i[0]][i[1]]=new Color**[Size[2]];
		for (i[2]=0;i[2]<Size[2];i[2]++)
		{
			Matrix[i[0]][i[1]][i[2]]=new Color*[Size[3]];
			for (i[3]=0;i[3]<Size[3];i[3]++)
			{
				Matrix[i[0]][i[1]][i[2]][i[3]]=0;
			}
		}
	}
}
Background=new Color(3);
Background->setValueToValue(1,0);
Background->setValueToValue(2,0);
Background->setValueToValue(3,0);
}

PicturMatrix::PicturMatrix(const PicturMatrix& matrx,bool copy=true)
//if copy is true constructs a object with the same values as the given
//else constructs a object with the same values but the Matrix values/Color pointers are all set to 0
{
NumberOfColorComponents=matrx.getNumberOfColorComponents();
Depth=new unsigned int[NumberOfColorComponents];
for (unsigned int a=0;a<NumberOfColorComponents;a++)
	{Depth[a]=matrx.getDepthOfComponent(a+1);}
Size=matrx.getSize();
unsigned long i[4];
Matrix=new Color****[Size[0]];
for (i[0]=0;i[0]<Size[0];i[0]++)
{
	Matrix[i[0]]=new Color***[Size[1]];
	for (i[1]=0;i[1]<Size[1];i[1]++)
	{
		Matrix[i[0]][i[1]]=new Color**[Size[2]];
		for (i[2]=0;i[2]<Size[2];i[2]++)
		{
			Matrix[i[0]][i[1]][i[2]]=new Color*[Size[3]];
			for (i[3]=0;i[3]<Size[3];i[3]++)
			{
				if (copy)
				{
					Color* tmp=matrx.getColorFrom(i);
					if (tmp) {Matrix[i[0]][i[1]][i[2]][i[3]]=tmp->copy();}
					else {Matrix[i[0]][i[1]][i[2]][i[3]]=0;}
				}else {Matrix[i[0]][i[1]][i[2]][i[3]]=0;}
			}
		}
	}
}
if (copy) 
	{Background=(matrx.getBackgroundColor())->copy();}
else{
	Background=new Color(3);
	Background->setValueToValue(1,0);
	Background->setValueToValue(2,0);
	Background->setValueToValue(3,0);
}
}

PicturMatrix::PicturMatrix(char* file)
//load constructor
//constructs a object with the values as the given fram a file
{
Size=new unsigned long[4];
for (int a=0;a<4;a++)
	Size[a]=1;
Matrix=new Color****[0];
Matrix[0]=new Color***[0];
Matrix[0][0]=new Color**[0];
Matrix[0][0][0]=new Color*[0];
Matrix[0][0][0][0]=0;
Background=new Color(1);
Background->setValueToValue(1,0);
Depth=new unsigned int[1];
load(file);
}

PicturMatrix::~PicturMatrix()
//destructor
{
long i[4];
for (i[0]=Size[0]-1;i[0]>=0;i[0]--)
{
	for (i[1]=Size[1]-1;i[1]>=0;i[1]--)
	{
		for (i[2]=Size[2]-1;i[2]>=0;i[2]--)
		{
			for (i[3]=Size[3]-1;i[3]>=0;i[3]--)
			{
				if (!Matrix[i[0]][i[1]][i[2]][i[3]]) {delete Matrix[i[0]][i[1]][i[2]][i[3]];}
			}
			delete Matrix[i[0]][i[1]][i[2]];
		}
	delete Matrix[i[0]][i[1]];
	}
delete Matrix[i[0]];
}
delete Matrix;
delete Size;
delete Depth;
delete Background;
}

unsigned long* PicturMatrix::getSize() const
//returns the size of the Matrix
//post: the unsigned int[4] array of the size
{
unsigned long *sz=new unsigned long[4];
for (int a=0;a<4;a++)
	sz[a]=Size[a];
return sz;
}

bool PicturMatrix::setColorOnPosition(unsigned long* pos,Color col)
//insert on the position ps in the Matrix a copy of the given color
//object col, the eventuell old Color object on this position is deleted
//if no ReferenceColor is defined it set also the ReferenceColor to
//the same type as the given Color object col
//pre: the Color col to insert an the position pos to insert
{
if ((pos[0]<Size[0])&&(pos[1]<Size[1])&&(pos[2]<Size[2])&&(pos[3]<Size[3])){
	if (!Matrix[pos[0]][pos[1]][pos[2]][pos[3]])
	{//ther is a Color object on the position in the Matrix
		delete Matrix[pos[0]][pos[1]][pos[2]][pos[3]];
		Matrix[pos[0]][pos[1]][pos[2]][pos[3]]=col.copyValue();
	}else{//ther is no Color object on the position in the Matrix yet
		Matrix[pos[0]][pos[1]][pos[2]][pos[3]]=col.copyValue();
	}
	return true;
}
return false;
}

void PicturMatrix::overlap(PicturMatrix matrix)
//if in the given matrix is on a position a Color Object a copy
//of this is insert on the same Position in the Matrix of this Object
//if on this position is a 0 pointer and the position exsists(lower
//Size)
//pre: the PicturMatrix matrix to insert with this Pictur matrix oferlapping
{
unsigned long i[4];
for (i[0]=0;i[0]<Size[0];i[0]++)
	for (i[1]=0;i[1]<Size[1];i[1]++)
		for (i[2]=0;i[2]<Size[2];i[2]++)
			for (i[3]=0;i[3]<Size[3];i[3]++)
			{
				if (Matrix[i[0]][i[1]][i[2]][i[3]]==0)
				{
					Color* tmp=matrix.getColorFrom(i);
					if (tmp) Matrix[i[0]][i[1]][i[2]][i[3]]=tmp->copy();
				}
			}
}

bool PicturMatrix::load(char* file)
//load a pictur Matrix from the file with name file
//pre: the name of the file to load the PicturMatrix from
{
//read the ending of the file name
unsigned int end_part=0;
unsigned int i=0;
while (file[i]!=false)
{
	cout<<file[i];
	if (file[i]=='.') {end_part=i+1;}
	i++;
}
char fileend[i-end_part];
for (unsigned int a=end_part;a<i;a++)
{
	fileend[a-end_part]=file[a];
}
if (fileend[1]=='m')
	{return loadBitmap(file);}//fileend = bmp
if (fileend[1]=='t')
	{return load_btx(file);}//fileend = btx
return false;
}

bool PicturMatrix::store(char* file)
//store this pictur Matrix to the file with name file
//pre: the name of the file to load the PicturMatrix from
{
return saveBitmap(file);
}

unsigned long PicturMatrix::distanceTo(PicturMatrix matrix) const
//evaluate the distance from the given PicturMatrix matrix
//pre: the PicturMatrix to evaluate the distance from this PicturMatrix
//post: a unsigned long number for the distance
{
unsigned long dist=0;
unsigned int mdist=0;//the maximal distance
long dtmp;//temporal distant of tow color components
double* tmp1;
double* tmp2;//temporal Color Component pointer
for (unsigned int b=1;b<=getNumberOfColorComponents();b++)
	{mdist=mdist+getDepthOfComponent(b);}
unsigned long i[4];
for (i[0]=0;i[0]<Size[0];i[0]++)
	for (i[1]=0;i[1]<Size[1];i[1]++)
		for (i[2]=0;i[2]<Size[2];i[2]++)
			for (i[3]=0;i[3]<Size[3];i[3]++)
			{
				if (Matrix[i[0]][i[1]][i[2]][i[3]]!=0)
				{
					Color* tmp=matrix.getColorFrom(i);
					if (tmp) {
						for (unsigned int a=1;a<=getNumberOfColorComponents();a++)
						{
							tmp1=Matrix[i[0]][i[1]][i[2]][i[3]]->getComponentPointer(a);
							tmp2=tmp->getComponentPointer(a);
							dtmp=(long)((*tmp1)-(*tmp2));
							if (dtmp<0) dtmp=-dtmp;
							if ((unsigned long)dtmp>Depth[a])
								{dist=dist+Depth[a];}
							else{
								dist=dist+dtmp;;
							}
						}
					}
					else {dist=dist+mdist;}
				}else{
					dist=dist+mdist;
				}
			}
return dist;
}

unsigned long PicturMatrix::distanceOfArea(PicturMatrix matrix, unsigned long* from, unsigned long* to) const
//evaluate the distance from the given PicturMatrix matrix in the area
//from to to(inclusiv to)
//pre: the PicturMatrix to evaluate the distance from this PicturMatrix,
//  the lower bound from and upper bound to of the area
//post: a unsigned long number for the distance
{
unsigned long dist=0;
unsigned long tcdist=0;//temporal color distance
unsigned int mdist=0;//the maximal distance
long dtmp;//temporal distant of tow color components
double* tmp1;
double* tmp2;//temporal Color Component pointer
for (unsigned int b=1;b<=getNumberOfColorComponents();b++)
	{mdist=mdist+getDepthOfComponent(b);}
unsigned long i[4];
for (i[0]=from[0];i[0]<=to[0];i[0]++)
	for (i[1]=from[1];i[1]<=to[1];i[1]++)
		for (i[2]=from[2];i[2]<=to[2];i[2]++)
			for (i[3]=from[3];i[3]<=to[3];i[3]++)
			{
				if (Matrix[i[0]][i[1]][i[2]][i[3]]==0)
				{
					Color* tmp=matrix.getColorFrom(i);
					if (tmp) {
						for (unsigned int a=1;a<=getNumberOfColorComponents();a++)
						{
							tmp1=Matrix[i[0]][i[1]][i[2]][i[3]]->getComponentPointer(a);
							tmp2=tmp->getComponentPointer(a);
							dtmp=(long)((*tmp1)-(*tmp2));
							if (dtmp<0) dtmp=-dtmp;
							if ((unsigned long)dtmp>Depth[a])
								{dist=Depth[a];}
							else{
								dist=dist+dtmp;
							}
						}
						dist=dist+tcdist;
						tcdist=0;
					}else{dist=dist+mdist;}
				}else{
					dist=dist+mdist;
				}
			}
return dist;
}

void PicturMatrix::resize(unsigned long* nsize)
//resize the Matrix to the new size nsize
//pre: the new size of of the object nsize
{
long i[4];
Color *****tmatrix=new Color****[nsize[0]];//matrix to save values
for (i[0]=0;i[0]<(long)nsize[0];i[0]++)
{
	tmatrix[i[0]]=new Color***[nsize[1]];
	for (i[1]=0;i[1]<(long)nsize[1];i[1]++)
	{
		tmatrix[i[0]][i[1]]=new Color**[nsize[2]];
		for (i[2]=0;i[2]<(long)nsize[2];i[2]++)
		{
			tmatrix[i[0]][i[1]][i[2]]=new Color*[nsize[3]];
			for (i[3]=0;i[3]<(long)nsize[3];i[3]++)
			{
				if((i[0]<(long)Size[0])&&(i[1]<(long)Size[1])&&(i[2]<(long)Size[2])&&(i[3]<(long)Size[3]))
					{tmatrix[i[0]][i[1]][i[2]][i[3]]=Matrix[i[0]][i[1]][i[2]][i[3]];}
			}
		}
	}
}
//delete old Matrix
for (i[0]=Size[0]-1;i[0]>=0;i[0]--)
{
	for (i[1]=Size[1]-1;i[1]>=0;i[1]--)
	{
		for (i[2]=Size[2]-1;i[2]>=0;i[2]--)
		{
			for (i[3]=Size[3]-1;i[3]>=0;i[3]--)
			{
				//delet all color who don't needed anymore
				if ((!Matrix[i[0]][i[1]][i[2]][i[3]])&&(i[0]>=(long)nsize[0])&&(i[1]>=(long)nsize[1])&&(i[2]>=(long)nsize[2])&&(i[3]>=(long)nsize[3]))
					{delete Matrix[i[0]][i[1]][i[2]][i[3]];}
			}
			delete Matrix[i[0]][i[1]][i[2]];
		}
	delete Matrix[i[0]][i[1]];
	}
delete Matrix[i[0]];
}
delete Matrix;
//copy values back to orginal matrix
Matrix=new Color****[nsize[0]];
for (i[0]=0;i[0]<(long)nsize[0];i[0]++)
{
	Matrix[i[0]]=new Color***[nsize[1]];
	for (i[1]=0;i[1]<(long)nsize[1];i[1]++)
	{
		Matrix[i[0]][i[1]]=new Color**[nsize[2]];
		for (i[2]=0;i[2]<(long)nsize[2];i[2]++)
		{
			Matrix[i[0]][i[1]][i[2]]=new Color*[nsize[3]];
			for (i[3]=0;i[3]<(long)nsize[3];i[3]++)
			{
				if((i[0]<(long)Size[0])&&(i[1]<(long)Size[1])&&(i[2]<(long)Size[2])&&(i[3]<(long)Size[3]))
					{Matrix[i[0]][i[1]][i[2]][i[3]]=tmatrix[i[0]][i[1]][i[2]][i[3]];}
				else{Matrix[i[0]][i[1]][i[2]][i[3]]=0;}
			}
		}
	}
}

//delete tmatrix(why eror?)
/*for (i[0]=nsize[0]-1;i[0]>=0;i[0]--)
{
	for (i[1]=nsize[0]-1;i[1]>=0;i[1]--)
	{
		for (i[2]=nsize[0]-1;i[2]>=0;i[2]--)
		{
			//don't delet the color objects
			cout<<" delte matrix "<<endl<<flush;
			delete tmatrix[i[0]][i[1]][i[2]];
		}
	delete tmatrix[i[0]][i[1]];
	}
delete tmatrix[i[0]];
}
delete tmatrix;
*/

for (int a=0;a<4;a++)
	Size[a]=nsize[a];
}


void PicturMatrix::clear()
//clears the matrix; deletes all Color Objects in it
//post: a blank Matrix
{
long i[4];
for (i[0]=Size[0]-1;i[0]>=0;i[0]--)
{
	for (i[1]=Size[1]-1;i[1]>=0;i[1]--)
	{
		for (i[2]=Size[2]-1;i[2]>=0;i[2]--)
		{
			for (i[3]=Size[3]-1;i[3]>=0;i[3]--)
			{
				//delet all color who don't needed anymore
				if (Matrix[i[0]][i[1]][i[2]][i[3]])
					{
						delete Matrix[i[0]][i[1]][i[2]][i[3]];
						Matrix[i[0]][i[1]][i[2]][i[3]]=0;
					}
			}
		}
	}
}
}

bool PicturMatrix::loadBitmap(char* file)
//load a pictur Matrix from the bitmap pictur file with name file
//pre: the name of the bitmap pictur file to load the PicturMatrix from
{
ifstream *stream=new ifstream(file);

NumberOfPositionComponents=2;
unsigned char c1,c2;
(*stream)>>c1>>c2;//identifier
readint(stream,4);//filesize
readint(stream,4);//reserved
readint(stream,4);//Offset from filebegin till data
readint(stream,4);//bitmap header size
unsigned long *nsize=new unsigned long[4];
nsize[0]=readint(stream,4);//horizontale width of bitmap pixels
nsize[1]=readint(stream,4);//vertical width of bitmap pixels
nsize[2]=1;
nsize[3]=1;
resize(nsize);//make big enougth matrix
readint(stream,2);//number of planes in this bitmap should be 1
unsigned int bpp=readint(stream,2);//bits per pixel
readint(stream,4);//compression specification, should be 0=none
readint(stream,4);//size of bitmap data
readint(stream,4);//horizontal pixel per meter, uninportant
readint(stream,4);//vertical pixel per meter, uninportant
unsigned int col=readint(stream,4);//number of colors
delete Depth;
switch (bpp)
{
case 1:Depth=new unsigned int[1];
	Depth[0]=2;
	NumberOfColorComponents=1;
	break;
case 4:Depth=new unsigned int[1];
	Depth[0]=16;
	NumberOfColorComponents=1;
	break;
case 8:Depth=new unsigned int[1];
	Depth[0]=256;
	NumberOfColorComponents=1;
	break;
case 16:Depth=new unsigned int[2];
	Depth[0]=256;
	Depth[1]=256;
	NumberOfColorComponents=2;
	break;
case 24:Depth=new unsigned int[3];
	Depth[0]=256;
	Depth[1]=256;
	Depth[2]=256;
	NumberOfColorComponents=3;
	break ;
case 32:Depth=new unsigned int[3];
	Depth[0]=256;
	Depth[1]=256;
	Depth[2]=65536;
	NumberOfColorComponents=3;
	break;
}
readint(stream,4);//number of important colors, should be equal number of colors
//color table
if ((col==0)&&(bpp==4)){col=16;}
if (!(((bpp==2)&&(col==0))||(bpp==24)))
	for (unsigned int i=0;i<col;i++ )
	{
		cout<<"color "<<i<<"  0;R;G;B "<<readint(stream,1)<<";"<<readint(stream,1)<<";"<<readint(stream,1)<<";"<<readint(stream,1)<<endl;
	}
//read pixels
long pos[4]={0,0,0,0};
if (bpp==24)
{
	Color col=Color(3);
	for (pos[0]=(long)(Size[0]-1);pos[0]>=0;pos[0]-- )
	{
		for (pos[1]=0;pos[1]<(long)Size[1];pos[1]++ )
		{
			col.setValueToValue(1,(int)readint(stream,1));
			col.setValueToValue(2,(int)readint(stream,1));
			col.setValueToValue(3,(int)readint(stream,1));
			setColorOnPosition((unsigned long*)pos,col);
		}
	}
	delete Background;
	Background=new Color(3);
	Background->setValueToValue(1,0);
	Background->setValueToValue(2,0);
	Background->setValueToValue(3,0);
}
/*
if (bpp==4)//black and whit pictur
{
	for (int xi=x-1;xi>=0;xi-- )
	{
		for (int yi=0;yi<y;yi++ )
		{
			int bw=readint(stream,1);
			cout<<bw%16<<"  ";
			if ((xi==x)&&(yi==0))
				{break;}
			else{
				if (yi==y-1)
				{
					yi=y+1;
					xi--;
					cout<<endl;
				}else{yi++;}
			}
			cout<<bw/16<<"  ";
		}
		cout<<endl;
	}
}
*/

delete stream;
return true;
}





bool PicturMatrix::saveBitmap(char* file) const
//store this pictur Matrix to the bitmap pictur file with name file
//pre: the name of the bitmap pictur file to store this PicturMatrix to
{
unsigned int bpp;

if ((Depth[0]==256)&&(Depth[1]==256)&&(Depth[2]==256))
	{bpp=24;}//bits per pixel; 24 for no color table
ofstream *stream=new ofstream(file);
(*stream)<<'B'<<'M';//identifier
writeint(stream,4, 54+(Size[0]*Size[1])*(bpp/8));//filesize
writeint(stream,4,0);//reserved
writeint(stream,4,54);//Offset from filebegin till data; 54 when no color table
writeint(stream,4,40);//bitmap header size
writeint(stream,4,Size[0]);//horizontale width of bitmap pixels
writeint(stream,4,Size[1]);//vertical width of bitmap pixels
writeint(stream,2,1);//number of planes in this bitmap should be 1
writeint(stream,2,bpp);//bits per pixel; 24 for no color table
writeint(stream,4,0);//compression specification, should be 0=none
writeint(stream,4,((unsigned int)(((Size[0]*Size[1])*(bpp/8)+2)/4)*4));//size of bitmap data
writeint(stream,4,0);//horizontal pixel per meter, uninportant
writeint(stream,4,0);//vertical pixel per meter, uninportant

writeint(stream,4,0);//number of colors
writeint(stream,4,0);//number of important colors, should be equal number of colors

long pos[4]={0,0,0,0};
if (bpp==24)
{
	Color *col=new Color(3);
	int tmp;
	for (pos[0]=(long)(Size[0]-1);pos[0]>=0;pos[0]-- )
	{
		for (pos[1]=0;pos[1]<(long)Size[1];pos[1]++ )
		{
			col=getColorFrom((unsigned long*)pos);
			for (unsigned short i=1;i<=3;i++)
			{
				tmp=col->getValue(i);
				if (tmp<0) {tmp=0;}//normalise
				if (tmp>255) {tmp=255;}
				writeint(stream,1,tmp);
			}
		}
	}
}
delete stream;
return true;
}


unsigned int PicturMatrix::readint(ifstream *stream,unsigned short byte) const
//reads a value with byte bytes from the stream and returns his integer value
//pre: the ifstream stream to read from and the number of bytes byte to read
//post: the readed value
{
unsigned char tc=0;
unsigned int read=0;
unsigned int exp=1;
for (unsigned short i=0;i<byte;i++)
{
	(*stream)>>tc;
	read=(unsigned short)tc*exp+read;
	exp=exp*256;
}
return read;
}

void PicturMatrix::writeint(ofstream *stream,unsigned short byte,int write) const
//writes the value of write with byte bytes to the stream stream
//pre: the value write to write, how much byte byte write should use and the stream to write to
//post: the value of write with byte bytes in the stream stream
{
for (unsigned short i=0;i<byte;i++)
{
	(*stream)<<(unsigned char)(write%256);
	write=write/256;
}
}

bool PicturMatrix::load_btx(char* file)
//load a saved btx(own format)
//post: the data of the btx file in this Matrix
{
NumberOfPositionComponents=2;
ifstream *stream=new ifstream(file);
char c='a';
unsigned int tmp=0;
(*stream)>>c;
while (c!=';')//read greatness x
{
	tmp=tmp*10+charToInt(c);
	(*stream)>>c;
}
unsigned long *nsize=new unsigned long[4];
nsize[0]=tmp;//horizontale width of bitmap pixels
tmp=0;
(*stream)>>c;
while ((c!=';')&&(c!='\n'))//read greatness y
{
	tmp=tmp*10+charToInt(c);
	(*stream)>>c;
}
nsize[1]=tmp;//vertical width of bitmap pixels
nsize[2]=1;
nsize[3]=1;
resize(nsize);//make big enougth matrix
delete Depth;
Depth=new unsigned int[1];
Depth[0]=2;
NumberOfColorComponents=1;

unsigned long *pos=new unsigned long[4];
pos[2]=0;pos[3]=0;

Color col=Color(1);
for (pos[0]=0;pos[0]<nsize[0];pos[0]++)
{
	for (pos[1]=0;pos[1]<nsize[1];pos[1]++)
	{
		c='a';
		while ((c!='0')&&(c!='1')) {(*stream)>>c;}//read until a 1 or 0 readed

		if (c=='0'){col.setValueToValue(1,0);}
		if (c=='1'){col.setValueToValue(1,1);}
		setColorOnPosition((unsigned long*)pos,col);
	}
}
delete stream;
return true;
}


int PicturMatrix::charToInt(char c)
//makes the char c to a integer number
//pre: the char c
//post: the integer number the char c represents(e.g. "1"=1)
{
switch (c)
{
	case '0':return 0;
	case '1':return 1;
	case '2':return 2;
	case '3':return 3;
	case '4':return 4;
	case '5':return 5;
	case '6':return 6;
	case '7':return 7;
	case '8':return 8;
	case '9':return 9;
}
return -1;//error
}

