package java.net;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/*
 * Java core library component.
 *
 * Copyright (c) 1997, 1998
 *      Transvirtual Technologies, Inc.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file.
 */
class PlainSocketImpl
  extends SocketImpl
{
static {
	System.loadLibrary("net");
}

protected synchronized void accept(SocketImpl s) throws IOException {
	socketAccept(s);
}

protected synchronized int available() throws IOException {
	return socketAvailable();
}

protected synchronized void bind(InetAddress address, int lport) throws IOException {
	this.address=address;
	this.localport=lport;
	socketBind(address, lport);
}

protected synchronized void close() throws IOException {
	socketClose();
}

protected void connect(InetAddress address, int port) throws IOException {
	this.address=address;
	this.port=port;
	socketConnect(address, port);
}

protected void connect(String host, int port) throws IOException {
	connect(InetAddress.getByName(host), port);
}

protected synchronized void create(boolean stream) throws IOException {
	fd=new FileDescriptor();
	address=new InetAddress();
	socketCreate(stream);
}

protected synchronized void finalize() throws IOException {
	close();
}

protected synchronized InputStream getInputStream() throws IOException {
	return new SocketInputStream(this); 
}

protected synchronized OutputStream getOutputStream() throws IOException {
	return new SocketOutputStream(this);
}

protected synchronized void listen(int count) throws IOException {
	socketListen(count);
}

public void setOption(int option, Object data) throws SocketException {
	final boolean disable = (data instanceof Boolean) && !((Boolean) data).booleanValue();
	if (disable) {
		data = new Integer(0);			// the common case
	}
	switch (option) {
		case SO_SNDBUF:
		case SO_RCVBUF:
		case SO_LINGER:
		case SO_REUSEADDR:
			break;
		case TCP_NODELAY:
			data = new Integer(disable ? 0 : 1);
			break;
		case SO_TIMEOUT:
			/* XXX what to do here? */
			throw new SocketException("Unimplemented socket option");
		case SO_BINDADDR:
			throw new SocketException("Read-only socket option");
		case IP_MULTICAST_IF:
		default:
			throw new SocketException("Unknown socket option");
	}
	socketSetOption(option, data);
}

public Object getOption(int option) throws SocketException {
	switch (option) {
		case SO_SNDBUF:
		case SO_RCVBUF:
		case SO_LINGER:
		case SO_REUSEADDR:
			return new Integer(socketGetOption(option));
		case TCP_NODELAY:
			return new Boolean(socketGetOption(option) != 0);
		case SO_TIMEOUT:
			/* XXX what to do here? */
			throw new SocketException("Unimplemented socket option");
		case SO_BINDADDR:
			int val = socketGetOption(option);
			try {
				return InetAddress.getByName(
				    ((int) ((val >> 24) & 0xff)) + "." +
				    ((int) ((val >> 16) & 0xff)) + "." +
				    ((int) ((val >>  8) & 0xff)) + "." +
				    ((int) ((val      ) & 0xff)) );
			} catch (UnknownHostException e) {
				throw new Error("impossible result");
			}
		case IP_MULTICAST_IF:
		default:
			throw new SocketException("Unknown socket option");
	}
}

public native void socketSetOption(int option, Object data) throws SocketException;

public native int socketGetOption(int option) throws SocketException;

native private void socketAccept(SocketImpl sock);

native private int  socketAvailable();

native private void socketBind(InetAddress addr, int port);

native private void socketClose();

native private void socketConnect(InetAddress addr, int port);

/* Inherits:-
  private FileDescriptor fd;
  private InetAddress address;
  private int localport;
  private int port */
native private void socketCreate(boolean stream);

native private void socketListen(int count);
}
