# Copyright 2010-2021, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

load(
    "//:build_defs.bzl",
    "MOZC_TAGS",
    "mozc_macos_application",
    "mozc_macos_bundle",
    "mozc_objc_library",
    "mozc_objc_test",
    "mozc_py_binary",
    "mozc_select",
    "mozc_select_release_channel",
)
load(
    "//:config.bzl",
    "BRANDING",
    "MACOS_BUNDLE_ID_PREFIX",
    "MACOS_CODESIGN_IDENTITY_INSTALLER_RELEASE",
    "MACOS_CODESIGN_IDENTITY_INSTALLER_TESTING",
    "MACOS_CODESIGN_IDENTITY_PSEUDO",
    "MACOS_CODESIGN_IDENTITY_RELEASE",
    "MACOS_CODESIGN_IDENTITY_TESTING",
    "MACOS_KEYCHAIN_INSTALLER_RELEASE",
    "MACOS_KEYCHAIN_INSTALLER_TESTING",
)

package(default_visibility = ["//visibility:private"])

# BUILD_TYPE_SELECT is treated as a function, but not a string. This cannot be a value of join().
# `--define CHANNEL=(dev|stable)` is the command line option to select a channel.
BUILD_TYPE_SELECT = mozc_select_release_channel(
    dev = "dev",
    stable = "stable",
)

# CODESIGN_IDENTITY_SELECT is treated as a function. This cannot be a value of join().
# `--define CODESIGN=testing` is the command line option to select testing codesign.
CODESIGN_IDENTITY_SELECT = select({
    "//:codesign_release": MACOS_CODESIGN_IDENTITY_RELEASE,
    "//:codesign_testing": MACOS_CODESIGN_IDENTITY_TESTING,
    "//conditions:default": MACOS_CODESIGN_IDENTITY_PSEUDO,
})

CODESIGN_IDENTITY_INSTALLER_SELECT = select({
    "//:codesign_release": MACOS_CODESIGN_IDENTITY_INSTALLER_RELEASE,
    "//:codesign_testing": MACOS_CODESIGN_IDENTITY_INSTALLER_TESTING,
    "//conditions:default": MACOS_CODESIGN_IDENTITY_PSEUDO,
})

KEYCHAIN_INSTALLER_SELECT = select({
    "//:codesign_release": MACOS_KEYCHAIN_INSTALLER_RELEASE,
    "//:codesign_testing": MACOS_KEYCHAIN_INSTALLER_TESTING,
    "//conditions:default": "",
})

mozc_macos_application(
    name = "mozc_macos",
    additional_contents = mozc_select(
        default = {},
        # macos is used for Google internal build.
        macos = {
            "//renderer:mozc_renderer_macos": "Resources",
            "//server:mozc_server_macos": "Resources",
        },
        # prod_macos also refers to oss_macos settings.
        oss_macos = {
            "//gui/about_dialog:about_dialog_macos": "Resources",
            "//gui/config_dialog:config_dialog_macos": "Resources",
            "//gui/dictionary_tool:dictionary_tool_macos": "Resources",
            "//gui/error_message_dialog:error_message_dialog_macos": "Resources",
            "//gui/tool:mozc_prelauncher_macos": "Resources",
            "//gui/word_register_dialog:word_register_dialog_macos": "Resources",
            "//renderer:mozc_renderer_macos": "Resources",
            "//server:mozc_server_macos": "Resources",
        },
    ),
    app_icons = ["//data/images/mac:product_icon.icns"],
    bundle_id = MACOS_BUNDLE_ID_PREFIX,
    bundle_name = BRANDING,
    infoplists = ["Info.plist"],
    resources = [
        "//data/images/mac:direct.tiff",
        "//data/images/mac:full_ascii.tiff",
        "//data/images/mac:full_katakana.tiff",
        "//data/images/mac:half_ascii.tiff",
        "//data/images/mac:half_katakana.tiff",
        "//data/images/mac:hiragana.tiff",
        "//data/installer:credits_en.html",
    ],
    strings = [
        "English.lproj/InfoPlist.strings",
        "Japanese.lproj/InfoPlist.strings",
    ],
    deps = ["mozc_macos_main_lib"],
)

