
void CreateHandleConnectionThread(struct sHandleConnection* struct_connection)
{

#ifdef WIN32
	_beginthreadex(NULL,0,HandleConnection,(void*)struct_connection,0,NULL);
#else
int errorCode;
pthread_t ptTmp;
    if( (errorCode=pthread_create(&ptTmp, NULL, HandleConnection, (void*)struct_connection)) != 0 )
    {
            printf("\r\nThread error (%i):\r\n",errorCode);
            perror(" -    pthread_create() ");
            exit(0);
    }
#endif

}

/*OWS Server*/
int ListenToPort(int port, SOCKET* fd)
{
	SOCKADDR_IN saddr;
	
	*fd=socket(AF_INET,SOCK_STREAM,0);
#ifdef WIN32
	if (*fd==INVALID_SOCKET)
#else
		if (*fd<0)
#endif
			return -1;
		
		saddr.sin_family = AF_INET;
		saddr.sin_addr.s_addr= htonl(INADDR_ANY);
		saddr.sin_port = htons((unsigned short int)port);
		
		if (bind(*fd, (LPSOCKADDR) &saddr, sizeof(saddr)) == SOCKET_ERROR)
			return -2;
		
		if (listen(*fd,100) == SOCKET_ERROR)
			return -3;
		
		return 1;
}

int StartOWSServer(unsigned int port)
{
	int ret;
	struct sHandleConnection* struct_connection;
	SOCKADDR_IN owsServer_client_addr;
	int sin_size;
    SOCKET  OWS_Server_fd;
    SOCKET  OWS_Server_fd_conn;
	
	sin_size=sizeof(SOCKADDR_IN);
	
	ret = ListenToPort((int)port, &OWS_Server_fd);
	
	switch(ret)
	{
	case -1:
		printf("\r\n\r\nOpenWebSpider Server: socket() error\r\n\r\n");
        return 0;
		break;
	case -2:
		printf("\r\n\r\nOpenWebSpider Server: bind() error\r\n\r\n");
        return 0;
		break;
	case -3:
		printf("\r\n\r\nOpenWebSpider Server: listen() error\r\n\r\n");
        return 0;
		break;
	case 1:
		/* wait for a connection */
		while(1)
		{
			OWS_Server_fd_conn=accept(OWS_Server_fd, (struct sockaddr *)&owsServer_client_addr, &sin_size);

            if(glQuit==1)
                break;
			
#ifdef WIN32
			if (OWS_Server_fd_conn==INVALID_SOCKET)
#else
				if (OWS_Server_fd_conn<0)
#endif
					continue;
				
	

				//memory is freed in the function HandleConnection()
				struct_connection = malloc(sizeof(struct sHandleConnection));
				
				struct_connection->sock = OWS_Server_fd_conn;
				memcpy(&struct_connection->client,&owsServer_client_addr, sizeof(SOCKADDR_IN));
				CreateHandleConnectionThread(struct_connection);
		}
		
		closesocket(OWS_Server_fd);
		
		return 0;
	}
	
	closesocket(OWS_Server_fd);

return 0;
}

