""" Contains common configuration-related entities used by cc_hdrs_map rules. """

_COMMON_RULES_ATTRS = {
    "deps": attr.label_list(
        default = [],
        doc = "The list of dependencies of current target",
    ),
    "srcs": attr.label_list(
        mandatory = True,
        allow_files = [
            ".c",
            ".cc",
            ".cpp",
            ".cxx",
            ".c++",
            ".C",
        ],
        doc = "The list of source files.",
    ),
    "public_hdrs": attr.label_list(
        allow_files = [
            ".h",
            ".hh",
            ".hpp",
            ".hxx",
            ".inc",
            ".inl",
            ".H",
        ],
        doc = """ 
        List of headers that may be included by dependent rules transitively.
        Notice: the cutoff happens during compilation.
        """,
        default = [],
    ),
    "private_hdrs": attr.label_list(
        allow_files = [
            ".h",
            ".hh",
            ".hpp",
            ".hxx",
            ".inc",
            ".inl",
            ".H",
        ],
        doc = """
        List of headers that CANNOT be included by dependent rules.
        Notice: the cutoff happens during compilation.
        """,
        default = [],
    ),
    "hdrs_map": attr.string_list_dict(
        default = {},
        doc = """
        Dictionary describing paths under which header files should be avaiable as.

        Keys are simple glob pathnames, used to match agains all header files avaiable in the rule.
        Values are list of paths to which matching header files should be mapped.

        '{filename}' is special token used to signify to matching file name.

        For example:
        '"**/*o.hpp": ["a/{filename}"]' - will ensure all hpp files with names ending with '0'
        will be also avaible as if they were placed in a subdirectory. 
        """,
    ),
}

_CC_COMPILABLE_ATTRS = {
    "additional_linker_inputs": attr.label_list(
        default = [],
        doc = """
        Pass these files to the C++ linker command.

        For example, compiled Windows .res files can be provided here to be embedded in the binary target.
        """,
    ),
    "copts": attr.string_list(
        default = [],
        doc = """
        Add these options to the C++ compilation command. Subject to "Make variable" substitution and Bourne shell tokenization.
        Each string in this attribute is added in the given order to COPTS before compiling the binary target. The flags take effect only for compiling this target, not its dependencies, so be careful about header files included elsewhere. All paths should be relative to the workspace, not to the current package.

        If the package declares the feature no_copts_tokenization, Bourne shell tokenization applies only to strings that consist of a single "Make" variable.
        """,
    ),
    "defines": attr.string_list(
        default = [],
        doc = """
        List of defines to add to the compile line. Subject to "Make" variable substitution and Bourne shell tokenization. Each string, which must consist of a single Bourne shell token, is prepended with -D and added to the compile command line to this target, as well as to every rule that depends on it. Be very careful, since this may have far-reaching effects. When in doubt, add define values to local_defines instead.
        """,
    ),
    "includes": attr.string_list(
        default = [],
        doc = """
        List of include dirs to be added to the compile line.
        Subject to "Make variable" substitution. Each string is prepended with -isystem and added to COPTS. Unlike COPTS, these flags are added for this rule and every rule that depends on it. (Note: not the rules it depends upon!) Be very careful, since this may have far-reaching effects. When in doubt, add "-I" flags to COPTS instead.

        Headers must be added to srcs or hdrs, otherwise they will not be available to dependent rules when compilation is sandboxed (the default).
        """,
    ),
    "linkopts": attr.string_list(
        default = [],
        doc = """
        Add these flags to the C++ linker command. Subject to "Make" variable substitution, Bourne shell tokenization and label expansion. Each string in this attribute is added to LINKOPTS before linking the binary target.
        Each element of this list that does not start with $ or - is assumed to be the label of a target in deps. The list of files generated by that target is appended to the linker options. An error is reported if the label is invalid, or is not declared in deps.
        """,
    ),
    "linkstatic": attr.bool(
        default = True,
        doc = "Link the binary in static mode.",
    ),
    "local_defines": attr.string_list(
        default = [],
        doc = """
        List of defines to add to the compile line. Subject to "Make" variable substitution and Bourne shell tokenization. Each string, which must consist of a single Bourne shell token, is prepended with -D and added to the compile command line for this target, but not to its dependents.
        """,
    ),
    "_cc_toolchain": attr.label(
        default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
    ),
    "_is_windows": attr.bool(
        default = False,
        doc = "Signify Windows execution platform. To be improved upon (should not require manual input)",
    ),
}

_CC_LIB_ATTRS = {
    "include_prefix": attr.string(
        default = "",
        doc = """
        The prefix to add to the paths of the headers of this rule.
        When set, the headers in the hdrs attribute of this rule are accessible at is the value of this attribute prepended to their repository-relative path.

        The prefix in the strip_include_prefix attribute is removed before this prefix is added.
        """,
    ),
    "strip_include_prefix": attr.string(
        default = "",
        doc = """
        The prefix to strip from the paths of the headers of this rule.
        When set, the headers in the hdrs attribute of this rule are accessible at their path with this prefix cut off.

        If it's a relative path, it's taken as a package-relative one. If it's an absolute one, it's understood as a repository-relative path.

        The prefix in the include_prefix attribute is added after this prefix is stripped.
        """,
    ),
}

# Authors' soap box:
# + no longer works, neither does |
#  "{**dictA, **dictB}" never did..
#   update modifies in place..

def get_cc_bin_attrs():
    """ To be described """
    cc_bin_attrs = {
        "stamp": attr.int(
            default = -1,
            doc = """
            Whether to encode build information into the binary. Possible values:

              * stamp = 1: Always stamp the build information into the binary, even in --nostamp builds. This setting should be avoided, since it potentially kills remote caching for the binary and any downstream actions that depend on it.

              * stamp = 0: Always replace build information by constant values. This gives good build result caching.

              * stamp = -1: Embedding of build information is controlled by the --[no]stamp flag.
            
            Stamped binaries are not rebuilt unless their dependencies change.
            """,
        ),
    }
    cc_bin_attrs.update(_COMMON_RULES_ATTRS)
    cc_bin_attrs.update(_CC_COMPILABLE_ATTRS)
    return cc_bin_attrs

def get_cc_hdrs_attrs():
    """ To be described. """
    cc_hdrs_attrs = {}
    cc_hdrs_attrs.update(_COMMON_RULES_ATTRS)
    cc_hdrs_attrs.pop("srcs")
    return cc_hdrs_attrs

def get_cc_so_attrs():
    """ To be described. """
    cc_so_attrs = {
        "alwayslink": attr.bool(
            default = True,
            doc = """
            If 1, any binary that depends (directly or indirectly) on this C++ library will link in all the object files for the files listed in srcs, even if some contain no symbols referenced by the binary. This is useful if your code isn't explicitly called by code in the binary, e.g., if your code registers to receive some callback provided by some service.
            """,
        ),
    }
    cc_so_attrs.update(_COMMON_RULES_ATTRS)
    cc_so_attrs.update(_CC_COMPILABLE_ATTRS)
    cc_so_attrs.update(_CC_LIB_ATTRS)
    return cc_so_attrs

def get_cc_archive_attrs():
    """ To be described. """
    cc_archive_attrs = {}
    cc_archive_attrs.update(_COMMON_RULES_ATTRS)
    cc_archive_attrs.update(_CC_COMPILABLE_ATTRS)
    cc_archive_attrs.update(_CC_LIB_ATTRS)
    return cc_archive_attrs