mozc_objc_library(
    name = "common",
    hdrs = ["common.h"],
    sdk_frameworks = ["Foundation"],
    visibility = [
        "//renderer:__pkg__",
    ],
    deps = ["//protocol:commands_cc_proto"],
)

mozc_objc_library(
    name = "mozc_macos_main_lib",
    srcs = ["main.mm"],
    sdk_frameworks = [
        "Cocoa",
        "Foundation",
        "InputMethodKit",
    ],
    tags = ["manual"],
    deps = [
        ":mozc_imk_input_controller",
        ":renderer_receiver",
        "//base:const",
        "//base:init_mozc",
        "//base:run_level",
        "//client",
        "//config:stats_config_util",
        "@com_google_absl//absl/flags:flag",
        "@com_google_absl//absl/log",
    ],
)

mozc_objc_library(
    name = "mozc_imk_input_controller",
    srcs = ["mozc_imk_input_controller.mm"],
    hdrs = ["mozc_imk_input_controller.h"],
    data = [
        "English.lproj/Config.xib",
        "Japanese.lproj/Config.xib",
    ],
    sdk_frameworks = [
        "Carbon",
        "Cocoa",
        "InputMethodKit",
    ],
    tags = ["manual"],
    deps = [
        ":common",
        ":keycode_map",
        ":renderer_receiver",
        "//base:const",
        "//base:process",
        "//base:util",
        "//base/mac:mac_process",
        "//base/mac:mac_util",
        "//client",
        "//client:client_interface",
        "//ipc",
        "//protocol:commands_cc_proto",
        "//protocol:config_cc_proto",
        "//protocol:renderer_cc_proto",
        "//renderer:renderer_client",
        "//renderer:renderer_interface",
        "@com_google_absl//absl/log",
        "@com_google_absl//absl/strings",
    ],
)

mozc_objc_test(
    name = "mozc_imk_input_controller_test",
    size = "small",
    srcs = ["mozc_imk_input_controller_test.mm"],
    deps = [
        ":keycode_map",
        ":mozc_imk_input_controller",
        "//base/mac:mac_util",
        "//client:client_mock",
        "//protocol:candidate_window_cc_proto",
        "//renderer:renderer_interface",
        "//testing:gunit_main_objc",
        "@com_google_absl//absl/container:flat_hash_map",
        "@com_google_absl//absl/log",
        "@com_google_absl//absl/time",
    ],
)

mozc_objc_library(
    name = "renderer_receiver",
    srcs = ["renderer_receiver.mm"],
    hdrs = ["renderer_receiver.h"],
    sdk_frameworks = ["Foundation"],
    deps = [
        ":common",
        "//protocol:commands_cc_proto",
    ],
)

mozc_objc_test(
    name = "renderer_receiver_test",
    size = "small",
    srcs = ["renderer_receiver_test.mm"],
    deps = [
        ":renderer_receiver",
        "//protocol:commands_cc_proto",
        "//testing:gunit_main_objc",
    ],
)

mozc_objc_library(
    name = "keycode_map",
    srcs = ["KeyCodeMap.mm"],
    hdrs = ["KeyCodeMap.h"],
    sdk_frameworks = [
        "Carbon",
        "Cocoa",
    ],
    tags = ["manual"],
    textual_hdrs = [
        ":init_kanamap",
        ":init_specialkeymap",
        ":init_specialcharmap",
    ],
    deps = [
        "//protocol:commands_cc_proto",
        "@com_google_absl//absl/base",
        "@com_google_absl//absl/log",
    ],
)

mozc_objc_test(
    name = "keycode_map_test",
    size = "small",
    srcs = ["KeyCodeMap_test.mm"],
    sdk_frameworks = ["AppKit"],
    deps = [
        ":keycode_map",
        "//base/protobuf:text_format",
        "//protocol:commands_cc_proto",
        "//testing:gunit_main_objc",
    ],
)

