#import "Mux.h"
#ifdef MuxInspector

@implementation Mux

/*
 *	Accept changes in the FIFO selector. The This sets the FIFO size
 *	by selecting between 1, 4, 8 or 14 bytes of Threshold.
 */
- enterFIFO : sender
{
    char	buf[20];
    char	name[20];
    IOReturn	ret;
    int		port = [ [sender selectedCell] tag] >> 4;

    FIFOIndex[port] = [ [sender selectedCell] tag] & 0xF;
    sprintf (name, "IOFIFO%u", port);
    ret = [devMaster setIntValues : &FIFOIndex[port]
		     forParameter : name
		     objectNumber : myTag
			    count : 1];
    sprintf (buf, "%u", FIFOIndex[port]);
    sprintf (name, "FIFO %u", port);
    if (ret != IO_R_SUCCESS) {
	NXLogError ("Couldn't set value for %s dynamically", name);
    }
    [ table insertKey : name value : buf];
    return self;
}

/*
 *	Accept changes in the # Port selector
 */
- enterSelection : sender
{
    NXRect ViewSize;

#   if (defined(DEBUG))
	IOLog ("- enterSelection : %x\n", [[sender selectedCell] tag]) ;
#   endif
    portIndex = [ [sender selectedCell] tag];
#   if (defined(DEBUG))
	IOLog ("unsetHexIntFromStringPort: %d\n", portIndex + (muxIndex != 0));
#   endif
    [ self unsetHexIntFromStringPort : portIndex + (muxIndex != 0)
				 key : IO_PORT_RANGES_KEY ];
#   if (defined(DEBUG))
	IOLog ("portIndex > 0\n");
#   endif
    /*
     *	Alter the auxiliary multiplexor window size accordingly
     */
    if (portIndex > 0) {
	if (multiPanel == nil) {
#	    if (defined(DEBUG))
		IOLog ("NXApp loadNibSection\n");
#	    endif
	    if ([NXApp loadNibSection : "Multiplexed.nib"
				owner : self
			    withNames : NO]) {
		portIndex = 0;
		return nil;	/* Load failed */
	    }
	    [ [multiPanel contentView] getFrame : &originalViewSize];
	    [ [muxInspector contentView] getFrame : &ViewSize];
	    [multiPanel moveTopLeftTo : NX_X(&ViewSize)+NX_WIDTH(&ViewSize)
				      : NX_Y(&ViewSize)+NX_HEIGHT(&ViewSize)
				      -NX_HEIGHT(&originalViewSize)];
	}
#	if (defined(DEBUG))
		IOLog ("sizeWindow : %d : %d\n",
		    NX_WIDTH(&originalViewSize),
		    NX_HEIGHT(&originalViewSize)*portIndex/8);
#	endif
	[multiPanel sizeWindow : NX_WIDTH(&originalViewSize)
			       : NX_HEIGHT(&originalViewSize)*portIndex/8];
    } else if (multiPanel != nil) {
	[multiPanel sizeWindow : 0:0];
    }
    if (multiPanel != nil)
	[multiPanel flushWindow];
    portRangeLength = portIndex + 1;
    return self;
}

/*
 *	accept changes in the Size display selector.
 */
- enterSize : sender
{
    int	port = [ [sender selectedCell] tag] >> 2;

    sizeIndex[port] = [ [sender selectedCell] tag] & 0x3;
    [self displaySize : port];
    return self;
}

/*
 *	Accept pushbutton - commands for the Buffer Size selector
 */
- minusBuffer : sender
{
    int	i;
    int	port = [ [sender selectedCell] tag];

#   if (defined(DEBUG))
	IOLog ("minusBuffer sizeIndex[%d] = %d\n", port, sizeIndex[port]) ;
#   endif
    switch (sizeIndex[port]) {
    case 0:
	for (i = 16; i > 0; --i) if (sizeBuffer[port] > (1 << i)) {
		sizeBuffer[port] = 1 << i;
		break;
	}
	[self setBufferSize : port];
	break;
    case 1:
	hiwatBuffer[0] -= (hiwatBuffer[0] - lowatBuffer[0]) / 2;
	[self setBufferHiwat : port];
	break;
    case 2:
	lowatBuffer[0] /= 2;
	[self setBufferLowat : port];
	break;
    }
    [self displaySize : port];
    return self;
}

