/******************************************************************************
 *
 * Copyright (c) 1999	TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *	SocketStream.cpp
 *
 *****************************************************************************/

// SOL++2000

#include <sol\SocketStream.h>

#include <sol\InvalidSocketException.h>
    
SocketStream::SocketStream()
    :Socket(),
	startPos(0),
	contentSize(0)
{

}


SocketStream::SocketStream(int domain, int protocol) 
    :Socket(domain, SOCK_STREAM, protocol),
	startPos(0),
	contentSize(0)
{
}


SocketStream::~SocketStream() 
{
}


SocketStream* SocketStream::accept(sockaddr* addr, int* size)
{
	BOOL rc = FALSE;
    SOCKET fd = getFD();
	SocketStream* soc = NULL;
    if(fd != INVALID_SOCKET) {
        SOCKET newfd = ::accept(fd, addr, size);
        if(newfd != INVALID_SOCKET) {
			soc = new SocketStream();
            soc -> setFD(newfd);	
        }
    }

	if(soc == NULL) {
		throw InvalidSocketException("Failed to accept a socket");	
	}

	return soc;
}


SocketStream* SocketStream::accept(InetAddress& address) 
{
	BOOL rc = FALSE;
    SOCKET fd = getFD();
	SocketStream* soc = NULL;
    if(fd != INVALID_SOCKET) {
		sockaddr_in* addr = address.getAddress();
		int size  = address.getSize();
        SOCKET newfd = ::accept(fd, (sockaddr*)addr, &size);
        if(newfd != INVALID_SOCKET) {
			soc = new SocketStream();
            soc -> setFD(newfd);	
        }
    }

	if(soc == NULL) {
		throw InvalidSocketException("Failed to accept a socket");	
	}

	return soc;
}


SocketStream* SocketStream::accept(int port, unsigned long address) 
{
	BOOL   rc = FALSE;
	SOCKET fd = getFD();
    int domain = getDomain();
	SocketStream* soc = NULL;
    if(fd != INVALID_SOCKET && domain == AF_INET) {
		sockaddr_in client;
        memset(&client, 0, sizeof(client));
        client.sin_family = domain;
        client.sin_port = htons(port);
        client.sin_addr.s_addr = htonl(address);
        int size = sizeof(client);
        SOCKET newfd = ::accept(fd, (sockaddr*)&client, &size);
        if(newfd != INVALID_SOCKET) {
			soc = new SocketStream();
            soc -> setFD(newfd);
        }
    }

	if(soc == NULL) {
		throw InvalidSocketException("Failed to accept a socket");	
	}
	return soc;
}



SOCKET SocketStream::create(int domain, int protocol) 
{
    return Socket::create(domain, SOCK_STREAM, protocol);
}


int SocketStream::connect(int port, hostent* hostEntry) 
{
	int rc    = Error;
	SOCKET fd = getFD();
	int domain = getDomain();
	if(fd != INVALID_SOCKET && domain == AF_INET) {
	   	sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = domain;
        server.sin_port   = htons(port);
        memcpy((char*)&server.sin_addr, 
                hostEntry->h_addr, hostEntry->h_length);
        rc = ::connect(fd, (sockaddr*)&server, sizeof(server));
    }
	return rc;
}


int SocketStream::connect(int port, unsigned long address) 
{
    SOCKET fd  = getFD();
    int domain = getDomain();

    if(fd != INVALID_SOCKET && domain == AF_INET) {
		sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = domain;
        server.sin_port   = htons(port);
        server.sin_addr.s_addr = htonl(address);
        return ::connect(fd, (sockaddr*)&server, sizeof(server));
     }
     else {
        return Error;
    }
}


int SocketStream::connect(sockaddr* addr, size_t size)
{
    SOCKET fd  = getFD();
    int domain = getDomain();
    if(fd != INVALID_SOCKET && domain == AF_INET) {
        return ::connect(fd, addr, size);
     }
     else {
        return Error;
    }
}


// 1999.07.03
int SocketStream::connect(InetAddress& addr)
{
    SOCKET fd  = getFD();
    int domain = getDomain();
    if(fd != INVALID_SOCKET && domain == AF_INET) {
        return ::connect(fd, (sockaddr*)addr.getAddress(), addr.getSize());
     }
     else {
        return Error;
    }
}


int SocketStream::readLine(StringBuffer& buffer)
{
	Boolean crFound = False;
	char ch[1];
	int len = 0;

	while ((len = recv(ch, 1, 0)) > 0) {
		buffer.append(ch[0]);
		if (ch[0] == 0xd) {
			crFound = True;
			continue;
		}

		if (crFound && ch[0]== 0xa) {
			break;
		}
	}
	return buffer.getContentSize();
}



int SocketStream::getLine(StringBuffer& buffer)
{
	Boolean found = False;
	for(int i = startPos; i<contentSize; i++) {
		if (line[i] == 0xd || line[i] == 0xa) {
			startPos = i+1;
			found = True;
		}
		else {
			buffer.append(line[i]);
		}
	}

	if (found) {
		return buffer.getContentSize();
	}

	while (1) {
		startPos = 0;
		contentSize = recv(line, 1024, 0);
		if (contentSize <=0) {
			// Reached to end of data.
			return  -1;
		}
		for(int i = startPos; i<contentSize; i++) {
			if (line[i] == 0xd || line[i] == 0xa) {
				startPos = i+1;
				found = True;
				break;
			} else {
				buffer.append(line[i]);
			}
		}

		if (found) {
			break;
		}
	}

	return buffer.getContentSize();
}