#ifdef WIN32
unsigned __stdcall 
#else
void* 
#endif
HandleConnection(void* connection)
{
SOCKET sock = ((struct sHandleConnection*)connection)->sock;
char query[MAXQUERYSIZE];
char origQuery[MAXQUERYSIZE];
char search_query[MAXQUERYSIZE];
char bufIn[2];
unsigned int queryArray[MAXWORDSxQUERY];
unsigned int query_elements;
int x,i;
int rec;
DWORD gtc;
RANKS* rankRes;
char* res;
int connOK;
int sortResults;
int fromBinaryQuery;
char* pp, *pp2;
int lLimit, rLimit;
int freeQuerySlot;
int numResults;
int *msg;
char *text_query;

    connOK = 1;

	while(connOK)
    {
        if(glQuit==1)
            break;

        memset(query,0,MAXQUERYSIZE);
        memset(queryArray,0,MAXWORDSxQUERY);

        rec=1;
        x=0;
        query_elements = 0;
		fromBinaryQuery = 0;

		search_query[0] = 0;

	    while(rec)
        {
            /* se la query è troppo lunga manda un messaggio di errore e sconnetti il client */
            if(x>=MAXQUERYSIZE)
            {
                printf("ERROR: Query too long\n");
                SEND(sock,"0:0.0\r\n");
                connOK=0;

                /* mette il primo carattere a 0 così il check subito dopo questo while fà 
                   un continue e si esce da while principale */
                query[0]=0;
                break;
            }

            if(recv(sock,bufIn,1,0)==1)
	        {

                /* ***************** */
                /* è il primo pacchetto e è binario ? */
                if(bufIn[0]=='b' && x == 0)
                {
                    /* ricevo un byte con il numero di parole della query */
                    if(recv(sock,(char*)&query_elements,sizeof(int),0)==sizeof(int))
                    {
                        /* se bufIn è 0 il pacchetto non è corretto */
                        if(query_elements<=0)
                            continue;

                        msg = malloc(query_elements*sizeof(int));

                        /* se ricevi correttamente la query */
                        if(recv(sock,(char*)msg,query_elements*sizeof(int),0)==query_elements*sizeof(int))
                        {
                            //res = queryArrayToText(msg, query_elements);
                            //strcpy(query,res);
                            memcpy(queryArray,msg,query_elements*sizeof(int));
                            FREE(msg);
                            //FREE(res);
                            res = NULL;
                            rec = 0;
                        }
                        else
                        {
                            FREE(msg);
                        }
                    }
                
                }
				else if(bufIn[0]=='t' && x == 0)	/* ricerca mysql */
                {
                    /* ricevo un byte con il numero di caratteri della query */
                    if(recv(sock,(char*)&query_elements,sizeof(int),0)==sizeof(int))
                    {
                        /* se bufIn è 0 il pacchetto non è corretto */
                        if(query_elements<=0)
                            continue;
						
                        text_query = malloc( query_elements + 1 );

                        /* se ricevi correttamente la query */
                        if(recv(sock,(char*)text_query,query_elements,0)==query_elements)
                        {
                            /* converte la query binaria in una testuale */
							/* s:0,1000:<query> */

							text_query[query_elements] = 0;

							memset(query,0,MAXQUERYSIZE);
							strcpy(query,"s:0,1000:");
							memcpy(query+9,text_query,query_elements);

                            FREE(text_query);

                            res = NULL;
                            rec = 0;
							fromBinaryQuery = 1;
                        }
                        else
                        {
                            FREE(text_query);
                        }
                    }
                
                }
                /* *********************** */

                if( rec == 0 || bufIn[0]=='\r' || bufIn[0]=='\n' || bufIn[0]=='\0' )
                    rec = 0;
                else
		            query[x++] = bufIn[0];
		    }
            else
            {
                connOK = 0;
                break;
            }
        }

        /* se la query è vuota e l'array è vuoto */
        if(query[0]==0 && query_elements==0)
            continue;

        /* logout */
        if(query[0]=='l'&& query[1]==0)
            break;

        sortResults = 0;

        /* formato query testuale:
           s:<inizio>,<quanti>:<query>
         */

        freeQuerySlot = GetFreeQuerySlot();
        if(freeQuerySlot == -1)
        {
            printf("ERROR: All slots full\n");
            SEND(sock,"0:0.0\r\n");
            continue;
        }
        queryStt[freeQuerySlot].available = 0;


        /* query testuale (o query testuale generata da binaria (fromBinaryQuery = 1) ) */
        if(query[0]=='s' && query[1]==':')
        {
            pp = strchr(query+2,',');
            if(!pp)
            {
                printf("ERROR: Wrong Format\n");
                SEND(sock,"0:0.0\r\n");
                InitQueryBuf(0,freeQuerySlot);
                continue;
            }

            pp[0]=0;

            lLimit = atoi(query+2);

            pp2 = strchr(pp+1,':');

            if(!pp2)
            {
                printf("ERROR: Wrong Format\n");
                SEND(sock,"0:0.0\r\n");
                InitQueryBuf(0,freeQuerySlot);
                continue;
            }

			strcpy(search_query, pp2+1);

            pp2[0]=0;
            rLimit = atoi(pp+1);
			
			/* converte le parole in ID solo se siamo in ricerca OOI */
			if( SERS_MODE == 0 )
			{
				/* processa una query testuale */
				/* splitta le parole e genera l'array di ID */
				if(parseTextQueries(search_query, queryArray, &query_elements) == 0 )
				{
					printf("ERROR: Wrong Format\n");
					SEND(sock,search_query);
					SEND(sock,":0.0\r\n");
					InitQueryBuf(0,freeQuerySlot);
					continue;
				}

				/* converte gli ID in una stringa di ID separati da ',' */
				query[0]=0;
				for(i=0;i<query_elements;i++)
				{
					/* origQuery usato temporaneamente per convertire l'ID della parola
					   in stringa */
					sprintf(origQuery,"%d",queryArray[i]);
					strcat(query,origQuery);

					if(i+1<query_elements)
						strcat(query,",");
				}
			}
			/* ********************************************* */

            printf("\nRecived text query: [%s]\n",search_query);

            strcpy(origQuery,query);

            /* questo nodo ha ricevuto un query testuale */
            /* quindi si aspetta i risultati ordinati per rank */
			if( fromBinaryQuery == 0)
				sortResults = 1;

        }

		/* invia gli ID delle parole a tutti i sottonodi solo se siamo in ricerca OOI */
		if( SERS_MODE == 0 )
		{
			if(query_elements <= 0)
			{
				printf("ERROR: Wrong Format\n");
				SEND(sock,"0:0.0\r\n");
				InitQueryBuf(0,freeQuerySlot);
			continue;
			}

			memcpy(queryStt[freeQuerySlot].queryArray,queryArray,query_elements*sizeof(int));
			queryStt[freeQuerySlot].nWords = query_elements;


			/* invia la query a tutti i sotto nodi */
			SendAMessageToAllNodesOOI(queryArray, query_elements);
		}
		else
		{
			/* siamo nella ricerca mysql */
			if( search_query[0] == 0 )
			{
				printf("ERROR: Wrong Format\n");
				SEND(sock,"0:0.0\r\n");
				InitQueryBuf(0,freeQuerySlot);
			continue;
			}


			/* salva la query testuale */
			strcpy(queryStt[freeQuerySlot].text_query, search_query);

			/* invia ai sottonodi la query testuale in un pacchetto binario */
			SendAMessageToAllNodesMysql( search_query );
		}

        gtc = GetTickCount();

		if( SERS_MODE == 0 )
		{
			/* cerca nel proprio indice */
			rankRes = ooiSearch(glLexicon, queryArray, query_elements, &numResults);
		}
		else
		{
			/* cerca nel mysql server */
			rankRes = mysqlSearch( search_query , &numResults);
		}

        /* aspetta che tutti i nodi abbiano ritornato un risultato */
        WaitResults(freeQuerySlot);

        /* ----------------- */

        gtc = (int)(GetTickCount()-gtc);
        printf("Results found in ms: %i\n", (int)gtc );

        /* abbiamo i risultati nella struttura in memoria ? */
        if(rankRes)
        {
            /* si:
                    ogni singolo nodo ordina i risultati per rank e passa al nodo 
                    superiore solo 1000 risultati(al massimo)
                    (lavorare con un massimo di 1000 risultati dovrebbe essere
                    abbastanza veloce :-) )
            */
            queryStt[freeQuerySlot].rkRes = mergeResults(queryStt[freeQuerySlot].rkRes, queryStt[freeQuerySlot].nRkRes, rankRes, numResults);
            queryStt[freeQuerySlot].nRkRes = queryStt[freeQuerySlot].nRkRes + numResults;

            FREE(rankRes);

            /* ordina i risultati per rank */
            insertion_sortRanks(queryStt[freeQuerySlot].rkRes, queryStt[freeQuerySlot].nRkRes, 1, 1);

            /* limita i risultati a MAXRESULTSxNODE */
            if(queryStt[freeQuerySlot].nRkRes > MAXRESULTSxNODE)
            {
                queryStt[freeQuerySlot].rkRes = limitResults(queryStt[freeQuerySlot].rkRes, MAXRESULTSxNODE);
                queryStt[freeQuerySlot].nRkRes = MAXRESULTSxNODE;
            }
        }

        /* rankRes da qui in poi è un semplice puntatore svuotato 
           i risultati di rankRes sono concatenati a quelli di queryStt.results */

        /* se abbiamo ricevuto una query testuale dobbiamo ordinare i risultati */
        if(sortResults==1)
            /* res è allocata in SortResults() */
            res = SortRANKSResults(queryStt[freeQuerySlot].rkRes,&queryStt[freeQuerySlot].nRkRes,lLimit, rLimit);

        if(sortResults==1)
        {
            SEND(sock,origQuery);
            SEND(sock,":");

		    if(res==NULL)
			    SEND(sock, "0.0,");
		    else
            {
                if(res[0]==0)
                    SEND(sock, "0.0,");
                else
			        SEND(sock, res);

                printf("Results: [%s]\n",res);
            }

            SEND(sock,"\r\n");
        }
        else
        {
			if( SERS_MODE == 0 )
			{
				/* ricerca OOI */

				/* protocollo:
				   | b | numero di parole della query | array delle parole | numero risultati | array risultati |
				 */
				/* query binaria */
				SEND(sock, "b");

				msg = malloc( sizeof(int)*(query_elements+1) );
				msg[0] = query_elements;
				memcpy(msg+1,queryArray,sizeof(int)*query_elements);
				SEND_BIN(sock, msg, sizeof(int)*(query_elements+1) );
				FREE(msg);
			}
			else
			{
				/* ricerca mysql */

				/* protocollo:
				   | t | lunghezza | query | numero risultati | array risultati |
				 */
				/* query binaria */
				SEND(sock, "t");

				msg = malloc( strlen(search_query) + sizeof(int) );
				msg[0] = strlen(search_query);
				memcpy(msg+1,search_query,strlen(search_query) );
				SEND_BIN(sock, msg, strlen(search_query) + sizeof(int) );
				FREE(msg);
			}

			msg = malloc( sizeof(int) + sizeof(RANKS)*(queryStt[freeQuerySlot].nRkRes) );
			msg[0] = queryStt[freeQuerySlot].nRkRes;
			memcpy(msg+1,queryStt[freeQuerySlot].rkRes,sizeof(RANKS)*queryStt[freeQuerySlot].nRkRes);
			SEND_BIN(sock, msg, sizeof(int) + sizeof(RANKS)*(queryStt[freeQuerySlot].nRkRes) );
			FREE(msg);

        }

        if(sortResults==1)
            FREE(res);  /* res è da liberare solo nel caso di ricerca ordinata */

        /* non và fatto il free di res2 ma và reinizializzato con InitQueryBuf() */
        InitQueryBuf(0,freeQuerySlot);
    }

	FREE(connection);
	
	closesocket(sock);
	
	ExitThread(0);
	return 0;
}


void WaitResults(int slot)
{
int waitRes;
int i;

    /* se non c'è nessun sotto-nodo connesso: esci */
    if( subNodesStruct.saddrElements==0 )
        return;

    waitRes = 1;
    /* aspetta i risultati da tutti i nodi connessi */
    while(1)
    {
        waitRes = 0;

        for(i=0; i<subNodesStruct.saddrElements; i++)
        {
            if(subNodesStruct.isConnected[i]==1 && queryStt[slot].NodeHasSent[i]==0)
            {
                waitRes = 1;
                break;
            }
        }

        if(waitRes==0)
            break;

        Sleep(SLEEP_DELAY1);
    }

return;
}