- plusBuffer : sender
{
    int	i;
    int	port = [ [sender selectedCell] tag];

    switch (sizeIndex[port]) {
    case 0:
	for (i = 0; i < 16; ++i) if (sizeBuffer[port] < (1 << i)) {
		sizeBuffer[port] = 1 << i;
		break;
	}
	[self setBufferSize : port];
	break;
    case 1:
	hiwatBuffer[port] += (sizeBuffer[port] - hiwatBuffer[port]) / 2;
	[self setBufferHiwat : port];
	break;
    case 2:
	lowatBuffer[port] += (hiwatBuffer[port] - lowatBuffer[port]) / 2;
	[self setBufferLowat : port];
	break;
    }
    [self displaySize : port];

    return self;
}

/*
 *	Set the Size directly from the window
 */
- setSize : sender
{   unsigned	i = atoi ([sender stringValue]);
    int	port = [ [sender selectedCell] tag];

    if (i >= 65536)
	i = 65535;
    switch (sizeIndex[port]) {
    case 0:
	if (i <= hiwatBuffer[port]) {
		hiwatBuffer[port] = i - 1;
		[self setBufferHiwat : port];
	}
	if (lowatBuffer[port] <= hiwatBuffer[port]) {
		lowatBuffer[port] = hiwatBuffer[port] - 1;
		[self setBufferLowat : port];
	}
	sizeBuffer[port] = i;
	[self setBufferSize : port];
	break;
    case 1:
	if (i <= lowatBuffer[port])
		i = lowatBuffer[port] + 1;
	if (hiwatBuffer[port] >= sizeBuffer[port]) {
		sizeBuffer[port] = hiwatBuffer[port] + 1;
		[self setBufferSize : port];
	}
	hiwatBuffer[port] = i;
	[self setBufferHiwat : port];
	break;
    case 2:
	if (i >= hiwatBuffer[port])
		i = hiwatBuffer[port] - 1;
	lowatBuffer[port] = i;
	[self setBufferLowat : port];
	break;
    }
    [self displaySize : port];

    return self;
}

- setBufferSize : (int)port
{   char	buf[20];
    char	name[80];
    IOReturn	ret;

    sprintf (name, "IOBufferSize%u", port);
#   if (defined(DEBUG))
	IOLog ("setIntValues : %d forParameter : \"%s\"\n", sizeBuffer[port],
	    name) ;
#   endif
    ret = [devMaster setIntValues : &sizeBuffer[port]
		     forParameter : name
		     objectNumber : myTag
			    count : 1];
    sprintf (name, "Buffer Size %u", port);
    if (ret != IO_R_SUCCESS) {
	NXLogError ("Couldn't set value for %s dynamically", name);
    }
    sprintf (buf, "%u", sizeBuffer[port]);
    return [ table insertKey : name value : buf];
}

- setBufferHiwat : (int)port
{   char	buf[20];
    char	name[80];
    IOReturn	ret;

    sprintf (name, "IOBufferHiwater%u", port);
    ret = [devMaster setIntValues : &hiwatBuffer[port]
		     forParameter : name
		     objectNumber : myTag
			    count : 1];
    sprintf (buf, "%u", hiwatBuffer[port]);
    sprintf (name, "RTS High Water %u", port);
    if (ret != IO_R_SUCCESS) {
	NXLogError ("Couldn't set value for %s dynamically", name);
    }
    return [ table insertKey : name value : buf];
}

- setBufferLowat : (int)port
{   char	buf[20];
    char	name[80];
    IOReturn	ret;

    sprintf (name, "IOBufferLowater%u", port);
    ret = [devMaster setIntValues : &hiwatBuffer[port]
		     forParameter : name
		     objectNumber : myTag
			    count : 1];
    sprintf (buf, "%u", lowatBuffer[port]);
    sprintf (name, "RTS Low Water %u", port);
    if (ret != IO_R_SUCCESS) {
	NXLogError ("Couldn't set value for %s dynamically", name);
    }
    return [ table insertKey : name value : buf];
}

