#include "inf71320_SMS.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "inf71320_keyboard.h"

void command_mode();
int check_login(char login[LOGIN_LENGTH+1]);

int mainqueue;
int localqueue;
char loggeduser[LOGIN_LENGTH+1];
void *shm;

int main(int argc, char *argv[])
{
	Request msg;
	mainqueue = msgget( SRVR_MSG_Q, IPC_CREAT | 0666 );
	
	int shmid;
	
	printf( "SMS Client by Krzysztof Kotarski\n" );
	
	shmid=shmget( IPC_PRIVATE, sizeof(char)+sizeof(int), IPC_CREAT | 0644 );
	if( fork() == 0 )
	{
		close( 0 );
		shm = shmat( shmid, 0, 0 );
		*(unsigned char *)shm = 3;
		*(int*)(shm + 1) = -1;
		while( ( *(unsigned char *)shm != 2 ) )
		{
			if ( ( *(unsigned char *)shm == 0 ) &&
				( msgrcv( *(int*)(shm + 1) , &msg, sizeof( msg ) - sizeof( msg.m_type ), M_MSG, IPC_NOWAIT ) > 0 ) )
				 
			{
				printf( ">>>>> Otrzymano wiadomosc od: %s <<<<<\nTresc:\n%s\n", msg.login, msg.msg );
			}
			usleep( 1 );
		}
		shmdt( shm );
	}
	else
	{
		unsigned char key;
		int st;
		int ex = 0;
		int first = 1;
		shm = shmat( shmid, 0, 0 );
		init_keyboard();
		while ( !ex )
		{
			if( ( first ) || ( kbhit() ) )
			{
				if(!first)
					key = readch();
				close_keyboard();
				if( key == 27 )
				{
					*(unsigned char *)shm = 2;
					ex = 1;
					continue;
				}
				if( ( key == '\t' ) || ( first ) )
				{
					first = 0;
					if( *(unsigned char *)shm != 1 )
					{	
						//printf( "### Przechodze w tryb polecen\n" );
						*(unsigned char *)shm = 1;
						command_mode();
						*(unsigned char *)shm = 0;
						//printf( "### Wychodze z trybu polecen\n" );
					}
				}
				init_keyboard();
			}
			usleep( 1 );
		}
		close_keyboard();
		wait( &st );
		shmdt( shm );
		shmctl( shmid, IPC_RMID, 0 );
	}
	return 0;
}

