#include <fcntl.h>
#include "io.h"
#include <stdio.h>
#include "malloc.h"
#include "stdlib.h"
#include "time.h"
#include "conio.h"
#include <string.h>

int Matrix[5][5]={{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}};
int *ptr;

void Print();
void MagicCheck();
int Save(char *Path);
int Load(char *Path);
int Code(char *FileName, char *NewName);
int Decode(char *FileName, char *NewName);
void Generate();

void main()
{
 char str1[200],str2[200];
 int x;
 ptr=&Matrix[0][0];
 do {
  	clrscr();
 	printf("Magic square coding system. Chose operation:\n\n");
	printf("1. Coding\n");
 	printf("2. Decoding\n");
   printf("3. Exit\n");
   x=getch();
   switch (x) {
    case 49: printf("Enter path to the object:\n");
       	  gets(str1);
           printf("Now a magic square will be generated.\n");
           Generate();
           printf("Checking magic:\n");
           MagicCheck();
           printf("Enter path to coded file:\n");
           gets(str2);
           printf("Please wait...\n");
           Save(str2);
           Code(str1,str2);
           printf("Operation complete. Program will save used matrix-key in the same directory.\n");
           printf("You will need this file to decode object.\n");
           break;

     case 50: printf("Enter path to the coded object:\n");
       	  gets(str1);
           printf("Make sure that the matrix key file is in the same directory.\n");
           printf("Checking magic:\n");
           Load(str1);
           MagicCheck();
           printf("Enter path to decoded file:\n");
           gets(str2);
           printf("Please wait...\n");
           Decode(str1,str2);
           printf("Operation complete. \n");
           break;

     case 27: break;
   }
 } while (x!=27);
 printf("Done.");
 getch();
}

int Decode(char *FileName, char *NewName)
{
   FILE *in,*out;
   static char *str,*str_new;
   in=fopen(FileName,"r");
   if (in==NULL)
   {
		fclose(in);
      return(0);
   }
   out=fopen(NewName,"w");
   if (out==NULL)
   {
		fclose(out);
      return(0);
   }
   int handle=open(FileName,O_RDONLY);
   long razmer=filelength(handle);
   while ((feof(in)==0)&&(razmer!=0))
   {
      str=(char*)malloc(26*sizeof(char)); str_new=(char*)malloc(26*sizeof(char));
   	fread(str,sizeof(char),25,in);
     	*(str+25)='\0';
      for (int i=0;i<25;i++) *(str_new+i)=' ';
      *(str_new+25)='\0';
      int j=0;
   	while ((j<25)&&(j<strlen(str)))
   	{
      	*(str_new+(int)(*(&Matrix[0][0]+j)-1))=*(str+j);
	      j++;
	   }
      fwrite(str_new,sizeof(char),strlen(str_new),out);
      *str='\0';*str_new='\0';
      free(str); free(str_new);
      razmer-=25;
   }
   fclose(in);
   fclose(out);
   return(1);
}

int Code(char *FileName, char *NewName)
{
	FILE *in,*out;
   static char *str,*str_new;
   in=fopen(FileName,"r");
   if (in==NULL)
   {
		fclose(in);
      return(0);
   }
   out=fopen(NewName,"w");
   if (out==NULL)
   {
		fclose(out);
      return(0);
   }
   int handle=open(FileName,O_RDONLY);
   long razmer=filelength(handle);
   while (feof(in)==0)
   {
      str=(char*)malloc(26*sizeof(char)); str_new=(char*)malloc(26*sizeof(char));
   	fread(str,sizeof(char),25,in);
      if (razmer>=25)
      	{
         	*(str+25)='\0';
            *(str_new+25)='\0';
            razmer-=25;
         }
      	else
         {
         	*(str+razmer)='\0';
            int d=strlen(str);
            for (int p=d; p<25; p++)
            	*(str+p)=' ';
            *(str+25)='\0';
            *(str_new+25)='\0';
         }
      int j=0;
   	while ((j<25)&&(j<strlen(str)))
   	{
      	*(str_new+j)=*(str+(int)(*(&Matrix[0][0]+j)-1));
	      j++;
	   }
      fwrite(str_new,sizeof(char),strlen(str_new),out);
      *str='\0';*str_new='\0';
      free(str); free(str_new);
   }
   fclose(in);
   fclose(out);
   return(1);
}

int Load(char *Path)
{
	FILE *in;
   char *name;
   char *r="matrix.a\0";
   int z=strlen(Path)-1;
   while (*(Path+z-1)!='\\') z--;
   name="";
   strcpy(name,Path);
   *(name+z)='\0';
   strcat(name,r);
   in=fopen(name,"r+b");
   if (in==NULL)
   {
		fclose(in);
      return(0);
   }
   fread(Matrix,sizeof(Matrix),1,in);
   fclose(in);
   return(1);
}

