    {-# LANGUAGE CPP #-}
    {- Windows compatibility layer
    Copyright (C) 2005 John Goerzen <jgoerzen@complete.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    -}

    {- |
       Module     : System.IO.WindowsCompat
       Copyright  : Copyright (C) 2005 John Goerzen
       License    : GNU GPL, version 2 or above

       Maintainer : John Goerzen <jgoerzen@complete.org>
       Stability  : provisional
       Portability: portable

    Provides some types and related items on Windows to be compatible with
    the System.Posix.* libraries

    See also "System.IO.StatCompat", which this module re-exports.

    Copyright (c) 2005 John Goerzen, jgoerzen\@complete.org

    On non-Windows platforms, this module does nothing.

    On Windows, it re-exports "System.IO.StatCompat".  It also provides various
    file type information modes that are otherwise in "System.Posix.Types" or
    "System.Posix.Files".  It also provides
    a rudimentary implemention of getFileStatus that emulates the Posix call
    to stat(2).

    Common usage might be like this:

    >import System.Posix.Types
    >#if (defined(mingw32_HOST_OS) || defined(mingw32_TARGET_OS) || defined(__MINGW32__))
    >import System.IO.WindowsCompat
    >#else
    >import System.Posix.Files
    >#endif

    Or, to avoid having to use CPP and make things even easier, just import
    "System.IO.PlafCompat", which essentially does the above.

    -}

    module System.IO.WindowsCompat
    #if !(defined(mingw32_HOST_OS) || defined(mingw32_TARGET_OS) || defined(__MINGW32__))
    where
    #else
           (module System.IO.StatCompat, module System.IO.WindowsCompat)
    where

    import System.Posix.Types
    import Data.Bits
    import System.IO.StatCompat
    import System.Posix.Consts
    import System.Time.Utils
    import System.Directory

    -- these types aren't defined here

    nullFileMode :: FileMode
    nullFileMode = 0

    ownerReadMode :: FileMode
    ownerReadMode = 0o00400

    ownerWriteMode :: FileMode
    ownerWriteMode = 0o00200

    ownerExecuteMode :: FileMode
    ownerExecuteMode = 0o00100

    groupReadMode :: FileMode
    groupReadMode = 0o00040

    groupWriteMode :: FileMode
    groupWriteMode = 0o00020

    groupExecuteMode :: FileMode
    groupExecuteMode = 0o00010

    otherReadMode :: FileMode
    otherReadMode = 0o00004

    otherWriteMode :: FileMode
    otherWriteMode = 0o00002

    otherExecuteMode :: FileMode
    otherExecuteMode = 0o00001

    setUserIDMode :: FileMode
    setUserIDMode = 0o0004000

    setGroupIDMode :: FileMode
    setGroupIDMode = 0o0002000

    stdFileMode :: FileMode
    stdFileMode = ownerReadMode  .|. ownerWriteMode .|.
                  groupReadMode  .|. groupWriteMode .|.
                  otherReadMode  .|. otherWriteMode

    ownerModes :: FileMode
    ownerModes = 0o00700

    groupModes :: FileMode
    groupModes = 0o00070

    otherModes :: FileMode
    otherModes = 0o00007

    accessModes :: FileMode
    accessModes = ownerModes .|. groupModes .|. otherModes

    ----------- stat
    type FileStatus = FileStatusCompat
    getFileStatus :: FilePath -> IO FileStatus
    getFileStatus fp =
        do isfile <- doesFileExist fp
           isdir <- doesDirectoryExist fp
           perms <- getPermissions fp
           modct <- getModificationTime fp
           let epochtime = clockTimeToEpoch modct
           return $ FileStatusCompat {deviceID = -1,
                                      fileID = -1,
                                      fileMode = if isfile then regularFileMode
                                                           else directoryMode,
                                      linkCount = 1,
                                      fileOwner = 0,
                                      fileGroup = 0,
                                      specialDeviceID = -1,
                                      fileSize = 0, -- fixme: hFileSize?
                                      accessTime = fromInteger epochtime,
                                      modificationTime = fromInteger epochtime,
                                      statusChangeTime = fromInteger epochtime
                                     }
    #endif