/*
 * NMSTL, the Networking, Messaging, Servers, and Threading Library for C++
 * Copyright (c) 2002 Massachusetts Institute of Technology
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <iostream>

#include <nmstl/thread>

using namespace nmstl;
using namespace std;

bool quit;
mutex quit_lock;
condition quit_condition;
int count = 0;

// A MyBushThread prints out a Bushism every second.  This is the
// first way to do threading - have your class directly extend thread.
class MyBushThread : public thread {
    const char *message;

public:
    MyBushThread(const char *message = "") :
        thread("bush-" + to_string(++::count)),
        message(message) {}

    virtual void run() {
        locking (quit_lock) {
            while (!quit) {
                if (quit_condition.wait(quit_lock,
                                        ntime::now() + ntime::msecs(random() % 20000)))
                    break;

                cout << "Dubya " << thread::self() << " says: " << message << endl;
            }
        }

        cout << "Dubya " << thread::self() << " says goodbye!" << endl;
    }
};


// A MyQuayleRunnable prints out a Quayle-ism every second.  This is
// the second way to do threading - give your class a run() method,
// and use the threaded<...> wrapper.
class MyQuayleRunnable {
    const char *message;

public:
    MyQuayleRunnable(const char *message = "") : message(message) {}

    virtual void run() {
        locking (quit_lock) {
            while (!quit) {
                if (quit_condition.wait(quit_lock,
                                        ntime::now() + ntime::msecs(random() % 20000)))
                    break;
		
                cout << "Quayle " << thread::self() << " says: " << message << endl;
            }
        }

        cout << "Quayle " << thread::self() << " says goodbye!" << endl;
    }
};


typedef threaded<MyQuayleRunnable> MyQuayleThread;

int main() {
    srand(time(0));

    MyBushThread bush[5] = {
        "I understand small business growth.  I was one.",
        "Rarely is the question asked: Is our children learning?",
        "I think we agree, the past is over.",
        "More and more of our imports come from overseas.",
        "Our nation must come together to unite."
    };

    MyQuayleThread quayle[5] = {
        "Republicans understand the importance of bondage\n"
        "    between a mother and child.",
        "If we do not succeed, then we run the risk of failure.",
        "We're going to have the best-educated American people\n"
        "    in the world.",
        "What a terrible thing to have lost one's mind.  Or not\n"
        "    to have a mind at all.  How true that is.",
        "A low voter turnout is an indication of fewer people\n"
        "    going to the polls."
    };

    cout << "(main thread " << thread::self() << ")" << endl;
    cout << "Hit enter once you're sufficiently nauseated." << endl;

    // Start all ten threads.

    for (int i = 0; i < 5; ++i) {
        bush[i].start();
        quayle[i].start();
    }


    // In the current thread, do blocking I/O to wait until the user
    // presses enter.

    string in;
    getline(cin, in);


    // Broadcast "quit" to all the threads.

    quit = true;
    quit_condition.broadcast();

    cout << "(main thread " << thread::self() << " exiting)" << endl;
}
