#include "../stdafx.h"
#include "CDefHandler.h"
#include <sstream>

long long pow(long long a, int b)
{
	if (!b) return 1;
	long c = a;
	while (--b)
		a*=c;
	return a;
}
void BMPHeader::print(std::ostream & out)
{
	CDefHandler::print(out,fullSize,4);
	CDefHandler::print(out,_h1,4);
	CDefHandler::print(out,_c1,4);
	CDefHandler::print(out,_c2,4);
	CDefHandler::print(out,x,4);
	CDefHandler::print(out,y,4);
	CDefHandler::print(out,_c3,2);
	CDefHandler::print(out,_c4,2);
	CDefHandler::print(out,_h2,4);
	CDefHandler::print(out,_h3,4);
	CDefHandler::print(out,dataSize1,4);
	CDefHandler::print(out,dataSize2,4);
	for (int i=0;i<8;i++)
		out << _c5[i];
	out.flush();
}
CDefHandler::CDefHandler()
{
	//FDef = NULL;
	RWEntries = NULL;
	RLEntries = NULL;
	notFreeImgs = false;
}
CDefHandler::~CDefHandler()
{
	//if (FDef)
		//delete [] FDef;
	if (RWEntries)
		delete [] RWEntries;
	if (RLEntries)
		delete [] RLEntries;
	if (notFreeImgs)
		return;
	for (int i=0; i<ourImages.size(); i++)
	{
		if (ourImages[i].bitmap)
		{
			SDL_FreeSurface(ourImages[i].bitmap);
			ourImages[i].bitmap=NULL;
		}
	}
}
CDefEssential::~CDefEssential()
{
	for(int i=0;i<ourImages.size();i++)
		SDL_FreeSurface(ourImages[i].bitmap);
}
void CDefHandler::openDef(std::string name)
{
	int i,j, totalInBlock;
	char Buffer[13];
	defName=name;

	int andame;
	std::ifstream * is = new std::ifstream();
	is -> open(name.c_str(),std::ios::binary);
	is->seekg(0,std::ios::end); // na koniec
	andame = is->tellg();  // read length
	is->seekg(0,std::ios::beg); // wracamy na poczatek
	unsigned char * FDef = new unsigned char[andame]; // allocate memory 
	is->read((char*)FDef, andame); // read map file to buffer
	is->close();
	delete is;
	i = 0;
	DEFType = readNormalNr(i,4,FDef); i+=4;
	fullWidth = readNormalNr(i,4,FDef); i+=4;
	fullHeight = readNormalNr(i,4,FDef); i+=4;
	i=0xc;
	totalBlocks = readNormalNr(i,4,FDef); i+=4;

	i=0x10;
	for (int it=0;it<256;it++)
	{
		palette[it].R = FDef[i++];
		palette[it].G = FDef[i++];
		palette[it].B = FDef[i++];
		palette[it].F = 0;
	}
	i=0x310;
	totalEntries=0;
	for (int z=0; z<totalBlocks; z++)
	{
		i+=4;
		totalInBlock = readNormalNr(i,4,FDef); i+=4;
		for (j=SEntries.size(); j<totalEntries+totalInBlock; j++)
			SEntries.push_back(SEntry());
		i+=8;
		for (j=0; j<totalInBlock; j++)
		{
			for (int k=0;k<13;k++) Buffer[k]=FDef[i+k]; 
			i+=13;
			SEntries[totalEntries+j].name=Buffer;
		}
		for (j=0; j<totalInBlock; j++)
		{ 
			SEntries[totalEntries+j].offset = readNormalNr(i,4,FDef);
			i+=4;
		}
		//totalEntries+=totalInBlock;
		for(int hh=0; hh<totalInBlock; ++hh)
		{
			SEntries[totalEntries].group = z;
			++totalEntries;
		}
	}
	for(j=0; j<SEntries.size(); ++j)
	{
		SEntries[j].name = SEntries[j].name.substr(0, SEntries[j].name.find('.')+4);
	}
	for(int i=0; i<SEntries.size(); ++i)
	{
		Cimage nimg;
		nimg.bitmap = getSprite(i, FDef);
		nimg.imName = SEntries[i].name;
		nimg.groupNumber = SEntries[i].group;
		ourImages.push_back(nimg);
	}
	delete [] FDef;
	FDef = NULL;
}

