    // 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_