static char rcsid[] = "$Id: Counter.m,v 1.1 1997/04/02 18:28:27 croehrig Exp $";
/*
 *  Counter:  simple counter object that runs in its own thread.
 */
#import <libc.h>
#import <math.h>
#import <appkit/Button.h>
#import <appkit/Slider.h>
#import "Counter.h"
#import "ThreadedApp.h"
#import "tprintf.h"

#define INITIAL_INTERVAL	500	// in milliseconds

@interface Counter(CounterPrivate)
- (void)counter:sender;
- (int)incCount;
@end

@implementation Counter : Object

// number of counters created
static int counters;

#define STOPPED 0
#define RUNNING 1

#define myrandom()	(random()/(double)MAXINT)
+ initialize
{
    if( self == [Counter class] ){
	srandom(0);
	counters = 1;
    }
    tprintf_init();
    return self;
}


- init
{
    NXScreen *screen;
    NXRect frame;


    [super init];
    interval = INITIAL_INTERVAL;
    running = NO;
    mynum = counters++;

    count = 0;
    if( [NXApp loadNibSection:"Counter.nib" owner:self] ){
	// set window title...
	title = (char *) malloc( 20*sizeof(char) );  // should be enough...
	sprintf( title, "Counter %d\n", mynum );
	[window setTitle:title];

	// move to random location
	[window getFrame:&frame andScreen:&screen];
	frame.size.width = screen->screenBounds.size.width 
			  - frame.size.width;
	frame.size.height = screen->screenBounds.size.height
			  - frame.size.height;
	frame.origin = screen->screenBounds.origin;
	frame.origin.x += myrandom()*frame.size.width;
	frame.origin.y += myrandom()*frame.size.height;
	[window moveTo:frame.origin.x:frame.origin.y];
	[window makeKeyAndOrderFront:self];

	// set values
	[slider setIntValue:interval];
	[intervalField setIntValue:interval];
	[countField setIntValue:count];

	runlock = [[CJRConditionLock alloc] initWithCondition:STOPPED];
	// go!
	[self start:self];
    }
    return self;
}

- free
{
    if( running )
	[self stop:self];
    
    [runlock free];
    if(title){
	free(title);
    }
    return [super free];
}


- windowWillClose:sender
{
    [self stop:self];
    [NXApp delayedFree:self];

    return self;
}


// "private" methods

- dispCount:(int)i
{
    [countField setIntValue:i];
    return self;
}


- (int)incCount
{
    count++;
    return count;
}

    
- (void)counter:sender
{

    [runlock lockWhenCondition:RUNNING];
    while( running ){

	// update countField under main thread
	[NXApp callbackTarget:countField perform:@selector(setIntValue:) 
	    with:(id)count];

	// use a callback to make absolutely sure a 'reset' isn't lost
	[NXApp callbackAndWaitTarget:self perform:@selector(incCount)];


	if( interval > 0 )
	    [NXApp sleepCurrentThread:interval];
    }

    [runlock unlockWithCondition:STOPPED];
}


// Actions...

- start:sender
{
    if( !running ){
	[runlock lock];
	[NXApp detachNewThreadSelector:@selector(counter:) toTarget:self
	    withObject:self];
	running = YES;
	[runlock unlockWithCondition:RUNNING];
    }
    return self;
}


- stop:sender
{
    if( running ){
	running = NO;
	// wait for thread to finish
	[runlock lockWhenCondition:STOPPED];
	[runlock unlock];
    }

    return self;
}

- startOrStop:sender
{
    if( [sender state] == 0 ){
	[self start:sender];
    } else {
	[self stop:sender];
    }
    return self;
}


- reset:sender
{
    count = 0;
    return self;
}


- setInterval:sender
{
    int i, max;

    i = [sender intValue];
    max = (int) [slider maxValue];
    if( i < 0 ){
	i = 0;
    } else if( i > max ){
	i = max;
    }
    [slider setIntValue:i];
    [intervalField setIntValue:i];

    interval = i;

    return self;
}

@end
