// chanbuftest.cc
//
//      Mike O'Donnell
//
//	Combined test for bounded buffers and channels.
//
//	Two threads circulate messages through a bounded buffer in one
//      direction, and a channel in the other direction.
//

#include "system.h"
#include "synch.h"

    struct testCBInp {
        Channel *channelSide;
        BoundedBuffer *bufferSide;
        int iterations;
    };

//----------------------------------------------------------------------
// ThreadA
//
//     Moves items from the channel to the buffer.
//----------------------------------------------------------------------

void
ThreadA(int testCBInpInt) {
    Channel *testChannel      = ((testCBInp *)testCBInpInt)->channelSide;
    BoundedBuffer *testBuffer = ((testCBInp *)testCBInpInt)->bufferSide;
    int iterations            = ((testCBInp *)testCBInpInt)->iterations;

    int i;
    char nextItem;

    for (i = 0; i<iterations; i++) {
        nextItem = testChannel->Receive();
        printf("%c -->\n", nextItem);
        testBuffer->Write(nextItem);
        printf("  --> %c\n", nextItem);
    }
}

//----------------------------------------------------------------------
// ThreadB
//
//     Moves items from the buffer to the channel.
//----------------------------------------------------------------------

void
ThreadB(int testCBInpInt) {
    Channel *testChannel      = ((testCBInp *)testCBInpInt)->channelSide;
    BoundedBuffer *testBuffer = ((testCBInp *)testCBInpInt)->bufferSide;
    int iterations            = ((testCBInp *)testCBInpInt)->iterations;

    int i;
    char nextItem;

    for (i = 0; i<iterations; i++) {
        nextItem = testBuffer->Read();
        printf("  <-- %c\n", nextItem);
        testChannel->Send(nextItem);
        printf("%c <--\n", nextItem);
    }
}

//----------------------------------------------------------------------
// ChannelTest
//----------------------------------------------------------------------

void
ChannelBufferTest() {
    int bufferSize, numberOfItems, iterCB, iterBC, i;

    printf("TESTING CHANNEL-BUFFER CYCLE\n\n");

    printf("Buffer size: "); scanf("%i", &bufferSize);
    printf("Number of items: "); scanf("%i", &numberOfItems);
    printf("Number of channel-to-buffer moves: "); scanf("%i", &iterCB);
    printf("Number of buffer-to-channel moves: "); scanf("%i", &iterBC);

    Channel *testChannel = new Channel("testChannel");
    BoundedBuffer *testBuffer = new BoundedBuffer("testBuffer", bufferSize);
    testCBInp *testInpA = new testCBInp;
    testInpA->channelSide = testChannel;
    testInpA->bufferSide = testBuffer;
    testInpA->iterations = iterBC;
    testCBInp *testInpB = new testCBInp;
    testInpB->channelSide = testChannel;
    testInpB->bufferSide = testBuffer;
    testInpB->iterations = iterCB;

    DEBUG('t', "Entering Channel Test\n");

    // Create and fork threads to transfer between buffer and channel

    Thread *tA = new Thread("thread A");
    Thread *tB = new Thread("thread B");

    tA->Fork(ThreadA, (int)testInpA);
    tB->Fork(ThreadB, (int)testInpB);

    // Write initial items to the buffer

    for (i = 0; i<numberOfItems; i++) {
       testBuffer->Write((char)(((int) 'a') + i));
    }

}
