# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import string
import sys


def usage():
    print(
        """
%s template_file -t unit_tests... -e extra_protocols...

  TEMPLATE_FILE is used to generate to generate the unit-tester .cpp
  UNIT_TESTS are the top-level protocols defining unit tests
  EXTRA_PROTOCOLS are top-level protocols for subprocesses that can be
                  spawned in tests but are not unit tests in and of
                  themselves
"""
        % (sys.argv[0]),
        file=sys.stderr,
    )
    sys.exit(1)


def main(argv):
    template = argv[1]

    if argv[2] != "-t":
        usage()
    i = 3
    unittests = []
    while argv[i] != "-e":
        unittests.append(argv[i])
        i += 1

    extras = argv[(i + 1) :]

    includes = "\n".join(['#include "%s.h"' % (t) for t in unittests])

    enum_values = "\n".join(["    %s," % (t) for t in unittests + extras])
    last_enum = unittests[-1]

    string_to_enums = "\n".join(
        [
            """    else if (!strcmp(aString, "%s"))
        return %s;"""
            % (t, t)
            for t in unittests + extras
        ]
    )

    enum_to_strings = "\n".join(
        [
            """    case %s:
        return "%s";"""
            % (t, t)
            for t in unittests + extras
        ]
    )

    parent_delete_cases = "\n".join(
        [
            """    case %s: {
           delete reinterpret_cast<%sParent*>(gParentActor);
           return;
       }
"""
            % (t, t)
            for t in unittests
        ]
    )

    parent_enabled_cases_proc = "\n".join(
        [
            """    case %s: {
        if (!%sParent::RunTestInProcesses()) {
            passed("N/A to proc");
            DeferredParentShutdown();
            return;
        }
        break;
       }
"""
            % (t, t)
            for t in unittests
        ]
    )

    parent_main_cases_proc = "\n".join(
        [
            """    case %s: {
        %sParent** parent =
        reinterpret_cast<%sParent**>(&gParentActor);
        *parent = new %sParent();
        (*parent)->Open(transport, child);
        return (*parent)->Main();
        }
"""
            % (t, t, t, t)
            for t in unittests
        ]
    )

    parent_enabled_cases_thread = "\n".join(
        [
            """    case %s: {
        if (!%sParent::RunTestInThreads()) {
            passed("N/A to threads");
            DeferredParentShutdown();
            return;
        }
        break;
       }
"""
            % (t, t)
            for t in unittests
        ]
    )

    parent_main_cases_thread = "\n".join(
        [
            """    case %s: {
        %sParent** parent =
        reinterpret_cast<%sParent**>(&gParentActor);
        *parent = new %sParent();

        %sChild** child =
        reinterpret_cast<%sChild**>(&gChildActor);
        *child = new %sChild();

        ::mozilla::ipc::MessageChannel *childChannel = (*child)->GetIPCChannel();
        ::mozilla::ipc::Side parentSide =
            ::mozilla::ipc::ParentSide;

        (*parent)->Open(childChannel, childMessageLoop, parentSide);
        return (*parent)->Main();
        }
"""
            % (t, t, t, t, t, t, t)
            for t in unittests
        ]
    )

    child_delete_cases = "\n".join(
        [
            """    case %s: {
           delete reinterpret_cast<%sChild*>(gChildActor);
           return;
       }
"""
            % (t, t)
            for t in unittests + extras
        ]
    )

    child_init_cases = "\n".join(
        [
            """    case %s: {
        %sChild** child =
            reinterpret_cast<%sChild**>(&gChildActor);
        *child = new %sChild();
        (*child)->Open(transport, parentPid, worker);
        return;
    }
"""
            % (t, t, t, t)
            for t in unittests + extras
        ]
    )

    templatefile = open(template, "r", encoding="utf-8")
    sys.stdout.write(
        string.Template(templatefile.read()).substitute(
            INCLUDES=includes,
            ENUM_VALUES=enum_values,
            LAST_ENUM=last_enum,
            STRING_TO_ENUMS=string_to_enums,
            ENUM_TO_STRINGS=enum_to_strings,
            PARENT_DELETE_CASES=parent_delete_cases,
            PARENT_ENABLED_CASES_PROC=parent_enabled_cases_proc,
            PARENT_MAIN_CASES_PROC=parent_main_cases_proc,
            PARENT_ENABLED_CASES_THREAD=parent_enabled_cases_thread,
            PARENT_MAIN_CASES_THREAD=parent_main_cases_thread,
            CHILD_DELETE_CASES=child_delete_cases,
            CHILD_INIT_CASES=child_init_cases,
        )
    )
    templatefile.close()


if __name__ == "__main__":
    main(sys.argv)
