#include <unistd.h>
#include <iostream>
class ThreadedClass : 
public Thread {
     int variable;
public:
#ifdef USE_GLIB_THREADS
    static void staticMethod(void *data){
        ThreadedClass *tc=static_cast<ThreadedClass*>(data);
        tc->method();
    }
#else
    static void *staticMethod(void *data){
        ThreadedClass *tc=static_cast<ThreadedClass*>(data);
        tc->method();
        cout <<"data"<<data<<endl;
        tc->exit(data);
        return data;
    }
#endif
    void setVariable(int var){
        variable=var;
    }
    void method(void){
        sleep(1);
        cout<<"varibale = "<<++variable<<endl;
    }
};
    void *threadMain(void){
        sleep(2);
        cout<<"hi again"<<endl;
        return NULL;
    }
};
    virtual void *threadMain(void){
        mutex->lock();
        cout<<"Mutex locked"<<endl;
        return NULL;
    }
protected:
public:
        mutex=m;
    }
};
class ThreadedUnLockClass : public ThreadedLockClass {
    void *threadMain(void){
        sleep(2);
        mutex->unLock();
        cout<<"Unlocking the mutex"<<endl;
        return NULL;
    }
public:
    ThreadedUnLockClass(
Mutex *m) : ThreadedLockClass(m) {
    }
};
    void *threadMain(void){
        while (1){
            sleep(1);
            cout<<"Forever thread, 1s has passed"<<endl;
        }
        return NULL;
    }
};
public:
    bool ready;
    WaitingThreadTest(){
        ready=false;
    }
    void *threadMain(void){
        while (running()){ 
            cond.lock();
            while (!ready)
                cond.wait();
            cout<<"WaitingThreadTest: I have been signalled and ready is true!"<<endl;
            ready=false;
            cond.unLock();
        }
        return NULL;
    }
};
public:
    void *threadMain(void){
        cond.lock();
        cond.wait();
        cout<<"WaitingThreadTest2 : I have been signalled "<<endl;
        cond.unLock();
        return NULL;
    }
};
int main(
int argc, 
char *argv[]){
     ThreadedClass threadedClass;
    threadedClass.setVariable(3);
    int res=threadedClass.run(threadedClass.staticMethod, static_cast<void*>(&threadedClass));
    cout<<&threadedClass<<'\t'<<threadedClass.meetThread()<<endl;
    ThreadedMethodClass threadedMethodClass;
    res=threadedMethodClass.run();
    cout<<"\nwaiting for the second thread to exit"<<endl;
    cout<<threadedMethodClass.meetThread()<<endl;
    cout<<"testing mutex lock unlock"<<endl;
    cout<<"testing mutex unlock twice"<<endl;
    ThreadedLockClass tlc(&mutex); tlc.run();
    ThreadedUnLockClass tuc(&mutex); tuc.run();
    sleep(1);
    cout<<"Main thread: waiting for the mutex to unlock."<<endl;
    cout<<"Main thread: mutex has unlocked."<<endl;
    ForeverThread ft;
    ft.run();
    sleep(2);
    cout<<"about to stop the forever thread"<<endl;
    ft.stop();
    cout<<"Stopped"<<endl;
    WaitingThreadTest2 waitingThread2;
    waitingThread2.run(); 
    sleep(1);
    waitingThread2.cond.lock(); 
    cout<<"\nsignalling the thread"<<endl;
    waitingThread2.cond.signal(); 
    cout<<"unlocking the thread"<<endl;
    waitingThread2.cond.unLock(); 
    WaitingThreadTest waitingThread;
    waitingThread.run(); 
    sleep(1);
    waitingThread.cond.lock(); 
    waitingThread.ready=true;
    cout<<"\nsignalling the thread"<<endl;
    waitingThread.cond.signal(); 
    cout<<"unlocking the thread"<<endl;
    waitingThread.cond.unLock(); 
    sleep(2); 
    ForeverThread ft1;
    cout<<"running forever thread"<<endl;
    ft1.run(sched_get_priority_max(SCHED_FIFO));
    ft1.getPriority();
    
    sleep(2);
    ft1.stop();
    cout<<"Stopped"<<endl;
}