- displaySize : (int)port
{   char buffer[80];

    if (port == portIndex)
	port = 8;
    switch (sizeIndex[port]) {
    case 0:
	sprintf (buffer, "%u", sizeBuffer[port]);
	break;
    case 1:
	sprintf (buffer, "%u", hiwatBuffer[port]);
	break;
    case 2:
	sprintf (buffer, "%u", lowatBuffer[port]);
	break;
    }
    switch (port) {
    case 0:
    	[muxInspector setStringValue : buffer];
	break;
    case 1:
	[port1Size setStringValue : buffer];
	break;
    case 2:
	[port2Size setStringValue : buffer];
	break;
    case 3:
	[port3Size setStringValue : buffer];
	break;
    case 4:
	[port4Size setStringValue : buffer];
	break;
    case 5:
	[port5Size setStringValue : buffer];
	break;
    case 6:
	[port6Size setStringValue : buffer];
	break;
    case 7:
	[port7Size setStringValue : buffer];
	break;
    case 8:
	sprintf (buffer, "%u bytes", muxIndex);
	[port8Size setStringValue : buffer];
    }
    return self;
}

- enterMultiplexorStyle : sender
{
    int	i;

    muxIndex = [ [sender selectedCell] tag];
    if (muxIndex == 0) {
	[ muxAddressSelector setEnabled : 0 ];
	[ muxAddressMinusButton setEnabled : 0 ];
	[ muxAddressPlusButton setEnabled : 0 ];
	[ self unsetHexIntFromStringPort : portIndex key : IO_PORT_RANGES_KEY ];
    }
    else {
	[ muxAddressSelector setEnabled : 1 ];
	[ muxAddressMinusButton setEnabled : 1 ];
	[ muxAddressPlusButton setEnabled : 1 ];
	[ self displaySize : 8 ];
	[ self getHexIntFromStringPort : portIndex
				   key : IO_PORT_RANGES_KEY argument : &i];
	[ self setHexIntFromStringPort : portIndex
				   key : IO_PORT_RANGES_KEY argument : i];
    }
    return self;
}

- minusAddress : sender;
{
    int	i;
    int	port = [ [sender selectedCell] tag];

    if (port == 8)
	port = portIndex + 1;
    [self getHexIntFromStringPort : port key : IO_PORT_RANGES_KEY argument : &i];
    if (port == (portIndex + 1)) {
	i -= muxIndex;
	if (muxIndex == 1)
	    i &= 0x3FF;
	else
	    i &= 0x3FE;
    } else {
	i -= 8;
	i &= 0x3F8;
    }
    [self setHexIntFromStringPort : port key : IO_PORT_RANGES_KEY argument : i];
    [self displayAddress : port];

    return self;
}

- plusAddress : sender;
{
    int	i;
    int	port = [ [sender selectedCell] tag];

    if (port == 8)
	port = portIndex + 1 ;
    [self getHexIntFromStringPort : port key : IO_PORT_RANGES_KEY argument : &i];
    if (port == (portIndex + 1)) {
	i += muxIndex;
	if (muxIndex == 1)
	    i &= 0x3FF;
	else
	    i &= 0x3FE;
    } else {
	i += 8;
	i &= 0x3F8;
    }
    [self setHexIntFromStringPort : port key : IO_PORT_RANGES_KEY argument : i];
    [self displayAddress : port];

    return self;
}

- displayAddress : (int)port
{   int		i;
    char	buffer[32];

    [self getHexIntFromStringPort : port key : IO_PORT_RANGES_KEY argument : &i];
    if (port == portIndex)
	port = 8;
    sprintf (buffer, "0x%x", i);
    switch (port) {
    case 0:
    	[port0Address setStringValue : buffer];
	break;
    case 1:
	[port1Address setStringValue : buffer];
	break;
    case 2:
	[port2Address setStringValue : buffer];
	break;
    case 3:
	[port3Address setStringValue : buffer];
	break;
    case 4:
	[port4Address setStringValue : buffer];
	break;
    case 5:
	[port5Address setStringValue : buffer];
	break;
    case 6:
	[port6Address setStringValue : buffer];
	break;
    case 7:
	[port7Address setStringValue : buffer];
	break;
    case 8:
	[port8Address setStringValue : buffer];
    }
    return self;
}

- (int)getUnsignedIntFromString : (char *)key
		       argument : (unsigned int *)val
{   char const *	cp;

    cp = [ table valueForStringKey : key ];
    if (cp) {
	*val = atoi (cp);
	return (YES);
    }
    return (NO);
}

/*
 *	Read the indexed value from the String in Hex
 */
