/*  Class to act as a cover for Internet addresses.
 *
 *  Copyright (c) 1996 Aleksey Sudakov <zander@cnext.crec.mipt.ru>.
 *
 *  This software is subject to the terms of the MiscKit license
 *  agreement. Refer to the license document included with the
 *  MiscKit distribution for these terms.
 *
 *  Version 1.0 BETA (16 December 1995)
 */

#import "MiscINETAddress.h"
//#import <misckit/MiscINETAddress.h>
#ifdef WIN32
#import <stdlib.h>
#import <stdio.h>
#import <winsock.h>
#define MAXHOSTNAMELEN 256
#else
#import <libc.h>
#import <netdb.h>
#endif WIN32
#import <errno.h>
#import <Foundation/NSCoder.h>
extern int errno;

MiscINETAddress *localNSAddress = nil;

@implementation MiscINETAddress

+ localAddress
{
	if (localNSAddress == nil) {
		char host[MAXHOSTNAMELEN+1];
		gethostname(host, MAXHOSTNAMELEN);
		localNSAddress = [MiscINETAddress addressFromCStringHostname:host];
	}

	return localNSAddress;
}

+ addressFromCStringHostname:(const char *)name
{
	return [[MiscINETAddress alloc] initFromCStringHostname:name];
}

+ addressFromHostname:(NSString *)name
{
	return [[MiscINETAddress alloc] initFromCStringHostname:[name cString]];
}

- init
{
	if (hostname != nil)
		[hostname release];
	address.s_addr = 0;
	hostname = nil;
	return self;
}

- (void)dealloc
{
	if (hostname != nil)
		[hostname release];
	[super dealloc];
}

- initWithCoder:(NSCoder *)coder
{
	[coder decodeValueOfObjCType:"L" at:&(address.s_addr)];
	hostname = [[coder decodeObject] retain];
	return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
	[coder encodeValueOfObjCType:"L" at:&(address.s_addr)];
	[coder encodeObject:hostname];
}

- initFromCStringHostname:(const char *)name
{
	int old_errno = errno;
	struct hostent *hent = gethostbyname((char *)name);

	[self init];
	if (hent == NULL) {
		unsigned long tmp = inet_addr((char *)name);
		if (tmp == -1) {
			errno = EINVAL;
			[self release];
			return nil;
		}
		address.s_addr = tmp;
	// hostname will be set later by sending -hostname msg
	} else
		memcpy(&address, hent->h_addr, hent->h_length);
	hostname = nil;
	errno = old_errno;
	return self;
}

- initTo:(struct in_addr)addr
{
	[self init];
	if (addr.s_addr == -1) {
		errno = EINVAL;
		[self release];
		return nil;
	}
	address = addr;
	// hostname will be set later by sending -hostname msg
	return self;
}

- copy
{
	return [self copyWithZone:[self zone]];
}

- copyWithZone:(NSZone*)zone
{
	MiscINETAddress*	copy = [[[self class] allocWithZone:zone] init];
	// Set instance variables here
	if (hostname != nil)
		copy->hostname = [[[self hostname] copyWithZone:zone] retain];
	// what about address ?
	return copy;
}

- (struct in_addr)address
{
	return address;
}

- (NSString *)hostname
{
	int old_errno = errno;
	if (hostname == nil) {
		struct hostent *hent = gethostbyaddr((char *)&address, sizeof(address), AF_INET);
		if (hent == NULL || hent->h_name == NULL)
			hostname = [[NSString stringWithCString:inet_ntoa(address)] retain];
		else
			hostname = [[NSString stringWithCString:hent->h_name] retain];
	}
	errno = old_errno;
	return hostname;
}

- (NSString *)stringAddress
{
	return [NSString stringWithCString:[self cStringAddress]];
}

- (char *)cStringAddress
{
	return inet_ntoa(address);
}

@end
