/* 
 * File:   main.cpp
 * Author: admin
 *
 * Created on Pondelok, 2011, júl 4, 23:04
 */

#include <cstdlib>
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <iostream>

using namespace std;

pthread_mutex_t *writerMutex;
pthread_mutex_t *readerMutex;
pthread_cond_t  *writerMutexCondition;
pthread_cond_t  *readersMutexCondition;

bool writer = false;
unsigned int readers = 0;

/**
 * 
 * mysqlpp::Connection *connection;
 */

void* dataThread(void *param)
{
    unsigned int tpid = (unsigned int) pthread_self(); 
    std::cout<<"start datathread: "<<tpid<<std::endl;
    /**
     * 
     * mysqlpp::Query query = connection->query();
     */
    while (1)
    {
        //std::cout<<"Vstup do kritickej sekcie, cakanie na writer: "<<tpid<<std::endl;
        pthread_mutex_lock(writerMutex);
        while(writer)
        {
            pthread_cond_wait(writerMutexCondition, writerMutex);
            std::cout<<"Cakam na writer: "<<writer<<" pid: "<<tpid<<std::endl;
        }
        pthread_mutex_unlock(writerMutex);
        //std::cout<<"Koniec cakania na writer: "<<tpid<<std::endl;
        
        //std::cout<<"Vstup do kritickej sekcie, uzamknutie readera: "<<readers<<" pid:"<<tpid<<std::endl;
        pthread_mutex_lock(readerMutex);
        readers++;
        //std::cout<<"Kriticka sekcia, uzamknutie readera: "<<readers<<" pid:"<<tpid<<std::endl;
        pthread_mutex_unlock(readerMutex);
        //std::cout<<"Koniec kritickej sekcie, uzamknute readery: "<<readers<<" pid:"<<tpid<<std::endl;
        
        std::cout<<"Reader worker: "<<tpid<<std::endl;
        for (int i = 0; i <= 10000000; i++);
        
        /**
         *  
         * query.execute("...");
         */
        
        //std::cout<<"Vstup do kritickej sekcie, odomknutie readera: "<<readers<<" pid:"<<tpid<<std::endl;
        pthread_mutex_lock(readerMutex);
        readers--;
        //std::cout<<"Kriticka sekcia, odomknutie readera: "<<readers<<" pid:"<<tpid<<std::endl;
        pthread_cond_signal(readersMutexCondition);
        pthread_mutex_unlock(readerMutex);
        //std::cout<<"Koniec kritickej sekcie, odomknute readery: "<<readers<<" pid:"<<tpid<<std::endl;
        std::cout<<"stop datathread: "<<tpid<<std::endl;
    }
}

void * refreshThread(void *param)
{
    unsigned int tpid = (unsigned int) pthread_self(); 
    std::cout<<"start refreshera: "<<tpid<<std::endl;
    /**
     * 
     * mysqlpp::Query query = connection->query();
     */
    while (1)
    {
        std::cout<<"Vstup do kritickej sekcie, nastavenie writer: "<<tpid<<std::endl;
        pthread_mutex_lock(writerMutex);
        writer = true;
        std::cout<<"Kriticka sekcia: writer = true: "<<tpid<<std::endl;
        pthread_mutex_unlock(writerMutex);
        std::cout<<"Koniec kriticka sekcia: "<<tpid<<std::endl;
        
        std::cout<<"Vstup do kritickej sekcie, cakanie na readerov: "<<readers<<" pid:"<<tpid<<std::endl;
        pthread_mutex_lock(readerMutex);
        while (readers > 0) 
        {
            std::cout<<"Cakanie na readerov: "<<readers<<" pid:"<<tpid<<std::endl;
            pthread_cond_wait(readersMutexCondition, readerMutex);
        }
        pthread_mutex_unlock(readerMutex);
        std::cout<<"Koniec kritickej sekcie, Readery: "<<readers<<" pid:"<<tpid<<std::endl;
        
        std::cout<<"Writer manager: data reloads"<<tpid<<std::endl;
        /**
         * query.execute("...");
         * 
         */
        sleep(10);
        
        std::cout<<"Vstup do kritickej sekcie, nastavenie writer: "<<tpid<<std::endl;
        pthread_mutex_lock(writerMutex);
        writer = false;
        std::cout<<"Kriticka sekcia: writer = false: "<<tpid<<std::endl;
        pthread_cond_broadcast(writerMutexCondition);
        pthread_mutex_unlock(writerMutex);
        std::cout<<"Koniec kriticka sekcia: "<<tpid<<std::endl;
        std::cout<<"Wait writer unsleep: "<<tpid<<std::endl;
        sleep(5);
    }
}
/*
 * 
 */
int main(int argc, char** argv) 
{
    /**
     * 
     * connection = new mysqlpp::Connection(true);
     * connection->set_option(new mysqlpp::ReconnectOption(true));
     * connection->connect(dbDB, dbServer, dbUser, dbPassword);
     * connection->query("set names 'utf8';").execute();
     */
    writerMutex = new pthread_mutex_t();
    readerMutex= new pthread_mutex_t();
    writerMutexCondition = new pthread_cond_t();
    readersMutexCondition= new pthread_cond_t();
    pthread_mutex_init(writerMutex, NULL);
    pthread_mutex_init(readerMutex, NULL);
    pthread_cond_init(writerMutexCondition, NULL);
    pthread_cond_init(readersMutexCondition, NULL);
    
    pthread_t *thpid = new pthread_t();
    
    int res = pthread_create(thpid, NULL, &refreshThread, NULL);
    for (int i = 0; i <=10; i++)
    {
        thpid = new pthread_t();
        res = pthread_create(thpid, NULL, dataThread, NULL);
    }
    getchar();
    pthread_mutex_destroy(writerMutex);
    pthread_mutex_destroy(readerMutex);
    pthread_cond_destroy(writerMutexCondition);
    pthread_cond_destroy(readersMutexCondition);
    return 0;
}

