//	This source and File 16-bit parity patterns method apply to GNU General Public License. 
//			Copyright (C) 2013  Jasenko Dzinleski 

//	This source applies to the GNU General Public License as
//	published by the Free Software Foundation 
//	and can not be used, copied, sold, redistributed or 
//	used in any other way but only by written permission by Jasenko Dzinleski . 
//	Copyright (C) from 2001 - 2013 and later by Jasenko Dzinleski 

//	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.

//
//		File 16-bit parity patterns
//		written by Dzinleski Jasenko  September 16 , 2013
//

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

FILE		*f1,*f2;

char		infn[256]="a.bmp";
char		ofn[256]="out.mar";

int		b8o,b8e;
int		df=2;
int		bytc=0;

int		bf[1024];			int	bfi=0;
long		lb[1024][2];
int		pb[16][16][16][16][3];		int	pbi=0;
int 		ba16[16][16][16][16][2];	int 	bai;

char		p_s[256];

int p_format(double in_n,char fm[256],char arr0[256])
{

int		sig;
char		arr1[256];
double 		iv,fv;
long long	lv,rv;
char		fa[256];int	fai=0;
int		i,j,k,l,m,n,e;


	if(in_n<0){sig=1;in_n*=-1.0;iv=in_n;}else{sig=0;iv=in_n;}

	for(i=0;i<256;++i){fa[i]='\0';}fai=0;
	for(j=0;j<256;++j){arr0[j]='\0';}

	for(i=1;i<12;++i)
	{
		lv=(long)iv/pow(10,i);//printf("%d %d %d\n",lv,i,(long)pow(10,i));
		if(lv==0){e=i-1;break;}
	}
	if(i==12){printf("Overflow...\n");arr0[0]='0';return(0);}

	if(e-1<0)
	{
		rv=(long)iv/pow(10,e);//printf("!%c",(char)(48+rv));
		fa[fai]=(char)(48+rv);++fai;

	}else{

	rv=(long)iv/pow(10,e);//printf("!%c",(char)(48+rv));
	fa[fai]=(char)(48+rv);++fai;
	rv*=pow(10,e);fv=(long)iv-rv;
	for(i=e-1;i>=0;--i)
	{
		lv=(long)fv/pow(10,i);//printf("!%c",(char)(48+lv));
		fa[fai]=(char)(48+lv);++fai;
		rv+=lv*pow(10,i);fv=iv;fv-=rv;
	}

	}

	//printf("%s\n",fa);

	if(strlen(fm)!=0)
	{

		m=0;l=strlen(fm);
		for(i=strlen(fm)-1;i>=0;--i)
		{if(fm[i]==','||fm[i]=='.'){if(l==strlen(fm)){l=i+1;++m;}else{++m;}}}
		k=(strlen(fm)-((strlen(fm)-l)+m))-strlen(fa);

		if(k>=0)
		{

			j=0;for(i=0;i<k;++i)
			{if(fm[i]=='.'||fm[i]==','){++k;}arr0[j]=fm[i];++j;}n=i;

			for(i=0;i<strlen(fa);++i)
			{
				if(fm[i+n]=='.'||fm[i+n]==','){arr0[j]=fm[i+n];++j;++n;}
				arr0[j]=fa[i];++j;
			}
				
			if(l!=strlen(fm))
			{
				--l;arr0[j]=fm[l];++j;
				for(i=l+1;i<strlen(fm);++i){arr0[j]=fm[i];++j;}

				iv=in_n;
				for(i=0;i<256;++i){fa[i]='\0';}fai=0;

				iv=pow(10,(strlen(fm)-(l+1)))*(iv-(double)((long)iv));

				for(i=1;i<12;++i)
				{
					lv=(long)iv/pow(10,i);//printf("%d %d %d\n",lv,i,(long)pow(10,i));
					if(lv==0){e=i-1;break;}
				}
				if(i==12){printf("Overflow...\n");arr0[0]='0';return(0);}

				if(e-1<0)
				{
					rv=(long)iv/pow(10,e);//printf("!%c",(char)(48+rv));
					fa[fai]=(char)(48+rv);++fai;

				}else{

				rv=(long)iv/pow(10,e);//printf("!%c",(char)(48+rv));
				fa[fai]=(char)(48+rv);++fai;
				rv*=pow(10,e);fv=(long)iv-rv;
				for(i=e-1;i>=0;--i)
				{
					lv=(long)fv/pow(10,i);//printf("!%c",(char)(48+lv));
					fa[fai]=(char)(48+lv);++fai;
					rv+=lv*pow(10,i);fv=iv;fv-=rv;
				}

				}

				//printf("s\n",fa);

				if((strlen(fm)-(l+1))==strlen(fa))
				{

				for(i=strlen(arr0)-1;i>=0;--i)
				{if(arr0[i]=='.'||arr0[i]==','){j=i;break;}}++j;
				for(i=0;i<strlen(fa);++i){arr0[j]=fa[i];++j;}

				}else{

					k=(strlen(fm)-(l+1))-strlen(fa);
					for(i=strlen(arr0)-1;i>=0;--i)
					{if(arr0[i]=='.'||arr0[i]==','){j=i;break;}}++j;
					for(i=0;i<k;++i){arr0[j]='0';++j;}
					for(i=0;i<strlen(fa);++i){arr0[j]=fa[i];++j;}

				}

			}

		}else{

			k=strlen(fa)-(strlen(fm)-((strlen(fm)-l)+m));
			j=0;for(i=0;i<k;++i){arr0[j]=fa[i];++j;}n=i;
			
			for(i=n;i<strlen(fa);++i)
			{
				if(fm[i-n]=='.'||fm[i-n]==','){arr0[j]=fm[i-n];++j;--n;}
				arr0[j]=fa[i];++j;
			}

			if(l!=strlen(fm))
			{
				--l;arr0[j]=fm[l];++j;
				for(i=l+1;i<strlen(fm);++i){arr0[j]=fm[i];++j;}

				iv=in_n;
				for(i=0;i<256;++i){fa[i]='\0';}fai=0;

				iv=pow(10,(strlen(fm)-(l+1)))*(iv-(double)((long)iv));

				for(i=1;i<12;++i)
				{
					lv=(long)iv/pow(10,i);//printf("%d %d %d\n",lv,i,(long)pow(10,i));
					if(lv==0){e=i-1;break;}
				}
				if(i==12){printf("Overflow...\n");arr0[0]='0';return(0);}

				if(e-1<0)
				{
					rv=(long)iv/pow(10,e);//printf("!%c",(char)(48+rv));
					fa[fai]=(char)(48+rv);++fai;

				}else{

				rv=(long)iv/pow(10,e);//printf("!%c",(char)(48+rv));
				fa[fai]=(char)(48+rv);++fai;
				rv*=pow(10,e);fv=(long)iv-rv;
				for(i=e-1;i>=0;--i)
				{
					lv=(long)fv/pow(10,i);//printf("!%c",(char)(48+lv));
					fa[fai]=(char)(48+lv);++fai;
					rv+=lv*pow(10,i);fv=iv;fv-=rv;
				}

				}

				//printf("s\n",fa);

				if((strlen(fm)-(l+1))==strlen(fa))
				{

				for(i=strlen(arr0)-1;i>=0;--i)
				{if(arr0[i]=='.'||arr0[i]==','){j=i;break;}}++j;
				for(i=0;i<strlen(fa);++i){arr0[j]=fa[i];++j;}

				}else{

					k=(strlen(fm)-(l+1))-strlen(fa);
					for(i=strlen(arr0)-1;i>=0;--i)
					{if(arr0[i]=='.'||arr0[i]==','){j=i;break;}}++j;
					for(i=0;i<k;++i){arr0[j]='0';++j;}
					for(i=0;i<strlen(fa);++i){arr0[j]=fa[i];++j;}

				}
				
			}

		}

	}else{

		j=0;for(i=0;i<strlen(fa);++i){arr0[j]=fa[i];++j;}

	}

	for(i=0;i<strlen(arr0);++i){if(arr0[i]=='#'){arr0[i]=' ';}}
	for(i=0;i<strlen(arr0)-1;++i){if((arr0[i]==' ')&&(arr0[i+1]==','||arr0[i+1]=='.')){arr0[i+1]=' ';}}

	if(sig==1)
	{
		for(i=0;i<256;++i){arr1[i]='\0';}
		j=0;arr1[j]='-';++j;
		for(i=0;i<strlen(arr0);++i){arr1[j]=arr0[i];++j;}
		for(i=0;i<256;++i){arr0[i]='\0';}
		j=0;for(i=0;i<strlen(arr1);++i){arr0[j]=arr1[i];++j;}
	}

	//printf("%s\n",arr0);



	return(0);
}