void CDefHandler::openFromMemory(unsigned char *table, int size, std::string name)
{
	int i,j, totalInBlock;
	char Buffer[13];
	defName=name;
	int andame = size;
	i = 0;
	DEFType = readNormalNr(i,4,table); i+=4;
	fullWidth = readNormalNr(i,4,table); i+=4;
	fullHeight = readNormalNr(i,4,table); i+=4;
	i=0xc;
	totalBlocks = readNormalNr(i,4,table); i+=4;

	i=0x10;
	for (int it=0;it<256;it++)
	{
		palette[it].R = table[i++];
		palette[it].G = table[i++];
		palette[it].B = table[i++];
		palette[it].F = 0;
	}
	i=0x310;
	totalEntries=0;
	for (int z=0; z<totalBlocks; z++)
	{
		int unknown1 = readNormalNr(i,4,table); i+=4;
		totalInBlock = readNormalNr(i,4,table); i+=4;
		for (j=SEntries.size(); j<totalEntries+totalInBlock; j++)
			SEntries.push_back(SEntry());
		int unknown2 = readNormalNr(i,4,table); i+=4;
		int unknown3 = readNormalNr(i,4,table); i+=4;
		for (j=0; j<totalInBlock; j++)
		{
			for (int k=0;k<13;k++) Buffer[k]=table[i+k]; 
			i+=13;
			SEntries[totalEntries+j].name=Buffer;
		}
		for (j=0; j<totalInBlock; j++)
		{ 
			SEntries[totalEntries+j].offset = readNormalNr(i,4,table);
			int unknown4 = readNormalNr(i,4,table); i+=4;
		}
		//totalEntries+=totalInBlock;
		for(int hh=0; hh<totalInBlock; ++hh)
		{
			SEntries[totalEntries].group = z;
			++totalEntries;
		}
	}
	for(j=0; j<SEntries.size(); ++j)
	{
		SEntries[j].name = SEntries[j].name.substr(0, SEntries[j].name.find('.')+4);
	}
	for(int i=0; i<SEntries.size(); ++i)
	{
		Cimage nimg;
		nimg.bitmap = getSprite(i, table);
		nimg.imName = SEntries[i].name;
		nimg.groupNumber = SEntries[i].group;
		ourImages.push_back(nimg);
	}
}

unsigned char * CDefHandler::writeNormalNr (int nr, int bytCon)
{
	//int tralalalatoniedziala = 2*9+100-4*bytCon;
	//unsigned char * ret = new unsigned char[bytCon];
	unsigned char * ret = NULL;
	for(int jj=0; jj<100; ++jj)
	{
		ret = (unsigned char*)calloc(1, bytCon);
		if(ret!=NULL)
			break;
	}
	long long amp = pow((float)256,bytCon-1);
	for (int i=bytCon-1; i>=0;i--)
	{
		int test2 = nr/(amp);
		ret[i]=test2;
		nr -= (nr/(amp))*amp;
		amp/=256;
	}
	return ret;
}
void CDefHandler::expand(unsigned char N,unsigned char & BL, unsigned char & BR)
{
	BL = (N & 0xE0) >> 5;
	BR = N & 0x1F;
}
int CDefHandler::readNormalNr (int pos, int bytCon, unsigned char * str, bool cyclic)
{
	int ret=0;
	int amp=1;
	if (str)
	{
		for (int i=0; i<bytCon; i++)
		{
			ret+=str[pos+i]*amp;
			amp*=256;
		}
	}
	//else 
	//{
	//	for (int i=0; i<bytCon; i++)
	//	{
	//		ret+=FDef[pos+i]*amp;
	//		amp*=256;
	//	}
	//}
	if(cyclic && bytCon<4 && ret>=amp/2)
	{
		ret = ret-amp;
	}
	return ret;
}
void CDefHandler::print (std::ostream & stream, int nr, int bytcon)
{
	unsigned char * temp = writeNormalNr(nr,bytcon);
	for (int i=0;i<bytcon;i++)
		stream << char(temp[i]);
	free(temp);
}