mozc_py_binary(
    name = "generate_mapping",
    srcs = ["generate_mapping.py"],
    test_lib = False,
)

genrule(
    name = "init_kanamap",
    srcs = ["//data/preedit:mac-kana.tsv"],
    outs = ["init_kanamap.h"],
    cmd = (
        "$(location :generate_mapping) --mapname=KanaMap" +
        " --result_type='const char *' --filename $< > $@"
    ),
    tools = [":generate_mapping"],
)

genrule(
    name = "init_specialkeymap",
    srcs = ["//data/preedit:mac-specialkeys.tsv"],
    outs = ["init_specialkeymap.h"],
    cmd = (
        "$(location :generate_mapping) --mapname=SpecialKeyMap" +
        " --result_type=KeyEvent::SpecialKey --filename $< > $@"
    ),
    tools = [":generate_mapping"],
)

genrule(
    name = "init_specialcharmap",
    srcs = ["//data/preedit:mac-specialchars.tsv"],
    outs = ["init_specialcharmap.h"],
    cmd = (
        "$(location :generate_mapping) --mapname=SpecialCharMap" +
        " --key_type=unichar --result_type=KeyEvent::SpecialKey" +
        " --filename $< > $@"
    ),
    tools = [":generate_mapping"],
)

mozc_objc_library(
    name = "activate_pane_lib",
    srcs = ["ActivatePane/ActivatePane.mm"],
    hdrs = ["ActivatePane/ActivatePane.h"],
    data = ["ActivatePane/ActivatePane.xib"],
    sdk_frameworks = [
        "Carbon",
        "Cocoa",
        "Foundation",
        "InstallerPlugins",
    ],
    tags = ["manual"],
)

mozc_macos_bundle(
    name = "activate_pane",
    bundle_name = "ActivatePane",
    infoplists = ["ActivatePane/Info.plist"],
    strings = [
        "ActivatePane/English.lproj/InfoPlist.strings",
        "ActivatePane/English.lproj/Localizable.strings",
        "ActivatePane/Japanese.lproj/InfoPlist.strings",
        "ActivatePane/Japanese.lproj/Localizable.strings",
    ],
    deps = ["activate_pane_lib"],
)

mozc_objc_library(
    name = "dev_confirm_pane_lib",
    srcs = ["DevConfirmPane/DevConfirmPane.mm"],
    hdrs = ["DevConfirmPane/DevConfirmPane.h"],
    data = ["DevConfirmPane/DevConfirmPane.xib"],
    sdk_frameworks = [
        "Carbon",
        "Cocoa",
        "Foundation",
        "InstallerPlugins",
    ],
    tags = ["manual"],
)

mozc_macos_bundle(
    name = "dev_confirm_pane",
    bundle_name = "DevConfirmPane",
    infoplists = ["DevConfirmPane/Info.plist"],
    strings = [
        "DevConfirmPane/English.lproj/InfoPlist.strings",
        "DevConfirmPane/English.lproj/Localizable.strings",
        "DevConfirmPane/Japanese.lproj/InfoPlist.strings",
        "DevConfirmPane/Japanese.lproj/Localizable.strings",
    ],
    deps = ["dev_confirm_pane_lib"],
)

mozc_objc_library(
    name = "uninstaller_main_lib",
    srcs = [
        "Uninstaller/DialogsController.mm",
        "Uninstaller/Uninstaller.mm",
        "Uninstaller/Uninstaller_main.mm",
    ],
    hdrs = [
        "Uninstaller/DialogsController.h",
        "Uninstaller/Uninstaller.h",
    ],
    data = [
        "Uninstaller/English.lproj/Dialogs.xib",
        "Uninstaller/Japanese.lproj/Dialogs.xib",
    ],
    sdk_frameworks = [
        "Cocoa",
        "Security",
    ],
    tags = ["manual"],
    deps = [
        "//base:init_mozc",
        "//base:url",
        "//base:version",
        "//base/mac:mac_util",
    ],
)