double p_val(char arr0[256])
{

	int	j=0,k=0,l;

	long		fr;
	int		rvi;
	long		rvl;
	long long	rvd;
	double		rvd_;

	char 		arr1[256];

	for(j=0;j<256;++j){arr1[j]='\0';}
	l=0;for(j=0;j<strlen(arr0);++j){if((arr0[j]>='0'&&arr0[j]<='9')||(arr0[j]=='.'||arr0[j]==',')){arr1[l]=arr0[j];++l;}}

	for(j=0;j<256;++j){arr0[j]='\0';}l=0;for(j=0;j<strlen(arr1);++j){arr0[l]=arr1[j];++l;}

	for(j=0;j<strlen(arr0);++j){if(arr0[j]=='.'){break;}}

	if(j==strlen(arr0))
	{
		rvl=0;l=-1;
		for(j=-1+strlen(arr0);j>=0;--j)
		{
			++l;rvl+=(long)(-48+arr0[j])*pow(10,l);
		}
		rvi=(int)rvl;
		rvd_=(double)rvl;

	}else{

			fr=0;l=-1;
			for(k=-1+strlen(arr0);k>j;--k)
			{
				++l;fr+=(long)(-48+arr0[k])*pow(10,l);
			}

			rvd=0;l=-1;
			for(k=j-1;k>=0;--k)
			{
				++l;rvd+=(long long)(-48+arr0[k])*pow(10,l);

			}rvd*=(long long)pow(10,strlen(arr0)-j-1);

			rvd_=(double)(rvd+(long long)fr)/(long long)pow(10,strlen(arr0)-j-1);
				
	}

	return(rvd_);
}

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

