protected void Transmit(Frame token)
    {
        // Send until THT reached
        // first send the token ack
        Frame sendFrame;
        Frame recieveFrame;
        byte[] bFrame;
        String[] splitInput;
        int dataSize;
        this.THT = 1040;
        Frame newToken;

        // send ack for token
        sendFrame = new Frame(0, token.SA, this.nodeNum, null);
        sendFrame.FS = 2;
        bFrame = sendFrame.ToBinary();
        sendStream.Write(bFrame, 0, bFrame.Length);

        // read from file, and build frame from it
        while (true)
        {
            // tokenize the input line
            splitInput = this.inputFile[index].Split(new char[] { ',' });
            dataSize = Convert.ToByte(splitInput[1]); // the size of data is always in the second array element
            if (dataSize > 254)
            {
                Console.WriteLine("LOL BAD STUFF");
            }

            if (this.THT < dataSize)
            {
                // not enough THT to send the frame, send a token
                newToken = new Token(0, 0, this.nodeNum);
                bFrame = newToken.ToBinary();

                sendStream.Write(bFrame, 0, bFrame.Length);
                recieveFrame = Frame.MakeFrame(Receive());
                Debug.Assert(recieveFrame.DA == this.nodeNum);
                Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);

                return;
            }

            // otherwise, build and send the frame
            sendFrame = new Frame(0, Convert.ToByte(splitInput[0]), this.nodeNum, new System.Text.UTF8Encoding().GetBytes(splitInput[2]));
            bFrame = sendFrame.ToBinary();
            sendStream.Write(bFrame, 0, bFrame.Length);
            THT -= sendFrame.size;

            // recieve ack
            while (true)
            {
                recieveFrame = Frame.MakeFrame(Receive());
                Debug.Assert(recieveFrame.SA == this.nodeNum);
                Debug.Assert(recieveFrame.DA == sendFrame.DA);
                Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);

                // frame wasn't accepted, resend
                if (recieveFrame.FS == 3)
                {
                    // is there enough THT to resend?
                    if (this.THT > sendFrame.size)
                    {
                        // send it!
                        sendStream.Write(bFrame, 0, bFrame.Length);
                        THT -= sendFrame.size;
                        continue;
                    }
                    else
                    {
                        // send the token along
                        newToken = new Token(0, 0, this.nodeNum);
                        bFrame = newToken.ToBinary();

                        sendStream.Write(bFrame, 0, bFrame.Length);
                        recieveFrame = Frame.MakeFrame(Receive());
                        Debug.Assert(recieveFrame.DA == this.nodeNum);
                        Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);
                        return;
                    }
                }
                else
                {
                    // frame was successfully recieved, move onto the next one
                    this.index++;
                    if (this.index >= this.inputFile.Length)
                    {
                        // nothing more to send
                        newToken = new Token(0, 0, this.nodeNum);
                        bFrame = newToken.ToBinary();

                        sendStream.Write(bFrame, 0, bFrame.Length);
                        recieveFrame = Frame.MakeFrame(Receive());
                        Debug.Assert(recieveFrame.DA == this.nodeNum);
                        Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);
                        return;
                    }
                    break;
                }
            }
        }
    }
    protected void Transmit(Frame token)
    {
        // Send until THT reached
        // first send the token ack
        Frame sendFrame;
        Frame recieveFrame;
        byte[] bFrame;
        int dataSize;
        this.THT = 1040;
        Frame newToken;
        Queue<Frame> sendQueue;
        Object locker;

        // send ack for token
        sendFrame = new Frame(0, token.SA, this.nodeNum, null);
        sendFrame.FS = 2;
        bFrame = sendFrame.ToBinary();
        sendStream.Write(bFrame, 0, bFrame.Length);

        // setup which buffer to send from
        if (bridgeNumber == 1)
        {
            lock (buf1Locker)
            {
                sendQueue = buffer1;
                locker = buf1Locker;
            }
        }
        else
        {
            lock (buf2Locker)
            {
                sendQueue = buffer2;
                locker = buf1Locker;
            }
        }

        // read from buffer and send it
        while (true)
        {
            // get the next frame to send and its size
            lock (locker)
            {
                sendFrame = sendQueue.Peek();
            }
            dataSize = sendFrame.size;

            if (this.THT < dataSize)
            {
                // not enough THT to send the frame, send a token
                newToken = new Token(0, 0, this.nodeNum);
                bFrame = newToken.ToBinary();

                sendStream.Write(bFrame, 0, bFrame.Length);
                recieveFrame = Frame.MakeFrame(Receive());
                //Debug.Assert(recieveFrame.DA == this.nodeNum);
                Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);

                return;
            }

            // otherwise, send the frame
            bFrame = sendFrame.ToBinary();
            sendStream.Write(bFrame, 0, bFrame.Length);
            THT -= sendFrame.size;

            // recieve ack
            while (true)
            {
                recieveFrame = Frame.MakeFrame(Receive());
                //Debug.Assert(recieveFrame.SA == this.nodeNum);
                //Debug.Assert(recieveFrame.DA == sendFrame.DA);
                //Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);

                // if it needs to be setup into the routing table
                if (recieveFrame.AC == 4)
                {
                    // if the frame recieved doesn't have the FS changed, nothing processed it
                    if (recieveFrame.FS == 0)
                    {
                        lock (locker)
                        {
                            sendQueue.Dequeue();
                            if (sendQueue.Count == 0)
                            {
                                // nothing more to send
                                newToken = new Token(0, 0, this.nodeNum);
                                bFrame = newToken.ToBinary();

                                sendStream.Write(bFrame, 0, bFrame.Length);
                                recieveFrame = Frame.MakeFrame(Receive());
                                //Debug.Assert(recieveFrame.DA == this.nodeNum);
                                Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);
                                return;
                            }
                        }
                        break;
                    }
                    // otherwise, add it to the routing table
                    else
                    {
                        lock (lookupTableLocker)
                        {
                            if (!lookupTable.Contains(sendFrame.DA))
                            {
                                lookupTable.Add(sendFrame.DA, bridgeNumber);
                                lock (logLocker)
                                {
                                    logFile.WriteLine(DateTime.Now.ToString() + " " + sendFrame.DA + " added to the routting table");
                                }
                            }
                        }

                        // make sure that if it needs to be resent, it doesn't get added again
                        sendFrame.AC = 0;
                        break;
                    }
                }

                // frame wasn't accepted, resend
                else if (recieveFrame.FS == 3)
                {
                    // is there enough THT to resend?
                    if (this.THT > sendFrame.size)
                    {
                        lock (logLocker)
                        {
                            //logFile.WriteLine(DateTime.Now.ToString() + " resending frame to " + sendFrame.DA + " from " + sendFrame.SA);
                        }
                        // send it!
                        sendStream.Write(bFrame, 0, bFrame.Length);
                        THT -= sendFrame.size;
                        continue;
                    }
                    else
                    {
                        // send the token along
                        newToken = new Token(0, 0, this.nodeNum);
                        bFrame = newToken.ToBinary();

                        sendStream.Write(bFrame, 0, bFrame.Length);
                        recieveFrame = Frame.MakeFrame(Receive());
                        //Debug.Assert(recieveFrame.DA == this.nodeNum);
                        Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);
                        return;
                    }
                }
                else
                {
                    // frame was successfully recieved, move onto the next one
                    lock (locker)
                    {
                        sendQueue.Dequeue();
                        if (sendQueue.Count == 0)
                        {
                            // nothing more to send
                            newToken = new Token(0, 0, this.nodeNum);
                            bFrame = newToken.ToBinary();

                            sendStream.Write(bFrame, 0, bFrame.Length);
                            recieveFrame = Frame.MakeFrame(Receive());
                            //Debug.Assert(recieveFrame.DA == this.nodeNum);
                            Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);
                            return;
                        }
                    }
                    break;
                }
            }
        }
    }
    // monitors run, since it will only accept a token
    public override void Run()
    {
        // connect with neighboring nodes
        this.Connect();

        // Accept incoming connection and wait for
        // right neighbor to be ready.

        // create the first token
        Frame sendFrame = new Token(0, 0, 0);
        byte[] bFrame = sendFrame.ToBinary();
        Frame recieveFrame;
        Frame newToken;
        Frame frame;

        // send it!
        sendStream.Write(bFrame, 0, bFrame.Length);
        recieveFrame = Frame.MakeFrame(Receive());
        Debug.Assert(recieveFrame.DA == this.nodeNum);
        Debug.Assert(recieveFrame.FS == 2 || recieveFrame.FS == 3);

        try
        {
            while (true)
            {
                // listen state
                // recieve frame, check if token

                frame = Frame.MakeFrame(Receive());

                if (frame is Token)
                {
                    // if it was sent by the monitor, everyone is done sending
                    if (frame.SA == this.nodeNum)
                    {
                        // send a frame with the finished bit enabled
                        sendFrame = new Frame(2, 255, 0, null);
                        bFrame = sendFrame.ToBinary();
                        sendStream.Write(bFrame, 0, bFrame.Length);
                    }
                    // if the token wasn't sent by the monitor, must send ack
                    else
                    {
                        sendFrame = new Frame(0, frame.SA, this.nodeNum, null);
                        sendFrame.FS = 2;
                        bFrame = sendFrame.ToBinary();
                        sendStream.Write(bFrame, 0, bFrame.Length);
                    }

                    // otherwise send a new token if the SA is not the monitor
                    newToken = new Token(0, this.nodeNum, this.nodeNum);

                    bFrame = newToken.ToBinary();
                    sendStream.Write(bFrame, 0, bFrame.Length);
                    frame = Frame.MakeFrame(Receive());

                    if (frame.SA == this.nodeNum)
                    {
                        // send a frame with the kill bit enabled
                        sendFrame = new Frame(2, lastNode, 0, null);
                        bFrame = sendFrame.ToBinary();
                        sendStream.Write(bFrame, 0, bFrame.Length);
                    }
                    else
                    {
                        Debug.Assert(frame.DA == this.nodeNum);
                        Debug.Assert(frame.FS == 2 || frame.FS == 3);
                    }
                }
                // otherwise, check if the bridge is telling it to shutdown
                else if (frame.AC == 1)
                {
                    Console.WriteLine("Exterminate list");
                    // send a frame with the kill bit enabled
                    sendFrame = new Frame(1, lastNode, 0, null);
                    bFrame = sendFrame.ToBinary();
                    sendStream.Write(bFrame, 0, bFrame.Length);
                    break;
                }
                else
                {
                    bFrame = frame.ToBinary();
                    sendStream.Write(bFrame, 0, bFrame.Length);
                }
            }
        }
        finally
        {
            // Close all open resources (i.e. sockets!)
            Console.WriteLine("Monitor node EX-TERM-INATED!");
            this.recieveStream.Close();
            this.recieveClient.Close();
        }
    }
    // what runs on startup of node
    public virtual void Run()
    {
        int destRing = -1;
        bool shouldTransmit = false;
        bool shutdown;

        // connect with neighboring nodes
        this.Connect();
        Console.WriteLine(this.nodeNum + "Connected");
        lock (logLocker)
        {
            logFile.WriteLine(DateTime.Now.ToString() + " Connected with token ring " + this.bridgeNumber);
        }

        Random rand = new Random();

        byte[] bFrame;

        // Accept incoming connection and wait for
        // right neighbor to be ready.
        try
        {
            while (true)
            {
                // listen state
                // recieve frame, check if token
                Frame frame = Frame.MakeFrame(Receive());

                if (frame is Token)
                {
                    // check to see if the thread's buffer has something to transmit
                    if (bridgeNumber == 1)
                    {
                        lock (buf1Locker)
                        {
                            if (buffer1.Count != 0)
                                shouldTransmit = true;
                            else
                                shouldTransmit = false;
                        }
                    }
                    else
                    {
                        lock (buf2Locker)
                        {
                            if (buffer2.Count != 0)
                                shouldTransmit = true;
                            else
                                shouldTransmit = false;
                        }
                    }

                    // if it does, enter transmit state
                    if (shouldTransmit)
                    {
                        Transmit(frame);
                    }

                    else
                    {
                        // otherwise, send the token along
                        bFrame = frame.ToBinary();
                        this.sendStream.Write(bFrame, 0, bFrame.Length);
                    }
                }

                // shutdown signal.
                else if (frame.AC == 2 || frame.DA == 255)
                {
                    Console.WriteLine(this.bridgeNumber + " is ready to shutdown");
                    lock (logLocker)
                    {
                        logFile.WriteLine(DateTime.Now.ToString() + " Token ring " + this.bridgeNumber + " is ready to shutdown");
                    }
                    // figure out if the other side is ready to shutdown
                    lock (shutdownLocker)
                    {
                        shutdown = shouldShutdown;
                        if (!shouldShutdown)
                            shouldShutdown = true;
                    }

                    // if not ready to shutdown, go into infinite send state until a shutdown signal comes through the buffer
                    if (!shutdown)
                    {
                        while (true)
                        {
                            // check to see if the thread's buffer has something to transmit
                            if (bridgeNumber == 1)
                            {
                                lock (buf1Locker)
                                {
                                    if (buffer1.Count != 0)
                                        shouldTransmit = true;
                                    else
                                        shouldTransmit = false;
                                }
                            }
                            else
                            {
                                lock (buf2Locker)
                                {
                                    if (buffer2.Count != 0)
                                        shouldTransmit = true;
                                    else
                                        shouldTransmit = false;
                                }
                            }

                            if (shouldTransmit)
                            {
                                if (shutdownTransmit())
                                {
                                    break; // shutdown
                                }
                                else
                                    Thread.Sleep(10); // otherwise, sleep for 10 ms
                            }
                            else
                            {
                                Thread.Sleep(10); // if nothing in the queue, sleep and try again
                            }
                        }
                        break;
                    }
                    // otherwise, send shutdown signal to both rings and shutdown
                    else
                    {
                        frame = new Frame(1, 0, 255, null);
                        if (bridgeNumber == 1)
                        {
                            lock (buf2Locker)
                            {
                                buffer2.Enqueue(new Frame(frame.AC, frame.DA, frame.SA, frame.data));
                            }
                            bFrame = frame.ToBinary();
                            this.sendStream.Write(bFrame, 0, bFrame.Length);
                        }
                        else
                        {

                            lock (buf1Locker)
                            {
                                buffer1.Enqueue(new Frame(frame.AC, frame.DA, frame.SA, frame.data));
                            }
                            bFrame = frame.ToBinary();
                            this.sendStream.Write(bFrame, 0, bFrame.Length);
                        }
                    }
                    break;
                }

                // send the frame to the proper ring
                else
                {
                    // check for which ring the frame goes to
                    lock (lookupTableLocker)
                    {
                        if (lookupTable.Contains(frame.DA))
                            destRing = (int)lookupTable[frame.DA];
                        else
                            destRing = -1;
                    }
                    // if it is unknown, add it to both buffers
                    if (destRing == -1)
                    {
                        // set the bit to be checked later for adding to lookup table
                        frame.AC = 4;

                        // add it to both buffers
                        lock (buf1Locker)
                        {
                            buffer1.Enqueue(new Frame(frame.AC, frame.DA, frame.SA, frame.data));
                        }
                        lock (buf2Locker)
                        {
                            buffer2.Enqueue(new Frame(frame.AC, frame.DA, frame.SA, frame.data));
                        }
                        // setup "faked" ack
                        frame.FS = 2; // frame accepted
                        frame.AC = 0; // reset the AC bit to avoid confusion
                    }
                    // if it is known, add it to that buffer
                    else
                    {
                        if (destRing == 1)
                        {
                            lock (buf1Locker)
                            {
                                buffer1.Enqueue(new Frame(frame.AC, frame.DA, frame.SA, frame.data));
                            }
                            if (this.bridgeNumber != destRing)
                            {
                                lock (logLocker)
                                {
                                    logFile.WriteLine(DateTime.Now.ToString() + " Sending frame to Token Ring " + destRing + ". Source=" + frame.SA + " Destination=" + frame.DA);
                                }
                            }
                        }
                        else
                        {
                            lock (buf2Locker)
                            {
                                buffer2.Enqueue(new Frame(frame.AC, frame.DA, frame.SA, frame.data));
                            }
                            if (this.bridgeNumber != destRing)
                            {
                                lock (logLocker)
                                {
                                    logFile.WriteLine(DateTime.Now.ToString() + " Sending frame to Token Ring " + destRing + ". Source=" + frame.SA + " Destination=" + frame.DA);
                                }
                            }
                        }

                        // setup "faked" ack
                        frame.FS = 2;
                    }
                    // send ack
                    bFrame = frame.ToBinary();
                    this.sendStream.Write(bFrame, 0, bFrame.Length);
                }
            }
        }
        finally
        {
            // Close all open resources (i.e. sockets!)
            Console.WriteLine(this.nodeNum + " " + this.bridgeNumber + " Exterminate!");
            lock (logLocker)
            {
                logFile.WriteLine(DateTime.Now.ToString() + " Token ring " + this.bridgeNumber + " is shutting down");
            }
            if (this.bridgeNumber == 1)
            {
                Thread.Sleep(20);
                lock (logLocker)
                {
                    logFile.Close();
                }
            }
            this.recieveStream.Close();
            this.recieveClient.Close();
        }
    }