void command_mode()
{
	Request req;
	Ack reqack;
	char cmd[12];
	
	//while(1)
	{
		printf("]:-> ");
		scanf("%s",cmd);
		if( strcmp(cmd,"exit") == 0 )
			return;
		if( strcmp(cmd,"login") == 0 )
			{
				if( strcmp(loggeduser,"") == 0 )
				{
					req.m_type = M_REQ_LOGIN;
					printf( "Logowanie\nlogin: " );
					scanf( "%s", req.login );
					if( check_login( req.login ) )
					{
						localqueue = msgget( atoi(&req.login[3]), IPC_CREAT | 0666 );
						printf( "password: " );
						scanf( "%s", req.data );
						msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
						msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
						if( reqack.result == RESULT_OK )
						{
							strcpy(loggeduser,req.login);
							*(int*)(shm + 1) = localqueue;
							printf( "[OK] Logowanie powiodlo sie\n" );
						}
						else
						{
							printf( "[ERR] Logowanie nie powiodlo sie\n" );
							if ( reqack.msg[0] != 0 )
								printf("%s\n",reqack.msg);
						}
					}
					else
					{
						printf( "[ERR] Bledny login\n" );
					}
				}
				else
					printf( "[ERR] Proba logowania podczas trwania sesji !\n" );
				return;
			}
		if( strcmp(cmd,"logout") == 0 )
			{
				req.m_type = M_REQ_LOGOUT;
				printf( "Wylogowywanie uzytkownika %s\n", loggeduser );
				strcpy(req.login,loggeduser);
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				if( ( msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 ) > 0 ) && 
					( reqack.result == RESULT_OK ) )
				{
					strcpy(loggeduser,"");
					printf( "[OK] Wylogowanie powiodlo sie\n" );
				}
				else
					printf( "[ERR] Wylogowanie nie powiodlo sie\n" );
				return;
			}
		if( strcmp(cmd,"passwd") == 0 )
			{
				req.m_type = M_REQ_PASSWD;
				printf( "Zmiana hasla uzytkownika %s\n", loggeduser );
				strcpy(req.login,loggeduser);
				printf( "new password: " );
				scanf( "%10s", req.data );
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
					printf( "[OK] Zmiana hasla powiodla sie\n" );
				else
					printf( "[ERR] Zmiana hasla nie powiodla sie\n" );
				return;
			}
		
		if( strcmp(cmd,"viewall") == 0 )
			{
				req.m_type = M_REQ_VIEWALL;
				printf( "Podglad listy wszytskich uzytkownikow\n" );
				strcpy(req.login,loggeduser);
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
				{
					printf( "[OK] Lista wszystkich uzytkownikow:\n%s", reqack.msg );
				}
				else
					printf( "[ERR] Proba podejrzenia listy wszytskich uzytkownikow nie powiodla sie\n" );
				return;
			}
		if( strcmp(cmd,"viewlogged") == 0 )
			{
				req.m_type = M_REQ_VIEWLOG;
				printf( "Podglad listy zalogowanych uzytkownikow\n" );
				strcpy(req.login,loggeduser);
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
				{
					printf( "[OK] Lista zalogowanych uzytkownikow:\n%s", reqack.msg );
				}
				else
					printf( "[ERR] Proba podejrzenia listy zalogowanych uzytkownikow nie powiodla sie\n" );
				return;
			}
		if( strcmp(cmd,"viewgroup") == 0 )
			{
				req.m_type = M_REQ_VIEWGRP;
				printf( "Podglad listy czlonkow grupy\n" );
				strcpy(req.login,loggeduser);
				printf( "group: ");
				scanf( "%s", req.data );
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
				{
					printf( "[OK] Lista czlonkow grupy %s:\n%s", req.data, reqack.msg );
				}
				else
					printf( "[ERR] Proba podejrzenia listy czlonkow grupy %s nie powiodla sie\n", req.data );
				return;
			}
		
		if( strcmp(cmd,"subscribe") == 0 )
			{
				req.m_type = M_REQ_SUBSCR;
				printf( "Zapisanie sie uzytkownika %s do grupy\n", loggeduser );
				strcpy(req.login,loggeduser);
				printf( "group: ");
				scanf( "%s", req.data );
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
					printf( "[OK] Dodanie uzytkownika do grupy powiodlo sie\n" );
				else
					printf( "[ERR] Dodanie uzytkownika do grupy nie powiodlo sie\n" );
				return;
			}
		if( strcmp(cmd,"unsubscribe") == 0 )
			{
				req.m_type = M_REQ_UNSUBSCR;
				printf( "Wypisanie sie uzytkownika %s z grupy\n", loggeduser );
				strcpy(req.login,loggeduser);
				printf( "group: ");
				scanf( "%s", req.data );
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
					printf( "[OK] Wypisanie uzytkownika z grupy powiodlo sie\n" );
				else
					printf( "[ERR] Wypisanie uzytkownika z grupy nie powiodlo sie\n" );
				return;
			}
		
		if( strcmp(cmd,"viewgroups") == 0 )
			{
				req.m_type = M_REQ_GETGRPS;
				printf( "Podglad listy wszytskich grup\n" );
				strcpy(req.login,loggeduser);
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
				{
					printf( "[OK] Lista wszystkich grup:\n%s", reqack.msg );
				}
				else
					printf( "[ERR] Proba podejrzenia listy wszytskich grup nie powiodla sie\n" );
				return;
			}
		
		if( strcmp(cmd,"senduser") == 0 )
			{
				int count=0;
				req.m_type = M_REQ_SNDUSR;
				printf( "Wysylanie wiadomosci SMS do uzytkownika\n" );
				strcpy(req.login,loggeduser);
				printf( "send to: " );
				scanf( "%s", req.data );
				while(getchar() != '\n');
				printf( "message: ");
				scanf(  "%255[^\n]", req.msg );
				while(getchar() != '\n') count++;
				if( count > 0 ) printf( "Za dlugi SMS, obcieto %d znakow\n", count );
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
				{
					printf( "[OK] Wysyłanie wiadomosci powiodlo sie\n" );
				}
				else
					printf( "[ERR] Wysylanie wiadomosci nie powiodlo sie\n" );
				return;
			}
		if( strcmp(cmd,"sendgroup") == 0 )
			{
				int count=0;
				req.m_type = M_REQ_SNDGRP;
				printf( "Wysylanie wiadomosci SMS do grupy\n" );
				strcpy(req.login,loggeduser);
				printf( "send to: " );
				scanf( "%s", req.data );
				while(getchar() != '\n');
				printf( "message: ");
				scanf(  "%255[^\n]", req.msg );
				while(getchar() != '\n') count++;
				if( count > 0 ) printf( "Za dlugi SMS, obcieto %d znakow\n", count );
				msgsnd( mainqueue, &req, sizeof( req ) - sizeof( req.m_type ), 0 );
				msgrcv( localqueue, &reqack, sizeof( reqack ) - sizeof( reqack.m_type ), req.m_type, 0 );
				if( reqack.result == RESULT_OK )
				{
					printf( "[OK] Wysyłanie wiadomosci powiodlo sie\n" );
				}
				else
					printf( "[ERR] Wysylanie wiadomosci nie powiodlo sie\n" );
				return;
			}
		if( strcmp(cmd,"help") == 0 )
			{
				printf("Lista dostepnych polecen:\n");
				printf("exit 		- 	wyjscie z trybu polecen\n");
				printf("login 		- 	zalogowanie uzytkownika\n");
				printf("logout 		- 	wylogowanie uzytkownika\n");
				printf("passwd 		- 	zmiana hasla uzytkownika\n");
				printf("viewall 	- 	podglad wszytskich uzytkownikow\n");
				printf("viewlogged 	- 	podglad zalogowanych uzytkownikow\n");
				printf("viewgroup 	- 	podglad uzytkownikow nalezacych do podanej grupy\n");
				printf("subscribe 	- 	zapisanie sie do grupy\n");
				printf("unsubsrcibe	- 	wypisanie sie z grupy\n");
				printf("viewgroups 	- 	podglad listy grup\n");
				printf("senduser 	- 	wyslanie wiadomosci do uzytkownika\n");
				printf("sendgroup 	- 	wyslanie wiadomosci do grupy\n");
				printf("help 		- 	wyswietlenie pomocy\n");
				return;
			}
		printf( "[ERR] Nierozpoznane polecenie\n" );
	}
}

int check_login(char login[LOGIN_LENGTH+1])
{
	int i;
	if( strncmp( login, "inf" ,3 ) != 0 )
		return 0;
	for( i = 3; i < LOGIN_LENGTH; i++ )
		if( ( login[i] < '0' ) || ( login[i] > '9' ) )
			return 0;
	return 1;
}