int	a,b,c,d,e;
int	i,j,k,l,m;

int	b1_,b2_,b3_;
int	b1,b2,b3;
int	d1,d2,d3;
int	d1_,d2_,d3_;
int	mc=0,unmc=0;

	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<16;++i){for(j=0;j<16;++j){for(k=0;k<16;++k){for(l=0;l<16;++l){
		pb[i][j][k][l][0]=-1;ba16[i][j][k][l][0]=-1;
	}}}}	

	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;
	
	f1=fopen(infn,"rb");
	while(!feof(f1))
	{

		bfi=0;while(!feof(f1)&&bfi<1024){bf[bfi]=getc(f1);++bfi;}
	
		a=16;
		while(a>=1)
		{

			i=0;mc=0;unmc=0;
			for(i=0;i<bfi;i+=a)
			{

				b1_=bf[i];++i;
				b2_=bf[i];++i;
				b3_=bf[i];++i;

				b1=b1_<<1;
				b2=b2_<<1;
				b3=b3_<<1;
	
				d1=((((b1&b8e)>>1)^(b2&b8o))|((b1&b8e)^((b2&b8o)<<1)));	
				d2=((((b1&b8e)>>1)^(b3&b8o))|((b1&b8e)^((b3&b8o)<<1)));
				d3=((((d1&b8e)>>1)^(d2&b8o))|((d1&b8e)^((d2&b8o)<<1)));
	
				d1_=((((b2&b8e)>>1)^(b1&b8o))|((b2&b8e)^((b1&b8o)<<1)));	
				d2_=((((b2&b8e)>>1)^(b3&b8o))|((b2&b8e)^((b3&b8o)<<1)));
				d3_=((((d2_&b8e)>>1)^(d1_&b8o))|((d2_&b8e)^((d1_&b8o)<<1)));

				b=((b1_<<8)&0xff00)|(b3_&(0xff));

				if(ba16[(b&0xf000)>>12][(b&0x0f00)>>8][(b&0x00f0)>>4][b&0x000f][0]==-1)
				{
					ba16[(b&0xf000)>>12][(b&0x0f00)>>8][(b&0x00f0)>>4][b&0x000f][0]=d3;
					ba16[(b&0xf000)>>12][(b&0x0f00)>>8][(b&0x00f0)>>4][b&0x000f][1]=d3_;
				}else{
					if((ba16[(b&0xf000)>>12][(b&0x0f00)>>8][(b&0x00f0)>>4][b&0x000f][0]==d3)&&
				  	(ba16[(b&0xf000)>>12][(b&0x0f00)>>8][(b&0x00f0)>>4][b&0x000f][1]==d3_))
					{
						++mc;
						if(mc==1){lb[i][0]=0;lb[i][1]=0;}
						lb[i][0]|=1<<(a-1);++lb[i][1];
					}
				}

				b1_=b2_;
				b2_=b3_;
				b3_=bf[i];
	
			}
			if(df==1){printf("%d\t%d\n",a,mc);}
			--a;
		}
		for(i=0;i<bfi;++i)
		{
			if(pb[(lb[i][0]&0xf000)>>12][(lb[i][0]&0x0f00)>>8][(lb[i][0]&0x00f0)>>4]
			[(lb[i][0]&0x000f)>>0][0]==-1)
			{
				pb[(lb[i][0]&0xf000)>>12][(lb[i][0]&0x0f00)>>8][(lb[i][0]&0x00f0)>>4]
				[(lb[i][0]&0x000f)>>0][0]=pbi;++pbi;
				pb[(lb[i][0]&0xf000)>>12][(lb[i][0]&0x0f00)>>8][(lb[i][0]&0x00f0)>>4]
				[(lb[i][0]&0x000f)>>0][1]=1;
				pb[(lb[i][0]&0xf000)>>12][(lb[i][0]&0x0f00)>>8][(lb[i][0]&0x00f0)>>4]
				[(lb[i][0]&0x000f)>>0][2]=lb[i][1];
			}else{
				++pb[(lb[i][0]&0xf000)>>12][(lb[i][0]&0x0f00)>>8][(lb[i][0]&0x00f0)>>4]
				[(lb[i][0]&0x000f)>>0][1];
				pb[(lb[i][0]&0xf000)>>12][(lb[i][0]&0x0f00)>>8][(lb[i][0]&0x00f0)>>4]
				[(lb[i][0]&0x000f)>>0][2]+=lb[i][1];
			}
		}
	}
	fclose(f1);

	if(df==2){
		for(i=0;i<16;++i){for(j=0;j<16;++j){for(k=0;k<16;++k){for(l=0;l<16;++l){
			if(pb[i][j][k][l][0]!=-1)
			{
				a=0;
				for(b=16-1;b>=0;--b)
				{
					c=0;c=1<<b;
					if(((c&((i<<12)|(j<<8)|(k<<4)|(l<<0)))>>b)==1){a+=b+1;++d;printf("1");}else{printf("0");}
				}

				printf("\t%d\t%d\t",pb[i][j][k][l][1],a);
				p_format(log(pb[i][j][k][l][2]),"00000.00000",p_s);printf("%s\t",p_s);
				p_format(log(pb[i][j][k][l][2]/pb[i][j][k][l][1]),"00000.00000",p_s);printf("%s\n",p_s);
			}
		}}}}	
	}
}