/*  Copyright (C) 2001 Marc Casaldaliga Albisu <casaldaliga@ifae.es>
================================================================
 
  This code is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  This code is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with Emacs (which is required to make this stuff work); if
  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  Cambridge, MA 02139, USA.
==================================================================
*/ 


//g++ -c IONotifier.C `sigc-config --cflags`
#include "IONotifier.H"
//for printf
#include <stdio.h>
//for select
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
//for signals
#include <sigc++/signal_system.h>
using namespace SigC;
//for threads
#include <pthread.h>

IONotifier::IONotifier(int fd_)
            :fd(fd_),againWritableEmited(false),fdIsValid(true)
        {
            pthread_mutex_init(&mutex,NULL);
            pthread_create(&thread,NULL,&IONotifier::watchFor,this);
        }
IONotifier::~IONotifier()
        {
            pthread_mutex_lock(&mutex);
            fdIsValid=false;
            pthread_mutex_unlock(&mutex);
            pthread_join(thread,NULL);
        }
    
 void * IONotifier::watchFor( void* arg)
        {
            IONotifier* self=(IONotifier *) arg;
            fd_set rfds, wfds;
            int retval;
                //first time:
            self->againWritableEmited=false;
                //include the actual fd in the sets checked for reading and writing

            while(1){
                pthread_mutex_lock(&(self->mutex));
                if(!self->fdIsValid) break;
                pthread_mutex_unlock(&(self->mutex));
                if(!self->againWritableEmited){
//againWritable has not been emited, so we check both if its readable and writable
                    FD_ZERO(&rfds);FD_ZERO(&wfds);
                    FD_SET(self->fd, &rfds);FD_SET(self->fd, &wfds);
                    retval = select(FD_SETSIZE, &rfds, &wfds, NULL, NULL);
                }else{
//if againWritable has been emited we don't want to emit if it's writable until something changes. Until then, only check if it's readable
                    FD_ZERO(&rfds);FD_ZERO(&wfds);
                    FD_SET(self->fd, &rfds);
                    retval = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
                }
                
                if (retval){
                    
//                    printf("Data is available now.\n");
                    if(FD_ISSET(self->fd, &rfds)){
                            //fd is readable
                        self->readable.emit();
//since this new situation:
                        self->againWritableEmited=false;
                    }
                    if(FD_ISSET(self->fd, &wfds)){
                            //fd is writable
                        self->againWritable.emit();
                        self->againWritableEmited=true;
                    }
                }else{
                    perror("Shouldn't arrive here");
                    
                }
                
            }
//            pthread_exit
        }


    

