/* Bulls and cows. Server. It needs port number as the first parameter
 (default is 1234). */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

int sock_fd, newsock_fd;
int own_number , opp_number = 0, own_turn, opp_turn;

void finish();
/* this function closes socket and
writes "bye-bye" */

int recintonce();
/* this function receive integer
from socket and returns minus one
if it is empty */

void sendint(unsigned int num);
/* this function sends integer
to socket */

int test(int num);
/* this function tests if the number
is correct */

int count(int num);
/* this function counts quantity of
figures in the given number */

int cow(int num_1,  int num_2);
/* this function counts quantity of
cows in the two given numbers;
the result does not depend on the order
of the numbers */

int bull(int num_1, int num_2);
/* this function counts quantity of
bulls in the two given numbers;
the result does not depend on the order
of the numbers */

void oppexited();
/* this function sais that opponent
exited end finishes the program */

int main(int argc, char** argv)
{
    int party_len;
    struct sockaddr_in own_addr, party_addr;
    int PORTNUM = 1234; /* default */
    int num;

    printf("Bulls and cows net game\n");

    if (argc > 1) /* first parameter is port number */
    {
	PORTNUM = atoi(argv[1]);
    }

    /* create a socket */
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
	printf("Cannot create a socket\n");
	return(1);
    }

    memset(&own_addr, 0, sizeof(own_addr)); /* pushes zeroes to own_addr */
    own_addr.sin_family = AF_INET;
    own_addr.sin_port = PORTNUM;
    own_addr.sin_addr.s_addr = INADDR_ANY;

    /* bind a socket */
    if (bind(sock_fd, (struct sockaddr *) &own_addr, sizeof(own_addr)) < 0)
    {
	printf("Cannot bind a socket\n");
	return(1);
    }

    if (listen(sock_fd, 0) < 0)
    {
	printf("Cannot listen a socket");
	return(1);
    }

    printf("Waiting for connect...\n");

    party_len = sizeof(party_addr);

    if ((newsock_fd = accept(sock_fd, (struct sockaddr *) &party_addr, &party_len)) < 0)
    {
	printf("Cannot accept connection");
	return(1);
    }

    printf("Connection accepted\n");

    close(sock_fd); /* close socket - we do not need it more */

    

	/* ======= now we have an open socket to communicate ;) ======= */



    for (;;) /* receive own number until it is right*/
    {
	    printf("Enter YOUR number or 0 to exit: ");
	    scanf("%d", &num);
	    if (test(num)) /* right number */
		{
	        break;
		}
	    if (num == 0) /* exit */
		{
 	        sendint(0);
  	        finish();
		}
	    printf("Invalid format. Try again\n");
	} /* invalid format */

	opp_number = recintonce(); /* test if opponent stopped the game
			                   and read the number if it is sent */
	if (opp_number = 0) /* if he stopped... */
    {
	    printf("Opponent stops the game\n"); /* stop the game */
		finish();
    }

	own_number = num; /* send own number */
    sendint(own_number);

	if (opp_number == -1)
	{
		printf("Waiting for opponent turn...\n");

        for (;;)
		{
	        opp_number = recintonce;
	        if (opp_number == 0) /* opponent stopped the game */
			{
		        printf("Opponent stops the game\n");
			}
	        if (opp_number > 0)
		    break;
		}
	    printf("Opponent number: %d\n", opp_number); /* it needs to comment this */
	}

	signal(SIGPIPE, oppexited);



	/* ======= now we have received opponent number ======= */



	for (;;) /* game starts */
    {
        for (;;)
		{
	        printf("Enter YOUR turn or 0 to exit: ");
	        scanf("%d", &num);
	        if (test(num)) /* right number */
			{
    	        break;
			}
	        if (num == 0) /* exit */
			{
	            sendint(0);
	            finish();
			}
	        printf("Invalid format. Try again\n");
        }
	    printf("Your turn: %d %d bulls %d cows", own_turn, bull(own_turn, opp_number), 
	       cow(own_turn, opp_number));
	
	    opp_turn = recintonce(); /* test if opponent stopped the game
			                      and read the number if it is sent */
	if (opp_turn == 0) /* if he stopped... */
            oppexited(); /* stop the game */
	if (opp_number == -1) /* we have not recieve it */
        {
	        printf("Waiting for opponent turn...\n");
        }
	
	    own_turn = num;
	    sendint(own_turn);
	
	    if (opp_turn < 0)
		{
	        for (;;)
			{
		    opp_turn = recintonce();
	            if (opp_turn == 0) /* opponent stopped the game */
				    oppexited(); /* stop the game */
	            if (opp_turn > 0)
 		            break;
			}
		}
	    printf("Opponent turn: %d %d bulls %d cows\n", opp_turn, bull(opp_turn, own_number),
	           cow(opp_turn, own_number));
	       
	    if (own_turn == opp_number)
		{
	        if (opp_turn == own_number)
			{
	            printf("Nobody win.\n :|\n");
			}
	        else
			{
	            printf("You win!!!\n :)\n");
			}
	        finish();
		}
	    if (opp_turn == own_number)
		{
	        printf("You lose.\n :(\n");
			finish();
		}
    }   /* game ends */
}

