//	This source and compression method apply to GNU General Public License. 
//			Copyright (C) 2001-2013 Jasenko Dzinleski 

//		This program is free software; you can redistribute it
//	and/or modify it under the terms of the GNU General Public License as
//	published by the Free Software Foundation; either version 2 of the
//	License, or (at your option) any later version. 

//	This program is distributed in the hope that it will be useful, but
//	WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//	General Public License for more details. 

//	You should have received a copy of the GNU General Public License along
//	with this program; if not, write to the Free Software Foundation, Inc.,
//	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

//  	mCompression 
//	written by Dzinleski Jasenko  December 2013

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <iostream>

#define		BuffL				128
#define		BtM				8*256
#define		TBEnd				24

int		Abc=100;
int		Rbc=16;
int		Rbl=32;

FILE		*f1,*f2;

char		infn[256]="War_and_Peace_NT.txt";

char		cfn[256]="c.mar";

int		d1__,d2__,d3__;
int		sa[1024];		int	sai=0;
int		pa[256][256][256][3];	int 	pai=0;

using std::vector; vector<vector<vector<int> > > da;	int	dai=0;

int		bi;
int		bt32_1[32];		int	bt32i_1=0;
int		br[BtM];		int	bri=0;
int		bt[BtM];		int	bti=0;

int		bc_=0,bc=0,bitc=0;
int		bytc=0,bytc1=0;

int	p_r(FILE *fw1,int brw[BtM],int brwi)
{
	int	i,ii=0,j,k,l;

	l=7;j=0;
	for(i=0;i<brwi;)
	{

		if(i<brwi){if(brw[i]  ){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}
		if(1+i<brwi){if(brw[++i]){j|=1<<l;}--l;}else{break;}

		if(l==-1){fprintf(fw1,"%c",(j&0x00ff));++bytc;++bytc1;l=7;j=0;++i;ii=i;}
					
	}

	//bitc+=i;

	if(i==brwi){brwi=0;}else{

		bti=0;for(j=ii;j<brwi;++j){bt[bti]=brw[j];++bti;}
		i=0;l=7;j=0;
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}
		if(i<bti){if(bt[i]){j|=1<<l;}++i;--l;}

		fprintf(fw1,"%c",(j&0x00ff));++bytc;++bytc1;
	}

	//bitc+=i;

	return(0);
}

int	pr24_(long e,int b_[32],int b_i,int af)
{

	int	a,b=0,d=-1,c;
	b_i=0;
	e&=0x00ffffff;
	for(a=24-1;a>=0;--a)
	{
		c=0;c=1<<a;
		if(((c&e)>>a)==1){if(d==-1){d=a;}if(af){b_[b_i]=1;++b_i;}}else{
			if(af){b_[b_i]=0;++b_i;}
		}
	}
	//printf("!%d %d!",e,d);
	return(d+1);

}

int pf_(long n)
{

	int	d,i,j,l=0;

	d=pr24_(n,bt32_1,bt32i_1,0);

	if(d>=0&&d<=2) {d=2;}
	if(d>2&&d<=4)  {d=4;}
	if(d>4&&d<=6)  {d=6;}
	if(d>6&&d<=8)  {d=8;}
	if(d>8&&d<=10) {d=10;}
	if(d>10&&d<=12){d=12;}
	if(d>12&&d<=14){d=14;}
	if(d>14&&d<=16){d=16;}
	if(d>16&&d<=18){d=18;}
	if(d>18&&d<=20){d=20;}

	//printf("!%d!",d);

	for(i=0;i<d;i+=2)
	{
		if
		(
			(((n&(0x3<<(d-2-i)))>>(d-2-i))&0x3)!=0
		)
		{
			pr24_((((n&(0x3<<(d-2-i)))>>(d-2-i))&0x3),bt32_1,bt32i_1,1);
			for(j=0;j<2;++j){br[bri]=bt32_1[22+j];++bri;++l;}

		}else{br[bri]=0;++bri;++l;br[bri]=0;++bri;++l;}
	}

	return(l);

}

