/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#ifndef __IWEAR_CONNECTION_H
#define __IWEAR_CONNECTION_H

#ifndef __IWEAR_IWEAR_H
#include <iwear/iwear.h>
#endif

#include <iwear/iwmutex.h>
#include <iwear/threadlocker.h>

extern "C"
{
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
}

#include <string>

namespace iwear
{
    namespace net
    {

#define DEFAULT_TIMEOUT 5.5 /* Default Timeout for everything */

/**
 * @warning This class and all of its descendants are never thread safe. If you
 * want to be able to use it over multiple threads, ensure proper locking
 * yourself or copy buffers/buffer pointers around.
 */
class Connection 
{
private:   
    // Dont allow Connection s to be copied or assigned
    Connection( const Connection& ) { }
    Connection& operator=( const Connection& ) { return *this; }
protected:
    Mutex ReadMutex;
    Mutex WriteMutex;
    void* user_data;
    static inline int get_errno( void ) { return errno; }
public:
    void* get_user_data( void ) { return user_data; }
    const void* get_user_data( void ) const { return user_data; }

    void set_user_data( void* ud ) { user_data = ud; }
    Connection( ) { }
    virtual ~Connection() { }
    /**
     * @param check is true per default. 
     * It indicates if the read ability on this connection should be checked
     * with the timeout. E.g. on a socketconnection, if this parameter is true,
     * it will do a select() on the filedescriptor, if false it wont. This is
     * usefull if a set of fds is beeing checked in one select() call and then
     * all of them should be read. Since in this case a subsequent select() is
     * invalid and would cause the connection to block forever.
     * The detailed implementation of this will of course change for different
     * connection types.
     * @note This function might throw different exceptions, especially on
     * packet based connection it will most likely throw exceptions if the full
     * packet wont fit into the buffer.
     */
    virtual ssize_t read( void * buf, size_t count, float to = DEFAULT_TIMEOUT, bool check = true ) = 0;

    /**
     * This Functions reads a std::string from the stream. It will have a
     * maximum length as specified by count, but might be shorter, in case of a
     * \\0 within the stream (The rest of the data will be discarded then !!)
     * @note This functions is slow by its nature, since it first needs to copy
     * a c-string buffer internally into a string, and when it returns the
     * string it will copy it again.
     * @warning Dont use this function on connections where you expect binary data
     */
    virtual string read( size_t count, float to = DEFAULT_TIMEOUT, bool check = true) = 0;

    /**
     * @note From select_tut(2): <br>
     * 5. The  functions  read(),  recv(), write(), and send() do not
     * necessarily read/write the full amount of data that you have requested.
     * If they do read/write the full amount, its because you have a  low
     * traffic  load and  a  fast  stream. This is not always going to be the
     * case. You should cope with the case of your functions only managing to
     * send or receive a single byte.<p>
     * This might be very important in case of slow/high latency serial/IR
     * links, so keep it always in mind when trying to send and receive data.
     */
    virtual ssize_t write( const void * buf , size_t count, float to = DEFAULT_TIMEOUT, bool check = true ) = 0;

    /**
     * This tries to write the whole string beginning at position pos. This is
     * to be able to conveniently write the rest of a string that does not have
     * been written completely.
     */
    virtual ssize_t write( const string& dat, string::size_type pos = 0, float to = DEFAULT_TIMEOUT, bool check = true ) = 0;

    /**
     * This terminates the connection
     */
    virtual void disconnect( void ) = 0;

    /**
     * In case a disconnection was detected, this should reconnect the
     * connection. It might throw an error if the reconnect wasnt possible.
     */
    virtual void reconnect( float to = DEFAULT_TIMEOUT ) = 0;

    /**
     * In case we want to accept connections on this connection we call this.
     * @note This will need connection specific setup before you can call this.
     */
    virtual Connection* accept( float to = DEFAULT_TIMEOUT, bool checkfd = true ) = 0;

    virtual bool is_connected( void ) = 0;
};

} // namespace net
} // namespace iwear
#endif
