#!/usr/bin/python3
import os
import sys
import shutil
import json
import re
from urllib.parse import urlparse
from contextlib import contextmanager

from build_vars import *

def new_section(msg):
    print("\n*******************************************************")
    print("* %s" % msg)
    print("*******************************************************\n")

def exit_if_fail_os_system(command):
    ret = os.system(command)
    if (ret):
        print("command failed with code %d: %s" % (ret, command))
        exit(1)

def exit_if_fail_os_makedirs(path, exist_ok=False):
    try:
        os.makedirs(path, exist_ok=exist_ok)
    except Exception as e:
        print("mkdir failed: %s: %s" % (path, e))
        exit(1)

@contextmanager
def exit_if_exception():
  try:
    yield
  except Exception as e:
    print("Something failed: %s" % e)
    exit(1)

#####################################################################
# Get the source and unpack it.
#####################################################################
new_section("Downloading and unpacking source:\n%s" % SOURCE_URL)

exit_if_fail_os_system("wget -N -nv %s" % SOURCE_URL)
exit_if_fail_os_system("tar -xf %s.tar.xz" % SOURCE_TARNAME)

#####################################################################
# Copy in default preferences and bookmarks
#####################################################################
new_section("Copying in preferences and bookmarks")

exit_if_fail_os_makedirs("%s/etc/chromium" % STAGING_DIR)

codename = os.environ["MINT_CODENAME"]
# exit_if_fail_os_system("cp data/master_preferences %s/etc/chromium" % STAGING_DIR)
exit_if_fail_os_system("sed s/@CODENAME@/%s/ data/master_preferences > %s/etc/chromium/master_preferences" % (codename, STAGING_DIR))

exit_if_fail_os_makedirs("%s/usr/share/chromium" % STAGING_DIR)
exit_if_fail_os_system("cp data/initial_bookmarks.html %s/usr/share/chromium" % STAGING_DIR)

exit_if_fail_os_makedirs("%s/usr/share/applications" % STAGING_DIR)
exit_if_fail_os_system("cp data/chromium-browser.desktop %s/usr/share/applications" % STAGING_DIR)

with exit_if_exception():
    src_icons_path = "%s/chrome/app/theme/chromium" % CHROME_SOURCE_DIR
    for file in os.listdir(src_icons_path):
        match = re.search(r'(?:product_logo_)(\d+)(?:.png)', file)
        if match:
            size = match.group(1)
            d = "%s/usr/share/icons/hicolor/%sx%s/apps" % (STAGING_DIR, size, size)
            exit_if_fail_os_makedirs(d, exist_ok=True)
            origin_path = os.path.join(src_icons_path, file)
            target_path = os.path.join(d, "chromium.png")
            exit_if_fail_os_system("cp %s %s" % (origin_path, target_path))

exit_if_fail_os_system("cp searchplugins/startpage-24.png %s/components/resources/default_100_percent/search_engine_choice/startpage.png" % CHROME_SOURCE_DIR)
exit_if_fail_os_system("cp searchplugins/startpage-48.png %s/components/resources/default_200_percent/search_engine_choice/startpage.png" % CHROME_SOURCE_DIR)
exit_if_fail_os_system("cp searchplugins/startpage-72.png %s/components/resources/default_300_percent/search_engine_choice/startpage.png" % CHROME_SOURCE_DIR)


#####################################################################
# Apply ubuntu patches
#####################################################################
new_section("Applying quilt patches")

series_file = "series.%s" % IMAGE_CODENAME
if IMAGE_32BIT:
    series_file += ".i386"

os.chdir(CHROME_SOURCE_DIR)
#exit_if_fail_os_system("QUILT_SERIES=%s QUILT_PATCHES=%s quilt push -a" % (os.path.join(curdir, "patches", series_file),
#                                                                           os.path.join(curdir, "patches")))
exit_if_fail_os_system("QUILT_SERIES=%s QUILT_PATCHES=%s quilt push -a --refresh" % (os.path.join(curdir, "patches", series_file),
                                                                                     os.path.join(curdir, "patches")))

