/*
 * 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 <sstream>
#include <nmstl/seda>
#include <algorithm>
#include <cctype>

using namespace nmstl;
using namespace std;

// Pretend that it takes some time to do stuff with the input string.
// Sleep cost for every character in the string.
void delay(const string& in, ntime cost) {
    thread::sleep(in.length() * cost);
}

char my_toupper(char ch) { return toupper(ch); }

// A task that converts a string to uppercase.
class uppercase_task : public seda_stage<string, string> {
    virtual void handle(string& in) {
        delay(in, ntime::msecs(400));
        transform(in.begin(), in.end(), in.begin(), my_toupper);

        DEBUG << "Uppercase: output \"" << in << "\"";
        output(in);
    }
};

// A task that reverses a string.
class reverse_task : public seda_stage<string, string> {
    virtual void handle(string& in) {
        delay(in, ntime::msecs(600));
        reverse(in.begin(), in.end());

        DEBUG << "Reverse: output \"" << in << "\"";
        output(in);
    }
};

// A task that outputs a string as "finished."
class output_task : public seda_stage<string> {
    virtual void handle(string& in) {
        delay(in, ntime::msecs(100));
        NOTICE << "Finished: \"" << in << "\"";
    }
};

const char *bushisms[] = {
    "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."
};

int main(int argc, const char **argv) {
    debug::get().set_show_thread(true);

    uppercase_task ut;
    reverse_task rt;
    output_task ot;

    ut.set_name("Uppercase");
    rt.set_name("Reverse");
    ot.set_name("Output");

    ut.set_nthreads(0, 5);
    rt.set_nthreads(0, 5);
    ot.set_nthreads(0, 5);

    ut.set_next(rt);
    rt.set_next(ot);

    seda_clock_thread clock(ntime::msecs(1000));
    clock.insert(ut);
    clock.insert(rt);
    clock.insert(ot);
    clock.start();

    cout << "Gimme a string!  (EOF to exit)" << endl;
    cout << "If you're lazy, just type * and I'll pick a string for you." << endl;

    while (1) {
        string in;
        cin >> in;

        if (in.empty())
            break;

        if (in == "*") {
            istringstream instr(bushisms[rand() % (sizeof bushisms / sizeof bushisms[0])]);
            while (instr >> in) {
                NOTICE << "Injecting \"" << in << "\" into queue";
                ut.inject(in);
            }
        } else {
            NOTICE << "Injecting \"" << in << "\" into queue";
            ut.inject(in);
        }
    }

    // Must destroy clock before stages; destruction order guarantees this
}