- (int)getHexIntFromStringPort : (int)port
			   key : (char *)key
		      argument : (unsigned int *)val
{   char const *	cp;
    int			i, c;

    cp = [ table valueForStringKey : key];
    i = 0;
    while ((i < port) && (*cp)) {
	while ((c = *cp) && (c != ' '))
	    ++cp;
	while (*cp == ' ')
	    ++cp;
	++i;
    }
    if ((*cp != '0') && (*++cp != 'x')) {
	*val = 0x110 + (port * 8);
	return (YES);
    }
    i = 0;
    while ((c = *++cp)
     && (((0 <= (c -= '0')) && (c <= 9))
      || ((10 <= (c -= 'A' - '0' - 10)) && (c <= 15))
      || ((10 <= (c -= 'a' - 'A')) && (c <= 15)))) {
	i <<= 16;
	i += c;
    }
    *val = i;
    return (YES);
}

- unsetHexIntFromStringPort : (int)port
			key : (char *)key
{
    char *	cp;
    char *	buf;
    int		c, i;

#   if (defined(DEBUG))
	IOLog ("- unsetHexIntFromStringPort : %d key : \"%s\"\n", port, key) ;
#   endif
    cp = buf = (char *)[ table valueForStringKey : key];
#   if (defined(DEBUG))
	IOLog ("[ table valueForStringKey : \"%s\"] = \"%s\"\n", key, buf);
#   endif
    i = 0;
    while (i < port) {
	if ((cp == NULL) || (*cp == '\0'))
	    break ;
	while ((c = *cp) && (c != ' '))
	    ++cp;
	if (++i < port)
	    break ;
	while (*cp == ' ')
	    ++cp;
    }
    if (cp)
	    *cp = '\0';
#   if (defined(DEBUG))
	IOLog ("table insertKey : \"%s\" value : \"%s\"\n", key, buf) ;
#   endif
    return [ table insertKey : key value : (buf == NULL) ? "" : buf];
}

- setHexIntFromStringPort : (int)port
		      key : (char *)key
		 argument : (int)val
{   char	buffer[BUFSIZ];
    char *	cp;
    char *	tp;
    int		i, c;

    cp = (char *)[ table valueForStringKey : key];
    tp = buffer;
    i = 0;
    while (i < port) {
	if ((c = *cp) == '\0') {
	    sprintf (tp, "0x%x-0x%x ", 0x110 + (8 * i), 0x110 + (8 * i) + 7);
	    tp += strlen (tp);
	} else {
	    while ((c = *tp++ = *cp) && (c != ' '))
		++cp;
	    while (*cp == ' ')
	       ++cp;
	}
	++i;
    }
    sprintf (tp, "0x%x-0x%x ", val, val
	+ ((port == 8) ? (portIndex - 1) : 7));
    tp += strlen (tp);
    while ((c = *cp) && (c != ' '))
	++cp;
    while (*cp == ' ')
	++cp;
    (void)strcpy (tp, cp);
    return [ table insertKey : key value : buffer ];
}

- loadMainNibFile
{
    char	buffer[MAXPATHLEN];
    static NXBundle *	myBundle;

	IOLog ("- loadMainNibFile\n");
    [super loadMainNibFile];
    if (myBundle)
	return self ;
	IOLog ("[NXBundle bundleForClass : [self class]]\n") ;
    myBundle = [NXBundle bundleForClass : [self class]];
	IOLog ("[myBundle getPath ...]\n") ;
    if (![myBundle getPath : buffer
	       forResource : MuxDeviceName
		    ofType : "nib"]) {
	NXLogError ("Couldn't find inspector nib");
	[self free];
	return nil;
    }
	IOLog ("[NXApp loadNibFile \"%s\"...]\n", buffer);
    if (![NXApp loadNibFile : buffer owner : self withNames : NO]) {
	NXLogError ("Couldn't load inspector nib");
	[self free];
	return nil;
    }
	IOLog ("[self setAccessoryView]\n") ;
    [self setAccessoryView: [self inspectionView]];

    return self;
}

- free
{
    [devMaster free];
    return [super free];
}

