#include <mecab.h>
#include <stdio.h>
#include <pthread.h>
#include <queue>

template <class T>
class CircularBuffer
{
private:
  unsigned int rp;
  unsigned int wp;
  unsigned int size;
  unsigned int used;
  pthread_mutex_t mutex;
  pthread_cond_t full;
  pthread_cond_t empty;
  bool end;
  T *data;

public:
  CircularBuffer (unsigned int _size) : 
    rp(0), wp(0), size (_size), used (0),end(false)
  {
    data = new T [_size];
    pthread_mutex_init (&mutex, NULL);
    pthread_cond_init (&full, NULL);
    pthread_cond_init (&empty, NULL);
  }

  ~CircularBuffer () 
  {
    delete [] data;
  }

  bool put (T& x) 
  {
    pthread_mutex_lock (&mutex);
    while (used == size) pthread_cond_wait (&full, &mutex);
    data[wp++] = x;
    if (wp >= size) wp = 0;
    used++;
    pthread_cond_signal  (&empty);
    pthread_mutex_unlock (&mutex);
    return true;
  }

  bool get (T &x) 
  {
    pthread_mutex_lock (&mutex);

    if (end && used == 0) { // there are no data
      pthread_mutex_unlock (&mutex);
      return false;
    }

    while (used == 0) pthread_cond_wait (&empty, &mutex);
    x = data[rp++];
    if (rp >= size) rp = 0;
    used--;
    pthread_cond_signal (&full);
    pthread_mutex_unlock (&mutex);
    return true;
  }

  void stop ()
  {
    end = true;
  }
};

CircularBuffer<char *> cb (16);

void *parse (void *p)
{
  char *r; 
  while (cb.get (r)) {
    MeCab::Tagger *t = (MeCab::Tagger *)(p);
    cout << t->parse (r);
    delete [] r; 
  }
  return 0;
}

void *work (void *p)
{
  while (true) {
    char* buf = new char [1024];
    if (! cin.getline (buf, 1024)) break;
    cb.put (buf);
  }

  cb.stop ();
   
  return 0;
}

#define NUM 2

int main (int argc, char **argv) 
{
  pthread_t **pt = new pthread_t* [NUM];
  MeCab::Tagger **ct = new MeCab::Tagger * [NUM];
  pthread_t w;
  pthread_create (&w, NULL, &work, (void *)NULL);   
   
  MeCab::Tagger *t = new MeCab::Tagger (argc, argv);   
  for (int i = 0; i < NUM; i++) {
    pt[i] = new pthread_t;
    ct[i] = new MeCab::Tagger (argc, argv);
    pthread_create (pt[i], NULL, &parse, (void *)ct[i]);
  }

  pthread_join (w, NULL);
  for (int i = 0; i < NUM; i++) {   
    pthread_join (*pt[i], NULL);
  }
}