#####################################################################
# Search modifications
#####################################################################
new_section("Modifying search engines")

# Upstream may add new engines over time, but we want any we add to never
# interfere with that, so start us out with a large number with plenty of
# room underneath for upstream.
NEW_ENGINE_IDS_START = 200

def make_new_engine_enum(name, prepop_json):
    enum_name = "SEARCH_ENGINE_%s" % name.split("_")[0].upper()
    data = []
    save = False
    id = 0

    with open("components/search_engines/search_engine_type.h", encoding="UTF-8") as f:
        for line in f:
            if enum_name in line:
                for entry_name in prepop_json["elements"].keys():
                    entry = prepop_json["elements"][entry_name]
                    try:
                        if entry["type"] == enum_name:
                            id = entry["id"]
                    except KeyError as e:
                        print("Engine %s missing 'type'" % entry_name)
                break

            if "SEARCH_ENGINE_MAX" in line:
                save = True
                data.append("  %s,\n" % enum_name)

            data.append(line)

    if save:
        # This increments once per new name, but additional locales use the same type
        global NEW_ENGINE_IDS_START
        NEW_ENGINE_IDS_START += 1

        prepop_json["int_variables"]["kMaxPrepopulatedEngineID"] = NEW_ENGINE_IDS_START
        id = prepop_json["int_variables"]["kMaxPrepopulatedEngineID"]
        # Save the modified file
        with open("components/search_engines/search_engine_type.h", "w", encoding="UTF-8") as f:
            for line in data:
                f.write(line)

    return (enum_name, id)

# // Default (for countries with no better engine set)
# const PrepopulatedEngine* const engines_default[] = {
#     &google,
#     &bing,
#     &yahoo,
# };

# // Note, the below entries are sorted by country code, not the name in comment.
# // Engine selection by country ------------------------------------------------
# // United Arab Emirates
# const PrepopulatedEngine* const engines_AE[] = {
#     &google,
#     &bing,
#     &yahoo,
#     &duckduckgo,
#     &yandex_ru,
# };

# This will help us find the locale so we can match it with our entries.
# For above, it will return "default" and "AE"
cc_locale_finder = re.compile(r'EngineAndTier engines_([A-Z]+)\[\]')
# Finds existing engine entries to delete
cc_mass_engine_finder = re.compile(r'(SearchEngineTier::[A-Za-z]+,)')

# Load JSON
with exit_if_exception():
    with open("%s/data/list.json" % curdir, encoding="UTF-8") as json_data:
        mint_json = json.load(json_data)

    # Load the cc file into an array
    data = []
    with open("components/search_engines/search_engine_countries-inc.cc", encoding="UTF-8") as f:
        for line in f:
            data.append(line)

# Find all lines with engine entries, record their index for removal
strip_lines = []
# remove all pre-existing engines
for index in range(0, len(data)):
    line = data[index]
    res = cc_mass_engine_finder.search(line)
    if res:
        strip_lines.append(index)

# Now remove the lines
strip_lines.sort()
strip_lines.reverse()
for index in strip_lines:
    data.pop(index)

# Now add our selections. All get at least generics, and if there are specific ones,
# generics come last
repopulated = []
for line in data:
    repopulated.append(line)

    if "engines_default[]" in line:
        for entry in mint_json["fallback"]:
            repopulated.append(f"    {{SearchEngineTier::kTopEngines, &{entry}}},\n")


    res = cc_locale_finder.search(line)
    if res:
        code = res[1]
        if code in mint_json["primary"].keys():
            locale_items  = []
            for entry in mint_json["primary"][code] + mint_json["fallback"]:
                if [item for item in locale_items if item.startswith(entry)]:
                    continue
                repopulated.append(f"    {{SearchEngineTier::kTopEngines, &{entry}}},\n")
                locale_items.append(entry)
        else:
            for entry in mint_json["fallback"]:
                repopulated.append(f"    {{SearchEngineTier::kTopEngines, &{entry}}},\n")

