#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "uici.h"

#define decprec        78
#define b1prec         127
#define b2prec         256   /* b2prec should be b1prec*2+2 */

#define server         "bach.dynet.com"
#define readport       7996
#define writeport      7995

#define BLKSIZE        1024


/* main() */
int main()
{
/* Variables for computation */
long kcount;
int i, j, jcount, k, l, pcount, pflag, subtr1flag, finished;
int d[decprec]; 
int b1[b1prec];
int b2[b2prec];
int bn[b2prec][decprec];
int lp1[b2prec];
FILE *wsf;
/* Variables for networking */
u_port_t portnum;
int commfd;
ssize_t bytesread;
int bytes_copied;
char buf[BLKSIZE];
char results[BLKSIZE] = "";
int ri;   /* results array index */
char unithalf[70];
char starthalf[70];
char current[70];
char authcode[9];
char str[188], tmpstr[9];

while (1) {    /* Main Loop */
/* Init some variables */
ri=0;  kcount=0;  jcount=0;  pcount=0;  pflag=1;  subtr1flag=0;
for (i=0; i<70; i++) { starthalf[i]=0;  unithalf[i]=0;  current[i]=0; }
for (i=0; i<9; i++) { authcode[i]=0;  tmpstr[i]=0; }
for (i=0; i<BLKSIZE; i++) { buf[i]=0; results[i]=0; }

/* Check to see if there's a .worksave file. */
/* If there is read start info from there else get it from the server */
if ((wsf = fopen(".worksave", "r")) != NULL) {
    fgets(str, 80, wsf);
    i=0;  j=0;
    while (str[i] != ' ') {
	unithalf[j] = str[i];  i++;  j++;
    }
    i++;  j=0;
    while (str[i] != '\n') {
	authcode[j] = str[i];  i++;  j++;
    }
    fgets(str, 80, wsf);
    i=0;  j=0;
    while (str[i] != ' ') {
	starthalf[j] = str[i];  i++;  j++;
    }
    i++;  j=0;
    while (str[i] != ' ') {
	tmpstr[j] = str[i];  i++;  j++;
    }
    tmpstr[j] = 0;  jcount = atoi(tmpstr);
    i++;  j=0;
    while (str[i] != '\n') {
	tmpstr[j] = str[i];  i++;  j++;
    }
    tmpstr[j] = 0;  pcount = atoi(tmpstr);
    j=0;
    while (!feof(wsf)) {    /* If not eof yet,  there must also be results */
	i=0;
	if (fgets(str, 186, wsf)) {
	    while (str[i] != '\n') {
		results[j]=str[i];  i++;  j++;
	    }
	    results[j]='\n';  j++;  ri=j;
	}
    }
    printf("Unit half  : %s\n", unithalf);
    printf("Auth code  : %s\n", authcode);
    printf("Previous results so far in work unit: \n%s", results);
    printf("Resuming at: %s\n", starthalf);
    fclose(wsf);
} else {
    /* Fetch start-half of work unit from server */
    portnum = (u_port_t)readport;
    if ((commfd = u_connect(portnum, server)) < 0) {
	u_error("Unable to establish connection to server");
	exit(1);
    }
    fprintf(stderr, "A connection has been made to %s\n", server);
    for ( ; ; ) {
	if ((bytesread = read(commfd, buf, BLKSIZE)) < 0) {
	    perror("Client read error");
	    break;
	} else if (bytesread == 0) {
	    fprintf(stderr, "Client detected end-of-file on input\n");
	    break;
	}
    }
    u_close(commfd);

    /* Parse buf for input data */
    printf("Work Unit from server: %s", buf);
    j=0;
    while (j<80) {
	if (buf[j] == ' ') { break; } else {
	    unithalf[j]=buf[j];
	}
	j++;
    }
    i=0;  j++;
    while (i<8) {
	authcode[i]=buf[j];
	i++;  j++;
    }

    printf("Unit half: %s\n", unithalf);
    printf("Auth code: %s\n", authcode);

    /* Set the starthalf string equal to the unithalf string */
    for (i=0; i<70; i++) { starthalf[i] = unithalf[i]; }
    
    /* Set subtr1flag */
    subtr1flag=1;
}

/* Initializations */
printf("\nInitializing...\n");
l=-1;
for (i=0; i<b1prec; i++) { b1[i]=0; }
for (i=0; i<b2prec; i++) { b2[i]=0; }
/* Initialize bn & lp1 */
bn[0][0]=1; lp1[0]=1;
for (j=1; j<b2prec; j++) { bn[0][j]=0; }
for (i=1; i<b2prec; i++)
{
        k=i-1;
        for (j=0; j<decprec; j++) { bn[i][j]=bn[k][j]*2; }
        /* Now carry digits */
        j=0; while ((bn[i][j]!=0) || (j<lp1[i-1]))
        {
                k=(int)(bn[i][j]/10);
                bn[i][j+1]+=k;
                bn[i][j]=bn[i][j]-k*10;
        j++; }
        lp1[i]=j;
}


j=0;
for (i=(strlen(starthalf)-1); i>-1; i-=1) {
    if (starthalf[i] == '1') { b1[j]=1; } else { b1[j]=0; }
    j++;
}
l=j-1;

/* Strip leading zeros if any exist */
j=l;  while ((j>-1) && (b1[j]==0)) { l-=1; j-=1; }

if (subtr1flag) {
    /* Now subtract 1 from the binary half to counter the first increment */
    /* This is because in the case of getting the starthalf from the */
    /* server, the starthalf has not been looked at yet.  But when getting */
    /* the starthalf from the .worksave file,  the last half has already */
    /* been looked at so we don't need to look at it again (it would also */
    /* throw off our count). */
    i=0; while ((b1[i]==0) && (i < b1prec)) { i++; }
    b1[i]=0;  if (i==l) { l-=1; }
    if (i != b1prec) { for (j=0; j<i; j++) { b1[j]=1; } }
}

/* Begin computation */
printf("Ok:\n");

finished=0;
while (!finished) {

/* Increment b1. */
i=0; while (b1[i]==1) { i++; }
b1[i]=1; 
if (i>l) { l++; }
for (j=0; j<i; j++) { b1[j]=0; }

/* Create b2 binary palindrome #1. */
j=0; for (i=l; i>-1; i-=1) { b2[j]=b1[i]; j++; }
for (i=0; i<=l; i++) { b2[j]=b1[i]; j++; }
         /* j is now the length+1 of b2. (b2[0..j-1]) */

/* Convert b2 to decimal d */
for (i=0; i<decprec; i++) { d[i]=0; }
for (i=0; i<j; i++)
{
        if (b2[i]==1)
        {
                for (k=0; k<lp1[i]; k++)
                { d[k]+=bn[i][k]; }
        }
}
/* Now carry all of the digits to next column. */
i=0; while ((d[i]!=0) || (i<lp1[j-1]))
{
        k=(int)(d[i]/10);
        d[i+1]+=k;
        d[i]=d[i]-k*10;
i++; }    /* i is now the length+1 of d[] */

/* Compare d[] to see if it's a palindrome. If so, printf it. */
k=0;  j=0;
while ((j<i) && (k==0)) {
	if (d[j]!=d[i-1-j]) k=1;
	j++;
}
if (k==0) 
{
        if (!pflag) { printf("\n");  pflag=1; }
        for (j=(l*2+1); j>-1; j-=1) {
	    printf("%d", b2[j]);
	    results[ri] = b2[j] + 48;  ri++;
	}
        i-=1; printf("     ");
	results[ri] = ' ';  ri++;
        for (j=i; j>-1; j-=1) {
	    printf("%d", d[j]);
	    results[ri] = d[j] + 48;  ri++;
       	}
        printf("\n");
	results[ri] = '\n';  ri++;
}

/* Create b2 binary palindrome #2. */
j=0; for (i=l; i>-1; i-=1) { b2[j]=b1[i]; j++; }
b2[j]=0; j++;
for (i=0; i<=l; i++) { b2[j]=b1[i]; j++; }
         /* j is now the length+1 of b2. (b2[0..j-1]) */

/* Convert b2 to decimal d */
for (i=0; i<decprec; i++) { d[i]=0; }
for (i=0; i<j; i++)
{
        if (b2[i]==1)
        {
                for (k=0; k<lp1[i]; k++)
                { d[k]+=bn[i][k]; }
        }
}
/* Now carry all of the digits to next column. */
i=0; while ((d[i]!=0) || (i<lp1[j-1]))
{
        k=(int)(d[i]/10);
        d[i+1]+=k;
        d[i]=d[i]-k*10;
i++; }    /* i is now the length+1 of d[] */

/* Compare d[] to see if it's a palindrome. If so, printf it. */
k=0;  j=0;
while ((j<i) && (k==0)) {
	if (d[j]!=d[i-1-j]) k=1;
	j++;
}
if (k==0) 
{
        if (!pflag) { printf("\n");  pflag=1; }
        for (j=(l*2+2); j>-1; j-=1) {
	    printf("%d", b2[j]);
	    results[ri] = b2[j] + 48;  ri++;
       	}
        i-=1; printf("     ");
	results[ri] = ' ';  ri++;
        for (j=i; j>-1; j-=1) {
	    printf("%d", d[j]);
	    results[ri] = d[j] + 48;  ri++;
       	}
        printf("\n");
	results[ri] = '\n';  ri++;
}

/* Create b2 binary palindrome #3. */
j=0; for (i=l; i>-1; i-=1) { b2[j]=b1[i]; j++; }
b2[j]=1; j++;
for (i=0; i<=l; i++) { b2[j]=b1[i]; j++; }
         /* j is now the length+1 of b2. (b2[0..j-1]) */

/* Convert b2 to decimal d */
for (i=0; i<decprec; i++) { d[i]=0; }
for (i=0; i<j; i++)
{
        if (b2[i]==1)
        {
                for (k=0; k<lp1[i]; k++)
                { d[k]+=bn[i][k]; }
        }
}
/* Now carry all of the digits to next column. */
i=0; while ((d[i]!=0) || (i<lp1[j-1]))
{
        k=(int)(d[i]/10);
        d[i+1]+=k;
        d[i]=d[i]-k*10;
i++; }    /* i is now the length+1 of d[] */

/* Compare d[] to see if it's a palindrome. If so, printf it. */
k=0;  j=0;
while ((j<i) && (k==0)) {
	if (d[j]!=d[i-1-j]) k=1;
	j++;
}
if (k==0) 
{
        if (!pflag) { printf("\n");  pflag=1; }
        for (j=(l*2+2); j>-1; j-=1) {
	    printf("%d", b2[j]);
	    results[ri] = b2[j] + 48;  ri++;
	}
        i-=1; printf("     ");
	results[ri] = ' ';  ri++;
        for (j=i; j>-1; j-=1) {
	    printf("%d", d[j]);
	    results[ri] = d[j] + 48;  ri++;
	}
        printf("\n");
	results[ri] = '\n';  ri++;
}

kcount++;
if (kcount==8388608) {     /* 8,388,608 loops to save current binary half */
    kcount=0;  jcount++;  pcount++;
    /* Set current[] to the string of the current binary half */
    i=0;  for (j=l; j>-1; j-=1) { current[i]=b1[j]+48;  i++; }  current[i]=0;

    if (pcount==4) {     /* 33,554,432 loops to print current binary half */
	/* Print out current binary half */
	printf("%s\n", current);  pcount=0;
    }

    /* Save current binary half to file */
    if ((wsf = fopen(".worksave", "w")) == NULL) {
	fprintf(stderr, "Cannot open .worksave file.\n");;
	exit(1);
    }
    /* fprintf all the necessary info to the file */
    fprintf(wsf, "%s %s\n", unithalf, authcode);
    fprintf(wsf, "%s %d %d\n", current, jcount, pcount);
    fprintf(wsf, "%s", results);
    fclose(wsf);
    
    if (jcount==128) {    /* 1,073,741,824 loops to a unit */
	jcount=0;

	/* Now set buf to the data to upload */
	i=0;
	while (i<strlen(unithalf)) { buf[i] = unithalf[i]; i++; }
	buf[i]='\n';  i++;  j=0;
	while (j<strlen(results)) { buf[i] = results[j]; i++; j++; }
	j=0;
	while (j<strlen(authcode)) { buf[i] = authcode[j]; i++; j++; }
	buf[i]=0;
	printf("\nUploading data...\n");
	/* Open writeport (and write to when a connection is received) */
	portnum = (u_port_t)writeport;
	while ((commfd = u_connect(portnum, server)) < 0) {
	    u_error("Unable to establish connection to server.\nWill try again in 5 minutes...\n");
	    sleep(300);
	}
	fprintf(stderr, "A connection has been made to %s\n", server);

	/* Now write data to socket */
        bytes_copied = strlen(buf);
        fprintf(stderr, "Sending:\n%s\n", buf);
        if (bytes_copied != u_write(commfd, buf, (size_t)bytes_copied)) {
            u_error("Client write_error");
	}
        close(commfd);
        fprintf(stderr, "[%ld]: Bytes transferred = %d\n",
                (long)getpid(), bytes_copied);
	u_close(commfd);
	finished=1;
	/* Now delete the .worksave file */
	if (remove(".worksave")) {
	    fprintf(stderr, "Cannot delete .worksave file.\n");
	    exit(1);
	}
    }   /* End of if (jcount... */
}   /* End of if (kcount... */

}   /* End of while(!finished) */

}   /* End of while(1) loop */

}   /* End of main() */


