/*  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.
==================================================================
*/ 
#include "TCPSender.hxx"
#include "PeriodicAction.hxx"
#include "socket_functions.h"
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <errno.h> 
#include <stdio.h>

TCPSender::TCPSender (char * servName_, unsigned int servPort_ )
        :retryingTime(3000000),tryingConnect(retryingTime),servPort(servPort_),comMode(false),newReceived(false)//,servName(servName_)
{
    strcpy(servName,servName_);
        //prepare the name
    init_sockaddr (&server, servName_, servPort);
        //this->Reset;

    
}
TCPSender::~TCPSender(){
    if(comMode){
        CloseConnection();
    }
}
    
void TCPSender::CloseConnection(){
    if (comMode){
#ifdef DEBUG
        cout<<"TCPSender: closing socket to server "<<servName<<":"<<servPort<<"\n";
#endif
        close(socketItself);
        comMode=false;
    }
}
void TCPSender::Reset() {
    if (comMode){
        CloseConnection();
    }
        //Tryingconnect PeriodicAction object DO this->isTrialToConnectSuccesful periodically WHILE this call is NOT returning true, that is is retrying until connection is succesfull. All the threading is done inside PeriodicAction!
    tryingConnect.DoWhileNot(slot(this, &TCPSender::isTrialToConnectSuccesful) );
    
// //       tryingConnect.FinallyDo(... callback to call when tryingConnect is finished, for example Start reporting periodically (start another PeriodicAction
//   //     supose we have a virtual method WhenConnectionIsEstablished
//       tryingConnect.FinallyDo(slot(this,&TCPSender::WhenConnectionIsEstablished));
    tryingConnect.Start();
        
}

int TCPSender::IODescriptor(){ //returns file descriptor (e.g. to use with IONotifier)
    return socketItself;
        
}

bool TCPSender::isTrialToConnectSuccesful(){
        //create the socketItself. After a failed connect call the socket has to be initialized again (?)
    socketItself = socket (PF_INET, SOCK_STREAM, 0);
    if ( (socketItself < 0) || (prepare_socket(socketItself) == -1) ) {
        perror("TCPSender: socket (client)");
        exit (EXIT_FAILURE);
    }
#ifdef DEBUG
    printf("TCPSender: trying to connect\n");
#endif  
    if (0 > connect (socketItself,
                     (struct sockaddr *) &server,
                     sizeof (server))){
        int myerrno=errno;
        perror("TCPSender: connect. Retrying");
        comMode=false;
        close(socketItself);
        
        return false;
        
    }else{
        comMode=true;
//            fconfigure $socketItself -buffering line
#ifdef DEBUG
        printf("TCPSender: TCPSender: successful connection\n");
#endif
        return true;
    }
}


void TCPSender::Send (char *msg ){ //Syncronous send
    char buffer[MAXMSG];
    
    strcpy(buffer,msg);
    unsigned int len=strlen(buffer);
    buffer[len]='\n';
    buffer[len+1]='\0';
#ifdef DEBUG
    printf("TCPSender: sending %s \n",buffer);
#endif

    if(write(socketItself, buffer, strlen(buffer)) != strlen(buffer)){
        int myerrno=errno;
    }
//      char * eol="\n";
//      if(write(socketItself, eol, strlen(eol)) != strlen(eol)){
//          int myerrno=errno;
//      }
//          //    fsync(readoutSend);
}


void TCPSender::Receive () { //Syncronous receive. If you are not sure there will be data to read, schedule this receive with IONotifier or something. Otherwise it will block
#ifdef DEBUG
    printf("TCPSender: Receive from TCPSender %d\n", this);
#endif
    int nbytes;
    nbytes = read (socketItself, receivedStream, MAXMSG);
    if (nbytes < 0){
            /* Read error. */
        perror("TCPSender: read");
//       this->CloseConnection();
       exit (EXIT_FAILURE);
    }else if (nbytes == 0){
        
            /* End-of-file. */
        receivedStream[0]='0';
        receivedStream[1]='\0';
        this->CloseConnection();
    }else{
   /* Data read. */
            //look for '\n' and chomp, in anycase read doesn't supply the \n so add it
        if(receivedStream[nbytes-1]=='\n'){
            receivedStream[nbytes-1]='\0';
#ifdef DEBUG        
//            printf("TCPSender: %c%c%c chomp\n", receivedStream[nbytes-3],receivedStream[nbytes-2],receivedStream[nbytes-1]);
            
#endif
        }else{
            receivedStream[nbytes]='\0';
        }
#ifdef DEBUG        
        printf("TCPSender: got message: `%s'\n", receivedStream);
#endif
        this->process();
        newReceived=true;
    }
}

string TCPSender::ReturnNew () {
    if (newReceived) {
        newReceived=false;
        return string(receivedStream);
    }else{
        return string("0");
    }
}

//this public method should be capitalized for some consistency. Put the change should be propagated. class Make up!
void TCPSender::process (){
//to be overriden
#ifdef DEBUG
    printf("TCPSender: message Received [%s] and processed from server %s:%d \n",receivedStream,servName,servPort);
#endif
}



