# interface target for our warnings
add_library(project_options INTERFACE)
add_library(project::options ALIAS project_options)

# Intergrate Window System Intergration (WSI) options with compiler options
include(WindowSystemIntergration)
target_link_libraries(project_options INTERFACE platform_wsi_defines)

# Set C++ Standard
target_compile_features(project_options INTERFACE cxx_std_23)

# installation
set_target_properties(project_options PROPERTIES EXPORT_NAME compiler_options)
install(TARGETS project_options EXPORT project_targets)

# Compiler specific options
#
# More compiler targets can be found at:
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
if("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang")
    # Clang options that cover both Clang and Apple Clang
    if(ENABLE_WARNINGS)
        target_compile_options(project_options INTERFACE
            "-Wall"
            "-Wextra"               # reasonable and standard
            "-Wshadow"              # warn the user if a variable declaration shadows one from a parent context
            "-Wnon-virtual-dtor"    # warn the user if a class with virtual functions has a non-virtual destructor.
                                    # This helps catch hard to track down memory errors
            "-Wold-style-cast"      # warn for c-style casts
            "-Wcast-align"          # warn for potential performance problem casts
            "-Wunused"              # warn on anything being unused
            "-Woverloaded-virtual"  # warn if you overload (not override) a virtual function
            "-Wpedantic"            # warn if non-standard C++ is used
            "-Wconversion"          # warn on type conversions that may lose data
            "-Wsign-conversion"     # warn on sign conversions
            "-Wnull-dereference"    # warn if a null dereference is detected
            "-Wdouble-promotion"    # warn if float is implicit promoted to double
            "-Wformat=2"            # warn on security issues around functions that format output (ie printf)
            "-Wimplicit-fallthrough"# warn on statements that fallthrough without an explicit annotation
            )

        if(ENABLE_WARNINGS_AS_ERRORS)
            target_compile_options(project_options INTERFACE "-Werror")
        endif()
    endif()

    option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF)
    if(ENABLE_BUILD_WITH_TIME_TRACE)
        target_compile_options(project_options INTERFACE -ftime-trace)
    endif()


    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
        # Apple Clang specific flags 
    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
        # Clang options that Apple Clang can't handle
    endif()
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    if(ENABLE_WARNINGS)
        target_compile_options(project_options INTERFACE
            "-Wall"
            "-Wextra"               # reasonable and standard
            "-Wshadow"              # warn the user if a variable declaration shadows one from a parent context
            "-Wpedantic"
            "-Wnon-virtual-dtor"    # warn the user if a class with virtual functions has a non-virtual destructor.
                                    # This helps catch hard to track down memory errors
            "-Wold-style-cast"      # warn for c-style casts
            "-Wcast-align"          # warn for potential performance problem casts
            "-Wunused"              # warn on anything being unused
            "-Woverloaded-virtual"  # warn if you overload (not override) a virtual function
            "-Wpedantic"            # warn if non-standard C++ is used
            "-Wconversion"          # warn on type conversions that may lose data
            "-Wsign-conversion"     # warn on sign conversions
            "-Wnull-dereference"    # warn if a null dereference is detected
            "-Wdouble-promotion"    # warn if float is implicit promoted to double
            "-Wformat=2"            # warn on security issues around functions that format output (ie printf)
            "-Wmisleading-indentation" # warn if indentation implies blocks where blocks do not exist
            "-Wduplicated-cond"     # warn if if / else chain has duplicated conditions
            "-Wduplicated-branches" # warn if if / else branches have duplicated code
            "-Wlogical-op"          # warn about logical operations being used where bitwise were probably wanted
            "-Wuseless-cast"        # warn if you perform a cast to the same type
            )

        if(ENABLE_WARNINGS_AS_ERRORS)
            target_compile_options(project_options INTERFACE "-Werror")
        endif()
    endif()
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    target_compile_options(project_options INTERFACE
        "/permissive-" # standards conformance mode for MSVC compiler.
        )
    if(ENABLE_WARNINGS)
        target_compile_options(project_options INTERFACE
            "/W4"       # Baseline reasonable warnings
            "/w14242"   # 'identifier': conversion from 'type1' to 'type1', possible loss of data
            "/w14254"   # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
            "/w14263"   # 'function': member function does not override any base class virtual member function
            "/w14265"   # 'classname': class has virtual functions, but destructor is not virtual instances of this
                        # class may not be destructed correctly
            "/w14287"   # 'operator': unsigned/negative constant mismatch
            "/we4289"   # nonstandard extension used: 'variable': loop control variable declared in the for-loop is
                        # used outside the for-loop scope
            "/w14296"   # 'operator': expression is always 'boolean_value'
            "/w14311"   # 'variable': pointer truncation from 'type1' to 'type2'
            "/w14545"   # expression before comma evaluates to a function which is missing an argument list
            "/w14546"   # function call before comma missing argument list
            "/w14547"   # 'operator': operator before comma has no effect; expected operator with side-effect
            "/w14549"   # 'operator': operator before comma has no effect; did you intend 'operator'?
            "/w14555"   # expression has no effect; expected expression with side- effect
            "/w14619"   # pragma warning: there is no warning number 'number'
            "/w14640"   # Enable warning on thread un-safe static member initialization
            "/w14826"   # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
            "/w14905"   # wide string literal cast to 'LPSTR'
            "/w14906"   # string literal cast to 'LPWSTR'
            "/w14928"   # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
            )

        if(ENABLE_WARNINGS_AS_ERRORS)
            target_compile_options(project_options INTERFACE "/WX")
        endif()
    endif()
else()
    message(AUTHOR_WARNING "No compiler options/warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.")
endif()


# Operating Specific options
if(WIN32)
    target_compile_definitions(project_options INTERFACE
        "NOMINMAX"  # Stop windows.h min/max macros conflicting with C++ Standard Library
        )
endif()