- setTable : (NXStringTable *)instance
{
    int		i;
    IOReturn	ret;
    IOString	kind;
    char	buf[32];

#   if (defined(DEBUG))
	IOLog ("- setTable\n");
#   endif
    table = instance;

    /*
     *       Set up the IODeviceMaster object to talk to the driver
     */
#   if (defined(DEBUG))
	IOLog ("[IODeviceMaster new]\n") ;
#   endif
    devMaster = [IODeviceMaster new];
    sprintf (buf, "%s%s", MuxDeviceName,
	[ table valueForStringKey : "Instance"]);
    (void)strcpy (kind, MuxDeviceKind) ;
    ret = [devMaster lookUpByDeviceName : buf
			   objectNumber : &myTag
			     deviceKind : &kind];
    if (ret != IO_R_SUCCESS) {
	/*
	 *      We might not be loaded, so just log the error
	 */
	NXLogError("Couldn't find %s device: error %d\n", buf, ret);
    }

    /*
     *	Initialize the various values from the device.
     */
    /* [IODeviceInspector setNumInterrupts : 1
			    numChannels : 0
			portRangeLength : NTTY + 1
		      memoryRangeLength : 0]; */
    for (i = 0; i < NTTY; ++i) {
	/* Set the receive buffer size */
	(void)sprintf (buf, "Buffer Size %u", i);
	if ((([self getUnsignedIntFromString : buf
				    argument : &sizeBuffer[i]] == NO)
	  && ([self getUnsignedIntFromString : "Buffer Size"
				    argument : &sizeBuffer[i]] == NO))
	 || (sizeBuffer[i] > 65535))
		sizeBuffer[i] = DOUBLE_BUFFER;
#	if (defined(DEBUG))
	    IOLog ("sizeBuffer[%d] = %d\n", i, sizeBuffer[i]);
#	endif
	/* Set the RTS Low Water Mark */
	(void)sprintf (buf, "RTS Low Water %u", i);
	if ((([self getUnsignedIntFromString : buf
				    argument : &lowatBuffer[i]] == NO)
	  && ([self getUnsignedIntFromString : "RTS Low Water"
				    argument : &lowatBuffer[i]] == NO))
	 || (lowatBuffer[i] > (sizeBuffer[i] - 2)))
		lowatBuffer[i] = sizeBuffer[i] / 3;
	/* Set the RTS High Water Mark */
	(void)sprintf (buf, "RTS High Water %u", i);
	if ((([self getUnsignedIntFromString : buf
				    argument : &hiwatBuffer[i]] == NO)
	  && ([self getUnsignedIntFromString : "RTS High Water"
				    argument : &hiwatBuffer[i]] == NO))
	 || (hiwatBuffer[i] > (sizeBuffer[i] - 2))
	 || (hiwatBuffer[i] <= lowatBuffer[i]))
		hiwatBuffer[i] = (lowatBuffer[i] + sizeBuffer[i]) / 2;
	/* Set the FIFO Water Mark */
	(void)sprintf (buf, "FIFO %u", i);
	if ((([self getUnsignedIntFromString : buf
				    argument : &FIFOIndex[i]] == NO)
	  && ([self getUnsignedIntFromString : "FIFO"
				    argument : &FIFOIndex[i]] == NO))
	 || ((FIFOIndex[i] != 1) && (FIFOIndex[i] != 4)
	  && (FIFOIndex[i] != 8) && (FIFOIndex[i] != 14))) {
#		if (FIFO_TRIGGER) == (FIFO_TRIGGER_14)
			FIFOIndex[i] = 14;
#		elif (FIFO_TRIGGER) == (FIFO_TRIGGER_8)
			FIFOIndex[i] = 8;
#		elif (FIFO_TRIGGER) == (FIFO_TRIGGER_4)
			FIFOIndex[i] = 4;
#		elif (FIFO_TRIGGER) == (FIFO_TRIGGER_1)
			FIFOIndex[i] = 1;
#		else
			FIFOIndex[i] = 14;
#		endif
	}
    }
    for (i = 0; i < NTTY; ++i) {
	[self displaySize : i];
	[self displayAddress : i];
    }
    [ self displaySize : 8 ];
    [ self displayAddress : 8 ];
    return self;
}

- (View *)inspectionView
{
    return muxInspector;
}

- resourcesChanged : (IOResources *)rsrc
{
    return self;
}

#ifdef STANDALONE
- rangeDidChange : sender
{
    return self;
}

- setNumInterrupts : (int)numInterrupts
       numChannels : (int)numChannels
   portRangeLength : (int)numPorts
 memoryRangeLength : (int)numAddresses
{
    return self;
}

/*
 *	Provide some abilities to create a standalone program model
 */
void main ()
{   NXApp = [Application new];
    [NXApp init];
    if ([NXApp loadNibSection : "Mux.nib"
			owner : NXApp
		    withNames : NO])
	[NXApp run];
    [NXApp free];
    exit (0);
}
#endif
@end
#endif