mozc_macos_application(
    name = "uninstaller_macos",
    app_icons = ["//data/images/mac:product_icon.icns"],
    bundle_name = "Uninstall" +
                  mozc_select(
                      default = "GoogleJapaneseInput",
                      oss = "Mozc",
                      prod = "GoogleJapaneseInput",
                  ),
    infoplists = ["Uninstaller/Info.plist"],
    strings = [
        "Uninstaller/English.lproj/InfoPlist.strings",
        "Uninstaller/Japanese.lproj/InfoPlist.strings",
    ],
    deps = ["uninstaller_main_lib"],
)

genrule(
    name = "tweak_preflight",
    srcs = mozc_select(
        default = ["//mac/installer:preflight_template.sh"],
        oss = ["//mac/installer:preflight_template.sh"],
    ),
    outs = ["preflight.sh"],
    cmd = " ".join([
        "$(location" +
        " //build_tools:tweak_macinstaller_script)",
        " --output $@",
        " --input $<",
        " --build_type ",
    ]) + BUILD_TYPE_SELECT,  # "dev" or "stable".
    tools = ["//build_tools:tweak_macinstaller_script"],
)

genrule(
    name = "tweak_postflight",
    srcs = mozc_select(
        default = ["//mac/installer:postflight_template.sh"],
        oss = ["//mac/installer:postflight_template.sh"],
    ),
    outs = ["postflight.sh"],
    cmd = " ".join([
        "$(location" +
        " //build_tools:tweak_macinstaller_script)",
        " --output $@",
        " --input $<",
        " --use_mozc_version_env",  # Use MOZC_VERSION environment variable if set.
        " --version_file" +
        " $(location //base:mozc_version_txt)" +
        " --build_type ",
    ]) + BUILD_TYPE_SELECT,  # "dev" or "stable".
    # macOS only since the script validates if the version string is proper for macOS.
    tags = MOZC_TAGS.MAC_ONLY,
    tools = [
        "//base:mozc_version_txt",
        "//build_tools:tweak_macinstaller_script",
    ],
)

mozc_py_binary(
    name = "zip_files",
    srcs = ["zip_files.py"],
    test_lib = False,
    deps = ["//build_tools:util"],
)

genrule(
    name = "zipped_installer_files",
    srcs = [
        ":tweak_preflight",
        ":tweak_postflight",
    ] + mozc_select(
        # Common files for all build types.
        macos = [
            ":activate_pane",
            ":dev_confirm_pane",
            ":mozc_macos",
            ":uninstaller_macos",
        ],
    ) + mozc_select(
        # Files per build type.
        macos = [
            "//mac/installer:distribution.xml",
            "//mac/installer:InstallerSections.plist",
            "//mac/installer:launch_agents",
            "//mac/installer:resources",
        ],
        oss_macos = [
            "//mac/installer:distribution.xml",
            "//mac/installer:InstallerSections.plist",
            "//mac/installer:launch_agents",
            "//mac/installer:resources",
        ],
        prod_macos = [
            "@google_updater//:GoogleUpdater.pkg",
            "//mac/installer:distribution.xml",
            "//mac/installer:InstallerSections.plist",
            "//mac/installer:launch_agents",
            "//mac/installer:resources",
        ],
    ),
    outs = ["installer.zip"],
    cmd = "$(location :zip_files) --inputs $(SRCS) --output $@",
    # macOS only since this rule depends on :tweak_postflight that works only for macOS.
    tags = MOZC_TAGS.MAC_ONLY,
    tools = [
        ":zip_files",
    ],
)

mozc_py_binary(
    name = "tweak_installer_files",
    srcs = ["tweak_installer_files.py"],
    test_lib = False,
    deps = ["//build_tools:util"],
)