void MagicCheck()
{
	int i,j,sum,flag,*temp;

   flag=1;
   for (i=0; i<5; i++)
   {
   	sum=0;
      for (j=0; j<5; j++) sum=sum+Matrix[i][j];
      if (sum!=65) flag=0;
   }
   for (i=0; i<5; i++)
   {
   	sum=0;
      for (j=0; j<5; j++) sum=sum+Matrix[j][i];
      if (sum!=65) flag=0;
   }
   sum=0;
   for (i=0; i<5; i++) sum=sum+Matrix[i][i];
   if (sum!=65) flag=0;
   temp=ptr+4;
   sum=*temp;
   for (i=0; i<4; i++)
   {
      temp=temp+4;
      sum=sum+(*temp);
   }
   if (sum!=65) flag=0; else ;
   if (flag==0) printf("Analyze failed...\n");
   else printf("Magic\n");
}

void Generate()
{
   struct aCell
   {
   	int stroka;
      int stolbec;
   };
   const struct aCell Series[5]={{0,2},{1,1},{2,0},{3,4},{4,3}};
   struct aCell Key;
   int flag=1;
   int k1,k2,z;
   static int kt1,kt2;
   int *temp,*s, w[5][5]={{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}};

   randomize();
   Key=Series[random(5)];
	k1=Key.stolbec; //stolbec
	k2=Key.stroka; //stroka
   Matrix[k2][k1]=1;
	z=1; temp=ptr+k2*5+k1;
	while (flag==1)
	{
	 	flag=0;
		if (k1>=0&&k1<=3&&k2>=1&&k2<=4)
		{
         temp=temp-4;
         kt1=k1+1;
         kt2=k2-1;
		}
		else
      	if ((k1==4)&&(k2==0))
         {
         	temp=temp+16;
            kt1=0;
            kt2=4;
         }
         else
         	if ((k1==4)&&(k2>0))
            {
            	temp=temp-9;
               kt1=0;
               kt2=k2-1;
            }
            else
            	if ((k1<4)&&(k2==0))
               {
               	temp=temp+21;
                  kt1=k1+1;
                  kt2=4;
               }
      //checking
      if (*temp==0)
      {
      	z++;
         *temp=z;
         flag=1;
      }
      else 	//go down
      {
      	temp=ptr+k2*5+k1;      kt1=k1; kt2=k2;
			if (k2<4)
         {
         	kt2=k2+1;
            temp=temp+5;
         }
         else
         {
         	kt2=0;
            temp=temp-20;
         }
         //checking
         if (*temp==0)
      	{
      		z++;
         	*temp=z;
         	flag=1;
	      }
      }
     	k1=kt1; k2=kt2;
	}
   if (z<25) printf("Generation failed.\n");
   Print();
   //rotating square: 0-none; 1-90 CW; 2-180; 3-90 CCW
   randomize;
   flag=random(4);
   printf("rotation: %d \n",flag);
   switch (flag)
   {
    case 0: break;
    case 1: temp=&w[0][0];
    			for (k1=0; k1<5; k1++)
            {
            	for (k2=4; k2>=0; k2--)
               {
               	*temp=Matrix[k2][k1];
                  temp++;
               }
            }
            for (k1=0; k1<5; k1++)
            	for(k2=0;k2<5; k2++)
               	Matrix[k1][k2]=w[k1][k2];
            break;
    case 2: temp=&w[0][0];
    			s=ptr+24;
    			for (k1=0; k1<25; k1++)
            {
            	*temp=*s;
               temp++;
               s--;
            }
            for (k1=0; k1<5; k1++)
            	for(k2=0;k2<5; k2++)
               	Matrix[k1][k2]=w[k1][k2];
            break;
    case 3: temp=&w[0][0];
    			for (k1=4; k1>=0; k1--)
            {
            	for (k2=0; k2<5; k2++)
               {
               	*temp=Matrix[k2][k1];
                  temp++;
               }
            }
            for (k1=0; k1<5; k1++)
            	for(k2=0;k2<5; k2++)
               	Matrix[k1][k2]=w[k1][k2];
            break;
   }
   Print();
}

void Print()
{
	int *temp;
	temp=ptr;
	printf("Square: \n");
	for(int i=0; i<5; i++)
	{
		for (int j=0; j<5; j++)
		{
			printf("%4d",*temp);
			temp++;
		}
		printf("\n");
	}
}

int Save(char *Path)
{
	FILE *t;
   static char *name;
   char *r="matrix.a\0";
   int z=strlen(Path)-1;
   while (*(Path+z-1)!='\\') z--;
   name="";
   strcpy(name,Path);
   *(name+z)='\0';
   strcat(name,r);
   t=fopen(name,"w+b");
   if (t==NULL)
   {
   	fclose(t);
      return(0);
   }
   fwrite(Matrix,sizeof(Matrix),1,t);
   fclose(t);
   return(1);
}