int p_d(int b1_,int b2_,int b3_)
{
int	b1,b2,b3;
int	d1,d2,d3;
int	d1_,d2_,d3_;
int	b8o,b8e;

	b8o=0;
	b8o|=1<<0;
	b8o|=1<<2;
	b8o|=1<<4;
	b8o|=1<<6;

	b8e=0;
	b8e|=1<<1;
	b8e|=1<<3;
	b8e|=1<<5;
	b8e|=1<<7;

	b1=b1_<<1;
	b2=b2_<<1;
	b3=b3_<<1;

	d1_=((((b2&b8e)>>1)^(b1&b8o))|((b2&b8e)^((b1&b8o)<<1)));	
	d2_=((((b2&b8e)>>1)^(b3&b8o))|((b2&b8e)^((b3&b8o)<<1)));

	d1=d1_<<1;
	d2=d2_<<1;

	d1__=((((d1&b8e)>>1)^(d2&b8o))|((d1&b8e)^((d2&b8o)<<1)));	

	return(0);
}

int	ar_i(int ri,int rj,int rk)
{
	int i,j,k;

 	da.resize(ri);for(i=0;i<ri;++i){da[i].resize(rj);for(j=0;j<rj;++j){da[i][j].resize(rk);}}

	return(0);
}

using namespace std;

