#include <iostream>
#include "graph_holder.h"
#include <math.h>

using namespace std;

extern void matrix_matrix_multiply(int *matrix_input_left, int *matrix_input_right, int *matrix_output, int left_matrix_rows,
								   int left_matrix_cols, int right_matrix_cols);
extern int read_line(char *buf, int ln, FILE *fptr, int ls);
void gen_synd(int *parmat,char *syndrome,char *err_pat);
char find_row(char *matrix, int m, int n, char *row);
int find_row_index(char *matrix, int m, int n, char *row);
extern void press_enter();


void bch31decode(int *input, int *output) {
//	std::cout << "\n entering bch31decode";
//	press_enter();
	
	FILE *fptr=0;
	  int i;
//	  std::cout << "\n recieved: ";
//	  for(i=0;i<31;i++)
//		  std::cout << " " << input[i];

	



int parmat[10][31]=        {{1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
  {1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
  {1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
  {1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
  {0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
  {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
  {1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
//std::cout << "\n havent called matrix_matrix_multiply yet";
//	press_enter();
  
int syndrome[10][1];
  matrix_matrix_multiply(parmat[0], input,
	syndrome[0],10 , 31
	, 1);
//  std::cout << "\n just called matrix_matrix_multiply yet";
//	press_enter();

  //std::cout << "\n syndrome:";

  for(i=0;i<10;i++)
	  syndrome[i][0]=syndrome[i][0]%2;
  //for(i=0;i<10;i++)
	//  std::cout << " " << syndrome[i][0];
  int number = syndrome[9][0]+syndrome[8][0]*2+syndrome[7][0]*4+syndrome[6][0]*8+syndrome[5][0]*16+
	  syndrome[4][0]*32+syndrome[3][0]*64+syndrome[2][0]*128+syndrome[1][0]*256+syndrome[0][0]*512;
  //std::cout << "\n number = " << number;
//  	std::cout << "\n 1+number = " << 1+number;
//std::cout << "\n right before opening the file";
//	press_enter();  
	fptr=fopen("c:/proj1/bch3121synd.txt", "r");
        if (!fptr)        {
                std::cout << "\n can't open file";
				press_enter();
                exit(1);
        }

       char trt[35];

	   char a[35],b[35],c[35];
	   
	   read_line(a,1,fptr,31);
	   read_line(b,2,fptr,31);
	   read_line(c,3,fptr,31);
	   
	   std::cout << "\n ";
	   /*
	   for(i=0;i<31;i++)
			std::cout << " " << (int) a[i];
	   std::cout << "\n ";
	   for(i=0;i<31;i++)
			std::cout << " " << (int) b[i];
	   std::cout << "\n ";
	   for(i=0;i<31;i++)
			std::cout << " " << (int) c[i];
press_enter(); */

                read_line(trt, 1+number, fptr,31);

				


        // using buf[i]:

            
//				std::cout << "\n 1+number = " << 1+number;
        fclose(fptr);
//		std::cout << "\n corrvct:";
//		for(i=0;i<31;i++)
//	  std::cout << " " <<  trt[i];

  for(i=0;i<31;i++)
	  output[i]=(input[i]+trt[i])%2;

}

void bch31decode_manual(int *input, int *output) {
//	std::cout << "\n entering bch31decode";
//	press_enter();
	
	  int i;
//	  std::cout << "\n recieved: ";
//	  for(i=0;i<31;i++)
//		  std::cout << " " << input[i];

	static char pass=0;
	static char syndrome_table[1024*10];
	static char err_patt[1024*31];




int parmat[10][31]=        {{1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
  {1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
  {0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
  {1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
  {1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
  {0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
  {1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
  {1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
//std::cout << "\n havent called matrix_matrix_multiply yet";
//	press_enter();


if (pass==0) {
		gen_synd((int *)parmat,syndrome_table,err_patt);
		pass++;
}
	   /*std::cout << "\n syndrome_table:";
	   std::cout << "\n";
	   for(i=0;i<10;i++)
		   std::cout << " " << (int) syndrome_table[0*10+i];
	   std::cout << "\n";
	      for(i=0;i<10;i++)
		   std::cout << " " << (int) syndrome_table[1*10+i];
		  std::cout << "\n";
		     for(i=0;i<10;i++)
		   std::cout << " " << (int) syndrome_table[1023*10+i];
  */
int syndrome[10][1];
  matrix_matrix_multiply(parmat[0], input,
	syndrome[0],10 , 31
	, 1);
//  std::cout << "\n just called matrix_matrix_multiply yet";
//	press_enter();

  //std::cout << "\n syndrome:";
char ss[10];
  for(i=0;i<10;i++)
	  ss[i]=syndrome[i][0]%2;
  //for(i=0;i<10;i++)
	  //std::cout << " " << syndrome[i][0];
 //std::cout << "\n right before opening the file";
//	press_enter();  
       char trt[31];
	   int z = find_row_index(syndrome_table, 1024,10,ss);

	   //std::cout << "\n z = " << z;
	   for(i=0;i<31;i++)
		   trt[i]=err_patt[z*31+i];

		//std::cout << "\n corrvct:";
		//for(i=0;i<31;i++)
	  //std::cout << " " <<  (int) trt[i];

  for(i=0;i<31;i++)
	  output[i]=(input[i]+trt[i])%2;

}

void gen_synd(int *parmat,char *syndrome_tab,char *err_pat) {
int i,j,ind1,ind2,ind3;
int q=0;
char temp_r[10];
memset(err_pat,0, 1024*31 * sizeof(char));
memset(syndrome_tab,0, 10 * sizeof(char));

for(i=1;i<32;i++) {
	err_pat[31*i-1+i]=1;
	for(j=0;j<10;j++) 
		syndrome_tab[i*10+j]=parmat[j*31+i-1];
}
i=32;

	for(ind1=0;ind1<31-1;ind1++) {
		for(ind2=ind1+1;ind2<31;ind2++) {
			err_pat[i*31+ind1]=1;
			err_pat[i*31+ind2]=1;
			for(j=0;j<10;j++) {
				syndrome_tab[i*10+j] = (parmat[j*31+ind1]+parmat[j*31+ind2])%2;
				}
			i++;
			}
		}



	for(ind1=0;ind1<31-2;ind1++) {
		for(ind2=ind1+1;ind2<31-1;ind2++) {
			for(ind3=ind2+1;ind3<31;ind3++) {
				//std::cout << "\n i = " << i; 
				for(j=0;j<10;j++) {
					temp_r[j] = (parmat[j*31+ind1]+parmat[j*31+ind2]+parmat[j*31+ind3])%2;
								  }
				if (find_row(syndrome_tab,i,10,temp_r)==0) {
					for(j=0;j<10;j++) 
					syndrome_tab[i*10+j]=temp_r[j];
					err_pat[i*31+ind1]=1;
					err_pat[i*31+ind2]=1;
					err_pat[i*31+ind3]=1;
					i++;

																	 }
				
				
				




				if (syndrome_tab[9]==1) {
					q++;
				}
				if(q==1) {
					std::cout << "\n First line changed!";
					std::cout << "\n i = " <<i;
					std::cout << "\n ind1 = " << ind1;
					std::cout << "\n ind1 = " << ind2;
					std::cout << "\n ind1 = " << ind3;
				}
if(i==1024)
			break;
															
											}
			if(i==1024)
			break;
										  }
		if(i==1024)
			break;
								 }

/*								 
std::cout << "i = " << i;
press_enter();
std::cout << "\n Error Matrix: ";
for(i=0;i<=1023;i++) {
	std::cout << "\n";
	for(j=0;j<31;j++)
		std::cout << " " << (int) err_pat[i*31+j];
}

std::cout << "\n Syndrome Matrix: ";
for(i=0;i<=1023;i++) {
	std::cout << "\n i = " << i << ": ";
	for(j=0;j<10;j++)
		std::cout << " " << (int) syndrome_tab[i*10+j];
}

*/
}


char find_row(char *matrix, int m, int n, char *row) {
// This function finds whether a row is present within a matrix.
// It takes as its input an matrix "matrix", represented as an 
// array of size "m"x"n", where the matrix is assumed to be "m" by "n"
// It returns 1 if "row" is one of the rows of this matrix and zero 
// otherwise. 
	int i,j;
	char ret=0;\
	/*	std::cout << "\n Matrix:";
		for(i=0;i<10;i++) {
			std::cout << "\n";
			for(j=0;j<n;j++) {
				std::cout << " " << (int) matrix[i*n+j];
			}
		}
		press_enter(); */

/*	std::cout << "\n find_row called!";
	std::cout << "\n m = " << m << " and n = " << n;
	std::cout << "\n the row is: \n " ;
		for(j=0;j<n;j++)
			std::cout << " " << row[j];
*/
		


	for(i=0;i<m;i++) {
	//	std::cout << "\n row = " << i;
	/*		if(i==433) {
					std::cout << "\n stop";
					std::cout << "\n stop";
					std::cout << "\n stop";
				} */

		for(j=0;j<n;j++) {
	/*		if (i==433) {
		std::cout << "\n n-1 = " << n-1;
		std::cout << "\n column = " << j;
			} */
			if (matrix[i*n+j]!=row[j])
				break;
			if (j==n-1)
				ret=1;
		}
	}

return ret;
}

int find_row_index(char *matrix, int m, int n, char *row) {
// This function finds whether a row is present within a matrix.
// It takes as its input an matrix "matrix", represented as an 
// array of size "m"x"n", where the matrix is assumed to be "m" by "n"
// It returns 1 if "row" is one of the rows of this matrix and zero 
// otherwise. 
	int i,j;
	int ret=-1;
	/*	std::cout << "\n Matrix:";
		for(i=0;i<10;i++) {
			std::cout << "\n";
			for(j=0;j<n;j++) {
				std::cout << " " << (int) matrix[i*n+j];
			}
		}
		press_enter(); */

/*	std::cout << "\n find_row called!";
	std::cout << "\n m = " << m << " and n = " << n;
	std::cout << "\n the row is: \n " ;
		for(j=0;j<n;j++)
			std::cout << " " << row[j];
*/
		


	for(i=0;i<m;i++) {
		for(j=0;j<n;j++) {
			if (matrix[i*n+j]!=row[j])
				break;
			if (j==n-1)
				ret=i;
		}
	}

return ret;
}


