// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEL_1_CPp_
#define DLIB_MISC_API_KERNEL_1_CPp_

#include "../platform.h"
#include "../threads.h"

#ifdef WIN32

#include "misc_api_kernel_1.h"

#include "../windows_magic.h"
#include <mmsystem.h>
#include <windows.h>

// tell visual studio to link to the library needed to call timeGetTime() 
#ifdef _MSC_VER
#pragma comment (lib, "winmm.lib")
#endif

#ifdef __BORLANDC__
// Apparently the borland compiler doesn't define this.
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif

namespace dlib
{
// ----------------------------------------------------------------------------------------

    void sleep (
        unsigned long milliseconds
    )
    {
        ::Sleep(milliseconds);
    }

// ----------------------------------------------------------------------------------------

    namespace
    {
        mutex& cwd_mutex()
        {
            static mutex m;
            return m;
        }
        // Make sure the above mutex gets constructed before main() 
        // starts.  This way we can be pretty sure it will be constructed
        // before any threads could possibly call set_current_dir() or
        // get_current_dir() simultaneously.
        struct construct_cwd_mutex
        {
            construct_cwd_mutex()
            {
                cwd_mutex();
            }
        } oaimvweoinvwe;
    }

    std::string get_current_dir (
    )
    {
        // need to lock a mutex here because getting and setting the
        // current working directory is not thread safe on windows.
        auto_mutex lock(cwd_mutex());
        char buf[1024];
        if (GetCurrentDirectoryA(sizeof(buf),buf) == 0)
        {
            return std::string();
        }
        else
        {
            return std::string(buf);
        }
    }

// ----------------------------------------------------------------------------------------

    void set_current_dir (
        const std::string& new_dir
    )
    {
        // need to lock a mutex here because getting and setting the
        // current working directory is not thread safe on windows.
        auto_mutex lock(cwd_mutex());
        if (SetCurrentDirectoryA(new_dir.c_str()) == 0)
        {
            throw set_current_dir_error("Error changing current dir to '" + new_dir + "'");
        }
    }

// ----------------------------------------------------------------------------------------

    uint64 timestamper::
    get_timestamp (
    ) const
    {
        unsigned long temp = timeGetTime();
        if (temp >= last_time)
        {            
            last_time = temp;
            return (offset + temp)*1000;
        }
        else
        {
            last_time = temp;

            // there was overflow since the last call so we need to make the offset
            // bigger to account for that
            offset += dword_max;
            return (offset + temp)*1000;
        }        
    }

// ----------------------------------------------------------------------------------------

    void create_directory (
        const std::string& dir
    )
    {
        if (CreateDirectoryA(dir.c_str(),0) == 0)
        {
            // an error has occurred
            if (GetLastError() == ERROR_ALREADY_EXISTS)
            {
                // make sure this is actually a directory
                DWORD attribs = GetFileAttributesA(dir.c_str());
                if (attribs == INVALID_FILE_ATTRIBUTES ||
                    (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0)
                {
                    // it isn't a directory
                    throw dir_create_error(dir);
                }
            }
            else
            {
                throw dir_create_error(dir);
            }
        }
    }

// ----------------------------------------------------------------------------------------
    
}

#endif // WIN32

#endif // DLIB_MISC_API_KERNEL_1_CPp_