int main(int argc,char *argv[])
{

int	a,b,c,d,e;
int	i,j,k,l,m,n;
int	lc;
int	b1_,b2_,b3_,b4_,b5_;

char	nl[256];int nli=0;
int	fbyte;
int	b1,b2,b3,b4,b5;

	printf("\n\tmCompression 1.0.0\n");
	printf("\twritten by Dzinleski Jasenko December , 2013\n\n");

	if(argv[1]==NULL){return(0);}else{
		strcpy(infn,argv[1]);f1=fopen(infn,"rb");
		if(f1==NULL){return(0);}else{fclose(f1);}
	}

	for(i=0;i<256;++i){for(j=0;j<256;++j){for(k=0;k<256;++k){
	pa[i][j][k][0]=-1;}}}

 	da.resize(Abc);for(i=0;i<Abc;++i){da[i].resize(Rbc);for(j=0;j<Rbc;++j){da[i][j].resize(Rbl);}}
	for(i=0;i<Abc;++i){da[i][0][0]=-1;da[i][0][1]=Rbc;}

	bc=0;bc_=0;bitc=0;
	f1=fopen(infn,"rb");
	f2=fopen(cfn,"wb");

	b1=getc(f1);if(!feof(f1)){++bc;}
	b2=getc(f1);if(!feof(f1)){++bc;}
	b3=getc(f1);if(!feof(f1)){++bc;}
	b4=getc(f1);if(!feof(f1)){++bc;}
	b5=getc(f1);if(!feof(f1)){++bc;}

	while(!feof(f1))
	{

		p_d(b1,b3,b5);d2__=d1__;p_d(b2,b3,b4);
		sai=0;e=0;c=1;i=2;
		sa[sai]=b1;++sai;
		sa[sai]=b2;++sai;
		sa[sai]=b3;++sai;
		sa[sai]=b4;++sai;
		sa[sai]=b5;++sai;
		while(!feof(f1)&&(d2__==d1__)&&sai<Rbl-2)
		{
			b1=b2;
			b2=b3;
			b3=b4;
			b4=getc(f1);if(!feof(f1)){++bc;}else{break;}sa[sai]=b4;++sai;
			b5=getc(f1);if(!feof(f1)){++bc;}else{break;}sa[sai]=b5;++sai;
			i+=1;j=1;e=0;
			while(j<i)
			{
				p_d(sa[i-j],sa[i],sa[i+j]);d2__=d1__;
				p_d(sa[i-(j+1)],sa[i],sa[i+(j+1)]);
				++j;
			}
			++c;
		}
		if(feof(f1)){break;}

		if(pa[sa[i-1]][sa[i]][sa[i+1]][0]==-1)
		{
			pa[sa[i-1]][sa[i]][sa[i+1]][0]=pai;a=pai;++pai;
			pa[sa[i-1]][sa[i]][sa[i+1]][1]=1;
			pa[sa[i-1]][sa[i]][sa[i+1]][2]=sai;
		}else{
			a=pa[sa[i-1]][sa[i]][sa[i+1]][0];
			++pa[sa[i-1]][sa[i]][sa[i+1]][1];
			pa[sa[i-1]][sa[i]][sa[i+1]][2]+=sai;
		}

		if(a>=Abc)
		{
			l=Abc;Abc=1+a;
			da.resize(Abc);
			for(i=l;i<Abc;++i){
			da[i].resize(Rbc);for(j=0;j<Rbc;++j){
			da[i][j].resize(Rbl);}}
			for(i=l;i<Abc;++i){da[i][0][0]=-1;da[i][0][1]=Rbc;}
		}

		if(da[a][0][0]==-1)
		{

			da[a][0][0]=1;
			l=da[a][0][0];
			da[a][l][0]=a;
			da[a][l][1]=sai;
			for(i=0;i<sai;++i){da[a][da[a][0][0]][2+i]=sa[i];}
			++dai;
		}else{

			m=-1;l=-1;
			for(i=1;i<=da[a][0][0];++i)
			{
				if(da[a][i][0]==a&&da[a][i][1]==sai)
				{
					k=0;b=0;
					while((-1+(sai-1)/2)+b<sai)
					{
						if
						(
							(da[a][i][(2+(-1+(sai-1)/2))-b]==sa[(-1+(sai-1)/2)-b])
							&&
							(da[a][i][(2+(-1+(sai-1)/2))+b]==sa[(-1+(sai-1)/2)+b])
						)
						{++k;}
						++b;
					}

					if(k==sai-1){l=i;break;}
					if(k>0&&m==-1){m=k;l=i;}else{if(k>0&&m<k){m=k;l=i;}}
				}
			}



			if((k==sai-1)||(m>=(sai-1)/2))
			{
				if(l==-1)
				{
					++da[a][0][0];
					if(da[a][0][0]>=da[a][0][1])
					{
						l=da[a][0][1];
						da[a].resize(Rbc+l);
						for(j=0;j<Rbc+l;++j){da[a][j].resize(Rbl);}
						da[a][0][1]=l+Rbc;
					}
					l=da[a][0][0];
					da[a][l][0]=a;
					da[a][l][1]=sai;
					for(i=0;i<sai;++i){da[a][da[a][0][0]][2+i]=sa[i];}
					++dai;
				}
			}else{
					++da[a][0][0];
					if(da[a][0][0]>=da[a][0][1])
					{
						l=da[a][0][1];
						da[a].resize(Rbc+l);
						for(j=0;j<Rbc+l;++j){da[a][j].resize(Rbl);}
						da[a][0][1]=l+Rbc;
					}
					l=da[a][0][0];
					da[a][l][0]=a;
					da[a][l][1]=sai;
					for(i=0;i<sai;++i){da[a][da[a][0][0]][2+i]=sa[i];}
					++dai;
			}

		}

		bitc+=pf_(l&0xffff);
		bitc+=pf_(a&0xffff);

		if(bri>128)
		{
			a=bri;
			while(a>128&&((double)a/(double)8)==(a/8)){--a;}
			i=0;
			while(i<a-8)
			{
				j=0;
				if(br[i]){j|=1<<7;}
				if(br[++i]){j|=1<<6;}
				if(br[++i]){j|=1<<5;}
				if(br[++i]){j|=1<<4;}
				if(br[++i]){j|=1<<3;}
				if(br[++i]){j|=1<<2;}
				if(br[++i]){j|=1<<1;}
				if(br[++i]){j|=1<<0;}
				fprintf(f2,"%c",j&0xff);
				++i;
			}
			bi=bri;bri=0;for(j=i;j<bi;++j){br[bri]=br[j];++bri;}
		}

		b1=getc(f1);if(!feof(f1)){++bc;}else{break;}
		b2=getc(f1);if(!feof(f1)){++bc;}else{break;}
		b3=getc(f1);if(!feof(f1)){++bc;}else{break;}
		b4=getc(f1);if(!feof(f1)){++bc;}else{break;}
		b5=getc(f1);if(!feof(f1)){++bc;}else{break;}

	}
	fclose(f1);
	fclose(f2);

	printf("\t File Bytes %d bytes \n\t Compressed %d bytes \n\t to %d bytes \n",
	(bc_+bc),
	bc,
	(bitc/8));

	printf("\t ~Ratio %e \n\n",100.0*(((double)bitc/(double)8)/(double)bc));

	return(0);

}