#ifndef INCLUDED_BOBCAT_FLOCK_
#define INCLUDED_BOBCAT_FLOCK_

#include <sys/file.h>
#include <chrono>
#include <thread>
#include <bobcat/exception>
#include <bobcat/semaphore>

namespace FBB
{

class Flock
{
    std::string d_filename;
    int d_fd;
    bool d_ok;              // set to true if the wait-members got the lock
    Semaphore d_sem;

    public:
        Flock();                                                // 1.cc

        // copy/move constructors not avaiable

                            // construct an object using 'lockname' as file
                            // if lockname doesn't exist it is created with
                            // access mode 'mode'
        Flock(std::string const &lockname, mode_t mode = 0600);         // 2.cc

        ~Flock();           // merely unlocks but does not remove 'd_filename'

        void shared() const;    // returns once a shared lock is obtained
                                // throws an exception if the lock file 
                                // doesn't exist

        template <typename Amount, typename Resolution>                 // .f
        bool shared(std::chrono::duration<Amount, Resolution> const &time);
                            // returns true when a shared lock was 
                            // obtained within 'time' time units
                            // throws an exception if d_fd is -1

        void exclusive() const; // returns once an exclusive lock is obtained
                                // throws an exception if the lock file 
                                // doesn't exist

        template <typename Amount, typename Resolution>                 // .f
        bool exclusive(std::chrono::duration<Amount, Resolution> const &wait);
                            // returns true when an exclusive lock was 
                            // obtained within 'wait' time units
                            // throws an exception if d_fd is -1

                            // throws an exception if d_fd is -1
        void unlock() const;// releases the lock

        int fd() const;                                                 // .f
        std::string const &filename() const;                            // .f

        void setFilename(std::string const &filename, mode_t mode = 0600);

    private:
        template <typename Amount, typename Resolution>                 // .f
        bool lockThread(std::chrono::duration<Amount, Resolution> const &wait,
                        int type);

        void reset();
        void requireFD() const;

        void notifyLock(int lockType);                  
        static void tryLock(Flock *ptr, int lockType);                  // .f

};

#include "flock.f"

} // FBB        

#endif