SDL_Surface * CDefHandler::getSprite (int SIndex, unsigned char * FDef)
{
	SDL_Surface * ret=NULL;

	long BaseOffset, 
		SpriteWidth, SpriteHeight, //format sprite'a
		LeftMargin, RightMargin, TopMargin,BottomMargin,
		i, add, FullHeight,FullWidth,
		TotalRowLength, // dlugosc przeczytanego segmentu
		NextSpriteOffset, RowAdd;

	unsigned char SegmentType, SegmentLength, BL, BR;

	i=BaseOffset=SEntries[SIndex].offset;
	int prSize=readNormalNr(i,4,FDef);i+=4;
	int defType2 = readNormalNr(i,4,FDef);i+=4;
	FullWidth = readNormalNr(i,4,FDef);i+=4;
	FullHeight = readNormalNr(i,4,FDef);i+=4;
	SpriteWidth = readNormalNr(i,4,FDef);i+=4;
	SpriteHeight = readNormalNr(i,4,FDef);i+=4;
	LeftMargin = readNormalNr(i,4,FDef);i+=4;
	TopMargin = readNormalNr(i,4,FDef);i+=4;
	RightMargin = FullWidth - SpriteWidth - LeftMargin;
	BottomMargin = FullHeight - SpriteHeight - TopMargin;

	//if(LeftMargin + RightMargin < 0)
	//	SpriteWidth += LeftMargin + RightMargin; //ugly construction... TODO: check how to do it nicer
	if(LeftMargin<0)
		SpriteWidth+=LeftMargin;
	if(RightMargin<0)
		SpriteWidth+=RightMargin;
	
	add = 4 - FullWidth%4;
	if (add==4)
		add=0;

	int ftcp=0;
		
	ret = SDL_CreateRGBSurface(SDL_SWSURFACE, FullWidth, FullHeight, 8, 0, 0, 0, 0);
	//int tempee2 = readNormalNr(0,4,((unsigned char *)tempee.c_str()));

	int BaseOffsetor = BaseOffset = i;

	for(int i=0; i<256; ++i)
	{
		SDL_Color pr;
		pr.r = palette[i].R;
		pr.g = palette[i].G;
		pr.b = palette[i].B;
		pr.unused = palette[i].F;
		(*(ret->format->palette->colors+i))=pr;
	}

	if (defType2==0)
	{
		if (TopMargin>0)
		{
			for (int i=0;i<TopMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		for (int i=0;i<SpriteHeight;i++)
		{
			if (LeftMargin>0)
			{
				for (int j=0;j<LeftMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			for (int j=0; j<SpriteWidth;j++)
				((char*)(ret->pixels))[ftcp++]=FDef[BaseOffset++];
			if (RightMargin>0)
			{
				for (int j=0;j<add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		if (BottomMargin>0)
		{
			for (int i=0;i<BottomMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}

	}
	if (defType2==1)
	{
		if (TopMargin>0)
		{
			for (int i=0;i<TopMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		RLEntries = new int[SpriteHeight];
		for (int i=0;i<SpriteHeight;i++)
		{
			RLEntries[i]=readNormalNr(BaseOffset,4,FDef);BaseOffset+=4;
		}
		for (int i=0;i<SpriteHeight;i++)
		{
			BaseOffset=BaseOffsetor+RLEntries[i];
			if (LeftMargin>0)
			{
				for (int j=0;j<LeftMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			TotalRowLength=0;
			do
			{
				SegmentType=FDef[BaseOffset++];
				SegmentLength=FDef[BaseOffset++];
				if (SegmentType==0xFF)
				{
					for (int k=0;k<=SegmentLength;k++)
					{
						((char*)(ret->pixels))[ftcp++]=FDef[BaseOffset+k];
						if ((TotalRowLength+k+1)>=SpriteWidth)
							break;
					}
					BaseOffset+=SegmentLength+1;////
					TotalRowLength+=SegmentLength+1;
				}
				else
				{
					for (int k=0;k<SegmentLength+1;k++)
					{
						((char*)(ret->pixels))[ftcp++]=SegmentType;//
						//((char*)(ret->pixels))+='\0';
					}
					TotalRowLength+=SegmentLength+1;
				}
			}while(TotalRowLength<SpriteWidth);
			RowAdd=SpriteWidth-TotalRowLength;
			if (RightMargin>0)
			{
				for (int j=0;j<RightMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			if (add>0)
			{
				for (int j=0;j<add+RowAdd;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		delete [] RLEntries;
		RLEntries = NULL;
		if (BottomMargin>0)
		{
			for (int i=0;i<BottomMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
	}
	if (defType2==2)
	{
		if (TopMargin>0)
		{
			for (int i=0;i<TopMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		RWEntries = new unsigned int[SpriteHeight];
		for (int i=0;i<SpriteHeight;i++)
		{
			BaseOffset=BaseOffsetor+i*2*(SpriteWidth/32);
			RWEntries[i] = readNormalNr(BaseOffset,2,FDef);
		}
		BaseOffset = BaseOffsetor+RWEntries[0];
		for (int i=0;i<SpriteHeight;i++)
		{
			//BaseOffset = BaseOffsetor+RWEntries[i];
			if (LeftMargin>0)
			{
				for (int j=0;j<LeftMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			TotalRowLength=0;
			do
			{
				SegmentType=FDef[BaseOffset++];
				unsigned char code = SegmentType / 32;
				unsigned char value = (SegmentType & 31) + 1;
				if(code==7)
				{
					for(int h=0; h<value; ++h)
					{
						((char*)(ret->pixels))[ftcp++]=FDef[BaseOffset++];
					}
				}
				else
				{
					for(int h=0; h<value; ++h)
					{
						((char*)(ret->pixels))[ftcp++]=code;
					}
				}
				TotalRowLength+=value;
			} while(TotalRowLength<SpriteWidth);
			if (RightMargin>0)
			{
				for (int j=0;j<RightMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			if (add>0)
			{
				for (int j=0;j<add+RowAdd;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		delete [] RWEntries;
		RWEntries = NULL;
		if (BottomMargin>0)
		{
			for (int i=0;i<BottomMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
	}
	if (defType2==3)
	{
		if (add==4)
			add=0;
		if (TopMargin>0)
		{
			for (int i=0;i<TopMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		RWEntries = new unsigned int[SpriteHeight];
		for (int i=0;i<SpriteHeight;i++)
		{
			BaseOffset=BaseOffsetor+i*2*(SpriteWidth/32);
			RWEntries[i] = readNormalNr(BaseOffset,2,FDef);
		}
		for (int i=0;i<SpriteHeight;i++)
		{
			BaseOffset = BaseOffsetor+RWEntries[i];
			if (LeftMargin>0)
			{
				for (int j=0;j<LeftMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			TotalRowLength=0;
			do
			{
				SegmentType=FDef[BaseOffset++];
				unsigned char code = SegmentType / 32;
				unsigned char value = (SegmentType & 31) + 1;
				if(code==7)
				{
					for(int h=0; h<value; ++h)
					{
						if(h<-LeftMargin)
							continue;
						if(h+TotalRowLength>=SpriteWidth)
							break;
						((char*)(ret->pixels))[ftcp++]=FDef[BaseOffset++];
					}
				}
				else
				{
					for(int h=0; h<value; ++h)
					{
						if(h<-LeftMargin)
							continue;
						if(h+TotalRowLength>=SpriteWidth)
							break;
						((char*)(ret->pixels))[ftcp++]=code;
					}
				}
				TotalRowLength+=( LeftMargin>=0 ? value : value+LeftMargin );
			}while(TotalRowLength<SpriteWidth);
			if (RightMargin>0)
			{
				for (int j=0;j<RightMargin;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
			if (add>0)
			{
				for (int j=0;j<add+RowAdd;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
		delete [] RWEntries;
		RWEntries=NULL;
		if (BottomMargin>0)
		{
			for (int i=0;i<BottomMargin;i++)
			{
				for (int j=0;j<FullWidth+add;j++)
					((char*)(ret->pixels))[ftcp++]='\0';
			}
		}
	}
	SDL_Color ttcol = ret->format->palette->colors[0];
	Uint32 keycol = SDL_MapRGBA(ret->format, ttcol.r, ttcol.b, ttcol.g, ttcol.unused);
	SDL_SetColorKey(ret, SDL_SRCCOLORKEY, keycol);
	return ret;
};

CDefEssential * CDefHandler::essentialize()
{
	CDefEssential * ret = new CDefEssential;
	ret->ourImages = ourImages;
	notFreeImgs = true;
	return ret;
}