//	This source and similar text sequences 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.

//  Permutation Groups 
//	written by Dzinleski Jasenko  May 2013


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

FILE		*f1,*f2,*f3,*f4,*f5,*f6,*f7;

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

char		out1fn[256]="out_1.txt";
char		out2fn[256]="out_2.txt";
char		out3fn[256]="out_3.txt";
char		out4fn[256]="out__.txt";

int		b8o,b8e;
int		b16o,b16e;

int 		ba16_1[16][16][16][16][4];		int ba16_1i=0;
int 		ba16_2[16][16][16][16][4];		int ba16_2i=0;
int		rd_[256][256][2];			int rd_i=0;
int 		rd_1[10000][3];				int rd1i=0;
int 		rd_2[10000][3];				int rd2i=0;

int		df1=0;
int		df2=0;
int		df3=1;

int		da[3][8];

int		rd__[256][256][256][2];			int rd__i=0;


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

	int	a,b,c,d,e;
	int	i,j,k,l,m;
	int	i_,j_,k_,l_;
	int	i__,j__,k__,l__;

	int	fbyte;

	int	d1,d2,d3;
	int	d1_,d2_,d3_,d4_;
	
	int	b1,b2,b3;
	int	b1_,b2_,b3_;
	
	for(i=0;i<16;++i){for(j=0;j<16;++j){for(k=0;k<16;++k){for(l=0;l<16;++l){
		ba16_1[i][j][k][l][0]=-1;ba16_1[i][j][k][l][2]=-1;ba16_1[i][j][k][l][1]=0;
		ba16_2[i][j][k][l][0]=-1;ba16_2[i][j][k][l][2]=-1;ba16_2[i][j][k][l][1]=0;
	}}}}
	ba16_1i=0;
	ba16_2i=0;
	
	for(i=0;i<256;++i){for(j=0;j<256;++j){
		rd_[i][j][0]=-1;
		rd_[i][j][1]=0;
	}}
	rd_i=0;

	for(i=0;i<256;++i){for(j=0;j<256;++j){for(k=0;k<256;++k){
		rd__[i][j][k][0]=-1;
		rd__[i][j][k][1]=0;
	}}}
	rd__i=0;
	
	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;

	b16o=0;
	b16o|=1<<0;
	b16o|=1<<2;
	b16o|=1<<4;
	b16o|=1<<6;
	b16o|=1<<8;
	b16o|=1<<10;
	b16o|=1<<12;
	b16o|=1<<14;
	
	b16e=0;
	b16e|=1<<1;
	b16e|=1<<3;
	b16e|=1<<5;
	b16e|=1<<7;
	b16e|=1<<9;
	b16e|=1<<11;
	b16e|=1<<13;
	b16e|=1<<15;

	f1=fopen(infn,"rb");

	b1_=getc(f1);
	b2_=getc(f1);
	b3_=getc(f1);

	while(!feof(f1))
	{

		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=((((b2&b8e)>>1)^(b3&b8o))|((b2&b8e)^((b3&b8o)<<1)));


		if(rd_[b1_][b2_][0]==-1){rd_[b1_][b2_][0]=rd_i;++rd_[b1_][b2_][1];a=rd_i;++rd_i;}else{
			a=rd_[b1_][b2_][0];
			++rd_[b1_][b2_][1];
		}
		if(ba16_1[(d1&0xf0)>>4][(d1&0x0f)>>0][(d2&0xf0)>>4][(d2&0x0f)>>0][0]==-1)
		{
			ba16_1[(d1&0xf0)>>4][(d1&0x0f)>>0][(d2&0xf0)>>4][(d2&0x0f)>>0][0]=ba16_1i;
			++ba16_1i;		
		}else{
			++ba16_1[(d1&0xf0)>>4][(d1&0x0f)>>0][(d2&0xf0)>>4][(d2&0x0f)>>0][1];
		}
		i_=0;for(i_=0;i_<rd1i;++i_){if(rd_1[i_][0]==a&&rd_1[i_][1]==((d1<<8)|d2)&&rd_1[i_][2]==((d2<<8)|d3)){break;}}
		if(i_==rd1i){rd_1[rd1i][0]=a;rd_1[rd1i][1]=((d1<<8)|d2);rd_1[rd1i][2]=((d2<<8)|d3);++rd1i;}
		

		if(rd_[b2_][b3_][0]==-1){rd_[b2_][b3_][0]=rd_i;++rd_[b2_][b3_][1];a=rd_i;++rd_i;}else{
			a=rd_[b2_][b3_][0];
			++rd_[b2_][b3_][1];
		}		
		if(ba16_2[(d2&0xf0)>>4][(d2&0x0f)>>0][(d3&0xf0)>>4][(d3&0x0f)>>0][0]==-1)
		{
			ba16_2[(d2&0xf0)>>4][(d2&0x0f)>>0][(d3&0xf0)>>4][(d3&0x0f)>>0][0]=ba16_2i;
			++ba16_2i;
		}else{
			++ba16_2[(d2&0xf0)>>4][(d2&0x0f)>>0][(d3&0xf0)>>4][(d3&0x0f)>>0][1];
		}			
		i_=0;for(i_=0;i_<rd2i;++i_){if(rd_2[i_][0]==a&&rd_2[i_][1]==((d1<<8)|d2)&&rd_2[i_][2]==((d2<<8)|d3)){break;}}
		if(i_==rd2i){rd_2[rd2i][0]=a;rd_2[rd2i][1]=((d1<<8)|d2);rd_2[rd2i][2]=((d2<<8)|d3);++rd2i;}


		b1_=b2_;
		b2_=b3_;
		b3_=getc(f1);

	}
	fclose(f1);
	
	printf("%d %d\n",ba16_1i,ba16_2i);
	
	printf("%d %d\n",rd1i,rd2i);
				
	m=1;a=1;
	while(m!=-1)
	{
	m=-1;
	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(ba16_1[i][j][k][l][1]>=1)
		{
			if(m==-1){m=ba16_1[i][j][k][l][1];i_=i;j_=j;k_=k;l_=l;}else{
				if(m<ba16_1[i][j][k][l][1]){m=ba16_1[i][j][k][l][1];i_=i;j_=j;k_=k;l_=l;}
			}
		}

	}}}}
	
	if(m!=-1){ba16_1[i_][j_][k_][l_][3]=a;ba16_1[i_][j_][k_][l_][1]=0;a+=2;}
	
	}
	printf("%d\t",a);

	m=1;a=1;
	while(m!=-1)
	{
	m=-1;
	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(ba16_2[i][j][k][l][1]>=1)
		{
			if(m==-1){m=ba16_2[i][j][k][l][1];i_=i;j_=j;k_=k;l_=l;}else{
				if(m<ba16_2[i][j][k][l][1]){m=ba16_2[i][j][k][l][1];i_=i;j_=j;k_=k;l_=l;}
			}
		}

	}}}}
	
	if(m!=-1){ba16_2[i_][j_][k_][l_][3]=a;ba16_2[i_][j_][k_][l_][1]=0;a+=2;}
	
	}
	printf("%d\n",a);

	f2=fopen(out1fn,"wb");
	f3=fopen(out2fn,"wb");
	f4=fopen(out3fn,"wb");	
	f5=fopen(out4fn,"wb");	

	d=0;
	f1=fopen(infn,"rb");

	b1_=getc(f1);
	b2_=getc(f1);
	b3_=getc(f1);

	while(!feof(f1))
	{

	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=((((b2&b8e)>>1)^(b3&b8o))|((b2&b8e)^((b3&b8o)<<1)));
		
	for(i=0;i<rd1i;++i)
	{				
		if(rd_[b1_][b2_][0]==rd_1[i][0])
		{
			if(ba16_1[(d1&0xf0)>>4][(d1&0x0f)>>0][(d2&0xf0)>>4][(d2&0x0f)>>0][0]!=-1)
			{
				if
				(
					ba16_1[(d1&0xf0)>>4][(d1&0x0f)>>0][(d2&0xf0)>>4][(d2&0x0f)>>0][3]==
					ba16_1[(rd_1[i][1]&0xf000)>>12][(rd_1[i][1]&0x0f00)>>8][(rd_1[i][1]&0x00f0)>>4][(rd_1[i][1]&0x000f)>>0][3]
				){break;}
			}
		}
	}
			
	b1=ba16_1[(d1&0xf0)>>4][(d1&0x0f)>>0][(d2&0xf0)>>4][(d2&0x0f)>>0][3]<<1;
	
	d1_=(rd_1[i][1]&0xff00)>>8;
	d2_=(rd_1[i][1]&0x00ff)>>0;

	for(j=0;j<rd2i;++j)
	{				
		if(rd_[b2_][b3_][0]==rd_2[j][0]&&rd_2[i][2]==rd_2[j][2])
		{
			if(ba16_2[(d2&0xf0)>>4][(d2&0x0f)>>0][(d3&0xf0)>>4][(d3&0x0f)>>0][0]!=-1)
			{
				if
				(
					ba16_2[(d2&0xf0)>>4][(d2&0x0f)>>0][(d3&0xf0)>>4][(d3&0x0f)>>0][3]==
					ba16_2[(rd_2[j][2]&0xf000)>>12][(rd_2[j][2]&0x0f00)>>8][(rd_2[j][2]&0x00f0)>>4][(rd_2[j][2]&0x000f)>>0][3]
				){break;}
			}
		}
	}
	
	b2=ba16_2[(d2&0xf0)>>4][(d2&0x0f)>>0][(d3&0xf0)>>4][(d3&0x0f)>>0][3]<<1;
	
	d3_=(rd_2[j][2]&0xff00)>>8;
	d4_=(rd_2[j][2]&0x00ff)>>0;

	d1=((((b1&b16e)>>1)^(b2&b16o))|((b1&b16e)^((b2&b16o)<<1)));
	
	++d;
	if(d==3)
	{
		da[d-1][0]=d1_;
		da[d-1][1]=d2_;
		da[d-1][2]=d3_;
		da[d-1][3]=d4_;
		da[d-1][4]=d1;
		da[d-1][5]=b1_;
		da[d-1][6]=b2_;
		da[d-1][7]=b3_;		

		if(rd__[da[0][4]][da[1][4]][da[2][4]][0]==-1)
		{
			rd__[da[0][4]][da[1][4]][da[2][4]][0]=rd__i;++rd__i;
			rd__[da[0][4]][da[1][4]][da[2][4]][1]=1;	
		}else{
			++rd__[da[0][4]][da[1][4]][da[2][4]][1];	
		}												
					
		if(df1){printf("%d\t%d\t%d\t%d\t%d\t%c%c%c\n",d1_,d2_,d3_,d4_,d1,a,b,c);printf("\n");}
		if(df2){printf("%d\t%d\t%d\t%c%c%c\n",da[0][4],da[1][4],da[2][4],da[0][5],da[1][5],da[2][5]);}	
		if(df3)
		{
			printf("%c",da[d-1][5]);
			fprintf(f2,"%c",da[d-1][5]);
			if(da[d-1][5]==13||da[d-1][5]==10){fprintf(f3,"%c",da[d-1][5]);}
		}
		d=0;
	}else{
		
		da[d-1][0]=d1_;
		da[d-1][1]=d2_;
		da[d-1][2]=d3_;
		da[d-1][3]=d4_;
		da[d-1][4]=d1;
		da[d-1][5]=b1_;
		da[d-1][6]=b2_;
		da[d-1][7]=b3_;														
		
		if(df1){printf("%d\t%d\t%d\t%d\t%d\t%c%c%c\n",d1_,d2_,d3_,d4_,d1,a,b,c);}
		if(df3)
		{
			printf("%c",da[d-1][5]);
			fprintf(f2,"%c",da[d-1][5]);
			if(d==1){fprintf(f3,"%d%c",da[d-1][4],(char)9);fprintf(f4,"%d%c%c",da[d-1][4],(char)13,(char)10);fprintf(f5,"%c%c",((da[d-1][4]&0xff00)>>8),((da[d-1][4]&0x00ff)>>0));}
		}
		
	}
					
	b1_=b2_;
	b2_=b3_;
	b3_=getc(f1);

	}
	fclose(f1);
	fclose(f2);
	fclose(f3);
	fclose(f4);
	fclose(f5);
	
	for(i=0;i<256;++i){for(j=0;j<256;++j){for(k=0;k<256;++k){
		if(rd__[i][j][k][0]!=-1){printf("%d\t%d\t%d\t%d\n",i,j,k,rd__[i][j][k][1]);}
	}}}
	
	return(0);
	
}