# Create a zip file for package. The files in the zip file are codesigned.
genrule(
    name = "package_files",
    srcs = [":zipped_installer_files"],
    outs = ["package_files.zip"],
    cmd = "$(location :tweak_installer_files) --productbuild --input $(SRCS)" +
          " --output $@" +
          mozc_select(
              default = " --noqt",
              oss_macos = " --oss",
              prod_macos = "",
          ) +
          ' --codesign_identity "' + CODESIGN_IDENTITY_SELECT + '"' +
          " --channel " + BUILD_TYPE_SELECT,
    exec_compatible_with = ["@platforms//os:macos"],
    # Use local execution instead of sandbox because it uses `codesign` that accesses to keychain.
    local = True,
    tags = ["manual"],
    tools = [":tweak_installer_files"],
)

# .keystone_install stored in the installer .dmg file.
genrule(
    name = "keystone_install",
    srcs = ["//mac/installer:.keystone_install_template"],
    outs = [".keystone_install"],
    cmd = " ".join([
        "$(location" +
        " //build_tools:tweak_macinstaller_script)",
        "--output $@",
        "--input $(SRCS)",
        "--build_type ",
    ]) + BUILD_TYPE_SELECT,  # "dev" or "stable"
    tags = ["manual"],
    tools = [
        "//build_tools:tweak_macinstaller_script",
    ],
)

# Binary for default tools (i.e. pkgbuild and productbuild commands)
mozc_py_binary(
    name = "build_package",
    srcs = ["build_package.py"],
    test_lib = False,
    deps = ["//build_tools:util"],
)

genrule(
    name = "package",
    srcs = [":package_files"],
    outs = ["Mozc.pkg"],
    cmd = "$(location :build_package) --input $(location :package_files)" +
          " --output $@" +
          ' --codesign_identity "' + CODESIGN_IDENTITY_INSTALLER_SELECT + '"' +
          ' --keychain "' + KEYCHAIN_INSTALLER_SELECT + '"' +
          mozc_select(
              default = "",
              oss = " --oss",
              prod = "",
          ),
    exec_compatible_with = ["@platforms//os:macos"],
    # Set local for `productsign` with the local KeyChain.
    local = True,
    # TODO(b/269007577): version_file, auto_updater_dir and build_type should be supported.
    tags = ["manual"],
    tools = [":build_package"],
    visibility = [
        "//:__pkg__",
    ],
)

genrule(
    name = "diskimage",
    srcs = [
        ":keystone_install",
        ":package",
    ],
    outs = ["Mozc.dmg"],
    cmd = " ".join([
        "$(location //build_tools:build_diskimage_mac)",
        "--output $@",
        "--pkg_file $(location :package)",
        "--keystone_install_file $(location :keystone_install)",
    ]) +
    # mozc_select cannot be in join, as it's treated as a function rather than a string.
    mozc_select(
        default = " --volname Mozc",
        prod = " --volname GoogleJapaneseInput",
    ),
    exec_compatible_with = ["@platforms//os:macos"],
    # Use local execution instead of sandbox because it uses `hdiutil` that accesses to /Volumes/.
    local = True,
    tags = ["manual"],
    tools = ["//build_tools:build_diskimage_mac"],
)

genrule(
    name = "diskimage_signed",
    srcs = [":diskimage"],
    outs = ["Mozc_signed.dmg"],
    cmd = " ".join([
        "cp $(location :diskimage) $@ &&",
        "chmod u+w $@ &&",
        "/usr/bin/codesign",
        "--force --verbose",
        "--deep",  # Recursive signs
        "--timestamp --options=runtime",  # For notarization
        "--keychain login.keychain",
    ]) +
    # mozc_select cannot be in join, as it's treated as a function rather than a string.
    mozc_select(
        default = " --identifier Mozc",
        prod = " --identifier GoogleJapaneseInput",
    ) + ' --sign "' + CODESIGN_IDENTITY_SELECT + '"' + " $@",
    exec_compatible_with = ["@platforms//os:macos"],
    # Use local execution instead of sandbox because it uses `codesign` that accesses to keychain.
    local = True,
    tags = ["manual"],
)