void sendint(unsigned int num) 
{
    char n;

    n = (char) (num >> 8); /* n contains upper byte of num */
    if (write(newsock_fd, &n, 1) < 0) /* send the upper byte */
    {
	    printf("Unable to send data\n"); /* error */
	    finish();
    }
    n = (char) num; /* n contains lower byte of num */
    if (write(newsock_fd, &n, 1) < 0) /* send the lower byte */
    {
	    printf("Unable to send data\n"); /* error */
	    finish();
    }
}

int number(unsigned int num, unsigned int pos)
{
    while (pos > 1)
    {
	    num /= 10;
	    --pos;
    }

    return num - (num / 10) * 10;
}


int count(int num)
{
    int i = 1;

    while (num > 9)
    {
	    num /= 10;
	    ++i;
    }

    return i;
}


int test(int num)
{
    int i[] = {0, 0, 0, 0};

    if (num <= 0 || num > 9876 || count(num) != 4)
	    return 0;

    i[0] = number(num, 1);
    i[1] = number(num, 2);
    i[2] = number(num, 3);
    i[3] = number(num, 4);

    if (i[0] == i[1] || i[0] == i[2] || i[0] == i[3] || i[1] == i[2] ||
	    i[1] == i[3] || i[2] == i[3])
	    return 0;

    return 1;
}


int bull(int num_1, int num_2)
{
    int j, i = 0;

    for (j = 1; j <= 4; ++j)
    {
	if (number(num_1, j) == number(num_2, j) )
	    ++i;
    }

    return i;
}


int cow(int num_1, int num_2)
{
    int i, j, sum = 0;

    for (i = 1; i <= 4; ++i)
	    for (j = 1; j <= 4; ++j)
		{
	        if (i != j && number(num_1, i) == number(num_2, j))
		    ++ sum;
		}

    return sum;
}


int recintonce() 
{
    int i = 0, res;
    unsigned char n;
    unsigned int num;

    do
    {
	    res = read(newsock_fd, &n, 1);
	    if (res < 0)
		{
	        printf("Unable to read data\n"); /* error */
	        finish();
		}
	    if (res == 0 && i == 0) /* socket is empty */
		    return -1;
	    if (res > 0)
		{
   	        ++i;
	        if (i == 1) /* read the upper byte */
			{
		        num = n;
		        num <<= 8;
			}
	        else /* read the lower byte */
			{
		        num |= n;
			}
		}
    }
    while (i < 2);

    return num;
}


void finish()
{
    close(newsock_fd);
    printf("Bye bye\n");
    exit(0);
}

void oppexited()
{
	printf("Opponent stops the game\n");
	finish();
}