with exit_if_exception():
    # Save the modified file
    with open("components/search_engines/search_engine_countries-inc.cc", "w", encoding="UTF-8") as f:
        # for line in data:
        for line in repopulated:
            f.write(line)

with exit_if_exception():
    # The json file has comments which break the parser.
    sanitized = []
    with open("components/search_engines/prepopulated_engines.json", encoding="UTF-8") as json_data:
        for line in json_data:
            if line.strip().startswith("//"):
                continue

            sanitized.append(line)

    prepop_json = json.loads("".join(sanitized))

# # Increment the version code
prepop_json["int_variables"]["kCurrentDataVersion"] += 1

with exit_if_exception():
    new_elements = {}

    def process_entries(entries):
        for engine in entries:
            try:
                match = prepop_json["elements"][engine]
                existing_type = match["type"]
                existing_id = match["id"]
                match = prepop_json["elements"][engine] = {}
                match["type"] = existing_type
                match["id"] = existing_id
            except:
                engine_type_enum, id = make_new_engine_enum(engine, prepop_json)

                match = {}
                prepop_json["elements"][engine] = match # initialize if not exist

                match["type"] = engine_type_enum
                match["id"] = id

            # Some aliasing so extensions folders don't need modifying between ff and chromium.
            ALIASES = {
                # mint_json entry : extensions entry
                "yahoo_ar": "yahoo_esar",
                "yahoo_cl": "yahoo_escl",
                "yahoo_mx": "yahoo_esmx",
                "yahoo_br": "yahoo_pt"
            }

            try:
                aliased_engine = ALIASES[engine]
            except:
                aliased_engine = engine

            # Load JSON
            with open("%s/searchplugins/extensions/%s/manifest.json" %  \
                          (curdir, aliased_engine.replace("_", "-")), encoding="UTF-8") as json_data:
                manifest = json.load(json_data)

            match["name"] = manifest["name"]

            try:
                search_url = "%s?%s" % (manifest["chrome_settings_overrides"]["search_provider"]["search_url"], \
                                        manifest["chrome_settings_overrides"]["search_provider"]["search_url_get_params"])
            except:
                search_url = manifest["chrome_settings_overrides"]["search_provider"]["search_url"]

            match["search_url"] = search_url

            # Not all have suggest_url_get_params
            try:
                suggest_url = "%s?%s" % (manifest["chrome_settings_overrides"]["search_provider"]["suggest_url"], \
                                        manifest["chrome_settings_overrides"]["search_provider"]["suggest_url_get_params"])
            except:
                suggest_url = manifest["chrome_settings_overrides"]["search_provider"]["suggest_url"]

            match["suggest_url"] = suggest_url

            parsed_url = urlparse(search_url)
            match["favicon_url"] = "%s://%s/favicon.ico" % (parsed_url.scheme, parsed_url.netloc)
            # required
            match["keyword"] = manifest["chrome_settings_overrides"]["search_provider"]["keyword"]

            new_elements[engine] = match

    for locale in mint_json["primary"].keys():
        entries = mint_json["primary"][locale]
        process_entries(entries)

    process_entries(mint_json["fallback"])

    # Google needs to be in prepopulated_engines.json even if it's not in
    # template_url_prepopulate_data.cc, or else the build fails. It's hardcoded
    # in multiple locations.
    new_elements["google"] = prepop_json["elements"]["google"]
    new_elements["google"]["keyword"] = "google"

    prepop_json["elements"] = new_elements

with exit_if_exception():
    with open("components/search_engines/prepopulated_engines.json", "w", encoding="UTF-8") as json_file:
        json.dump(prepop_json, json_file, sort_keys=False, indent=2, ensure_ascii=False)

new_section("Prep finished, run build")
