#!/usr/bin/env python

# Copyright JS Foundation and other contributors, http://js.foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import fnmatch
import os

def build_soft_links(project_path, jerry_path):
    """ Creates soft links into the @project_path. """

    if not os.path.exists(project_path):
        os.makedirs(project_path)

    links = [
        { # arc
            'src': os.path.join('targets', 'baremetal-sdk', 'curie-bsp', 'jerry_app', 'arc'),
            'link_name': 'arc'
        },
        { # include
            'src': os.path.join('targets', 'baremetal-sdk', 'curie-bsp', 'jerry_app', 'include'),
            'link_name': 'include'
        },
        { # quark
            'src': os.path.join('targets', 'baremetal-sdk', 'curie-bsp', 'jerry_app', 'quark'),
            'link_name': 'quark'
        },
        { # quark/jerryscript
            'src': jerry_path,
            'link_name': os.path.join('quark', 'jerryscript')
        }
    ]

    for link in links:
        src = os.path.join(jerry_path, link['src'])
        link_name = os.path.join(project_path, link['link_name'])
        if not os.path.islink(link_name):
            os.symlink(src, link_name)
            print("Created symlink '{link_name}' -> '{src}'".format(src=src, link_name=link_name))


def find_sources(root_dir, sub_dir):
    """
    Find .c and .S files inside the @root_dir/@sub_dir directory.
    Note: the returned paths will be relative to the @root_dir directory.
    """
    src_dir = os.path.join(root_dir, sub_dir)

    matches = []
    for root, dirnames, filenames in os.walk(src_dir):
        for filename in fnmatch.filter(filenames, '*.[c|S]'):
            file_path = os.path.join(root, filename)
            relative_path = os.path.relpath(file_path, root_dir)
            matches.append(relative_path)

    return matches


def build_jerry_data(jerry_path):
    """
    Build up a dictionary which contains the following items:
     - sources: list of JerryScript sources which should be built.
     - dirs: list of JerryScript dirs used.
     - cflags: CFLAGS for the build.
    """
    jerry_sources = []
    jerry_dirs = set()
    for sub_dir in ['jerry-core', 'jerry-math', os.path.join('targets', 'baremetal-sdk', 'curie-bsp', 'source')]:
        for file in find_sources(os.path.normpath(jerry_path), sub_dir):
            path = os.path.join('jerryscript', file)
            jerry_sources.append(path)
            jerry_dirs.add(os.path.split(path)[0])

    jerry_cflags = [
        '-DJERRY_GLOBAL_HEAP_SIZE=10',
        '-DJERRY_NDEBUG',
        '-DJERRY_DISABLE_HEAVY_DEBUG',
        '-DJERRY_BUILTIN_NUMBER=0',
        '-DJERRY_BUILTIN_STRING=0',
        '-DJERRY_BUILTIN_BOOLEAN=0',
        #'-DJERRY_BUILTIN_ERRORS=0',
        '-DJERRY_BUILTIN_ARRAY=0',
        '-DJERRY_BUILTIN_MATH=0',
        '-DJERRY_BUILTIN_JSON=0',
        '-DJERRY_BUILTIN_DATE=0',
        '-DJERRY_BUILTIN_REGEXP=0',
        '-DJERRY_BUILTIN_ANNEXB=0',
        '-DJERRY_ESNEXT=0',
        '-DJERRY_LCACHE=0',
        '-DJERRY_PROPERTY_HASHMAP=0',
    ]

    return {
        'sources': jerry_sources,
        'dirs': jerry_dirs,
        'cflags': jerry_cflags,
    }


def write_file(path, content):
    """ Writes @content into the file at specified by the @path. """
    norm_path = os.path.normpath(path)
    with open(norm_path, "w+") as f:
        f.write(content)
    print("Wrote file '{0}'".format(norm_path))


def build_obj_y(source_list):
    """
    Build obj-y additions from the @source_list.
    Note: the input sources should have their file extensions.
    """
    return '\n'.join(['obj-y += {0}.o'.format(os.path.splitext(fname)[0]) for fname in source_list])


def build_cflags_y(cflags_list):
    """
    Build cflags-y additions from the @cflags_list.
    Note: the input sources should have their file extensions.
    """
    return '\n'.join(['cflags-y += {0}'.format(cflag) for cflag in cflags_list])


def build_mkdir(dir_list):
    """ Build mkdir calls for each dir in the @dir_list. """
    return '\n'.join(['\t$(AT)mkdir -p {0}'.format(os.path.join('$(OUT_SRC)', path)) for path in dir_list])


def create_root_kbuild(project_path):
    """ Creates @project_path/Kbuild.mk file. """

    root_kbuild_path = os.path.join(project_path, 'Kbuild.mk')
    root_kbuild_content = '''
obj-$(CONFIG_QUARK_SE_ARC) += arc/
obj-$(CONFIG_QUARK_SE_QUARK) += quark/
'''
    write_file(root_kbuild_path, root_kbuild_content)


def create_root_makefile(project_path):
    """ Creates @project_path/Makefile file. """

    root_makefile_path = os.path.join(project_path, 'Makefile')
    root_makefile_content = '''
THIS_DIR   := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
T          := $(abspath $(THIS_DIR)/../..)
PROJECT    := {project_name}
BOARD        := curie_101
ifeq ($(filter curie_101, $(BOARD)),)
$(error The curie jerry sample application can only run on the curie_101 Board)
endif
BUILDVARIANT ?= debug
quark_DEFCONFIG = $(PROJECT_PATH)/quark/defconfig
arc_DEFCONFIG = $(PROJECT_PATH)/arc/defconfig

# Optional: set the default version
VERSION_MAJOR  := 1
VERSION_MINOR  := 0
VERSION_PATCH  := 0
include $(T)/build/project.mk
'''.format(project_name=project_name)

    write_file(root_makefile_path, root_makefile_content)


def create_arc_kbuild(project_path):
    """ Creates @project_path/arc/Kbuild.mk file. """

    arc_path = os.path.join(project_path, 'arc')
    arc_kbuild_path = os.path.join(arc_path, 'Kbuild.mk')
    arc_sources = find_sources(arc_path, '.')
    arc_kbuild_content = build_obj_y(arc_sources)

    write_file(arc_kbuild_path, arc_kbuild_content)


def create_quark_kbuild(project_path, jerry_path):
    """ Creates @project_path/quark/Kbuild.mk file. """
    quark_kbuild_path = os.path.join(project_path, 'quark', 'Kbuild.mk')

    # Extract a few JerryScript related data
    jerry_data = build_jerry_data(jerry_path)
    jerry_objects = build_obj_y(jerry_data['sources'])
    jerry_defines = jerry_data['cflags']
    jerry_build_dirs = build_mkdir(jerry_data['dirs'])

    quark_include_paths = [
        'include',
        'jerryscript',
        os.path.join('jerryscript', 'jerry-math', 'include'),
        os.path.join('jerryscript', 'targets', 'baremetal-sdk', 'curie-bsp', 'include')
    ] + list(jerry_data['dirs'])

    quark_includes = [
        '-Wno-error',
    ] + ['-I%s' % os.path.join(project_path, 'quark', path) for path in quark_include_paths]

    quark_cflags = build_cflags_y(jerry_defines + quark_includes)

    quark_kbuild_content = '''
{cflags}

obj-y += main.o
{objects}

build_dirs:
{dirs}

$(OUT_SRC): build_dirs
'''.format(objects=jerry_objects, cflags=quark_cflags, dirs=jerry_build_dirs)

    write_file(quark_kbuild_path, quark_kbuild_content)


def main(curie_path, project_name, jerry_path):
    project_path = os.path.join(curie_path, 'wearable_device_sw', 'projects', project_name)

    build_soft_links(project_path, jerry_path)

    create_root_kbuild(project_path)
    create_root_makefile(project_path)
    create_arc_kbuild(project_path)
    create_quark_kbuild(project_path, jerry_path)


if __name__ == '__main__':
    import sys

    if len(sys.argv) != 2:
        print('Usage:')
        print('{script_name} [full or relative path of Curie_BSP]'.format(script_name=sys.argv[0]))
        sys.exit(1)

    project_name = 'curie_bsp_jerry'

    file_dir = os.path.dirname(os.path.abspath(__file__))
    jerry_path = os.path.join(file_dir, "..", "..", "..")
    curie_path = os.path.join(os.getcwd(), sys.argv[1])

    main(curie_path, project_name, jerry_path)

[((58, 14, 58, 45), 'os.path.join', 'os.path.join', ({(58, 27, 58, 35): 'root_dir', (58, 37, 58, 44): 'sub_dir'}, {}), '(root_dir, sub_dir)', False, 'import os\n'), ((61, 37, 61, 53), 'os.walk', 'os.walk', ({(61, 45, 61, 52): 'src_dir'}, {}), '(src_dir)', False, 'import os\n'), ((113, 16, 113, 38), 'os.path.normpath', 'os.path.normpath', ({(113, 33, 113, 37): 'path'}, {}), '(path)', False, 'import os\n'), ((143, 23, 143, 62), 'os.path.join', 'os.path.join', ({(143, 36, 143, 48): 'project_path', (143, 50, 143, 61): '"""Kbuild.mk"""'}, {}), "(project_path, 'Kbuild.mk')", False, 'import os\n'), ((154, 25, 154, 63), 'os.path.join', 'os.path.join', ({(154, 38, 154, 50): 'project_path', (154, 52, 154, 62): '"""Makefile"""'}, {}), "(project_path, 'Makefile')", False, 'import os\n'), ((180, 15, 180, 48), 'os.path.join', 'os.path.join', ({(180, 28, 180, 40): 'project_path', (180, 42, 180, 47): '"""arc"""'}, {}), "(project_path, 'arc')", False, 'import os\n'), ((181, 22, 181, 57), 'os.path.join', 'os.path.join', ({(181, 35, 181, 43): 'arc_path', (181, 45, 181, 56): '"""Kbuild.mk"""'}, {}), "(arc_path, 'Kbuild.mk')", False, 'import os\n'), ((190, 24, 190, 72), 'os.path.join', 'os.path.join', ({(190, 37, 190, 49): 'project_path', (190, 51, 190, 58): '"""quark"""', (190, 60, 190, 71): '"""Kbuild.mk"""'}, {}), "(project_path, 'quark', 'Kbuild.mk')", False, 'import os\n'), ((227, 19, 227, 91), 'os.path.join', 'os.path.join', ({(227, 32, 227, 42): 'curie_path', (227, 44, 227, 64): '"""wearable_device_sw"""', (227, 66, 227, 76): '"""projects"""', (227, 78, 227, 90): 'project_name'}, {}), "(curie_path, 'wearable_device_sw', 'projects', project_name)", False, 'import os\n'), ((248, 17, 248, 57), 'os.path.join', 'os.path.join', ({(248, 30, 248, 38): 'file_dir', (248, 40, 248, 44): '""".."""', (248, 46, 248, 50): '""".."""', (248, 52, 248, 56): '""".."""'}, {}), "(file_dir, '..', '..', '..')", False, 'import os\n'), ((23, 11, 23, 39), 'os.path.exists', 'os.path.exists', ({(23, 26, 23, 38): 'project_path'}, {}), '(project_path)', False, 'import os\n'), ((24, 8, 24, 33), 'os.makedirs', 'os.makedirs', ({(24, 20, 24, 32): 'project_path'}, {}), '(project_path)', False, 'import os\n'), ((46, 14, 46, 51), 'os.path.join', 'os.path.join', ({(46, 27, 46, 37): 'jerry_path', (46, 39, 46, 50): "link['src']"}, {}), "(jerry_path, link['src'])", False, 'import os\n'), ((47, 20, 47, 65), 'os.path.join', 'os.path.join', ({(47, 33, 47, 45): 'project_path', (47, 47, 47, 64): "link['link_name']"}, {}), "(project_path, link['link_name'])", False, 'import os\n'), ((62, 24, 62, 60), 'fnmatch.filter', 'fnmatch.filter', ({(62, 39, 62, 48): 'filenames', (62, 50, 62, 59): '"""*.[c|S]"""'}, {}), "(filenames, '*.[c|S]')", False, 'import fnmatch\n'), ((79, 48, 79, 111), 'os.path.join', 'os.path.join', ({(79, 61, 79, 70): '"""targets"""', (79, 72, 79, 87): '"""baremetal-sdk"""', (79, 89, 79, 100): '"""curie-bsp"""', (79, 102, 79, 110): '"""source"""'}, {}), "('targets', 'baremetal-sdk', 'curie-bsp', 'source')", False, 'import os\n'), ((243, 8, 243, 19), 'sys.exit', 'sys.exit', ({(243, 17, 243, 18): '(1)'}, {}), '(1)', False, 'import sys\n'), ((247, 31, 247, 56), 'os.path.abspath', 'os.path.abspath', ({(247, 47, 247, 55): '__file__'}, {}), '(__file__)', False, 'import os\n'), ((249, 30, 249, 41), 'os.getcwd', 'os.getcwd', ({}, {}), '()', False, 'import os\n'), ((28, 19, 28, 92), 'os.path.join', 'os.path.join', ({(28, 32, 28, 41): '"""targets"""', (28, 43, 28, 58): '"""baremetal-sdk"""', (28, 60, 28, 71): '"""curie-bsp"""', (28, 73, 28, 84): '"""jerry_app"""', (28, 86, 28, 91): '"""arc"""'}, {}), "('targets', 'baremetal-sdk', 'curie-bsp', 'jerry_app', 'arc')", False, 'import os\n'), ((32, 19, 32, 96), 'os.path.join', 'os.path.join', ({(32, 32, 32, 41): '"""targets"""', (32, 43, 32, 58): '"""baremetal-sdk"""', (32, 60, 32, 71): '"""curie-bsp"""', (32, 73, 32, 84): '"""jerry_app"""', (32, 86, 32, 95): '"""include"""'}, {}), "('targets', 'baremetal-sdk', 'curie-bsp', 'jerry_app', 'include')", False, 'import os\n'), ((36, 19, 36, 94), 'os.path.join', 'os.path.join', ({(36, 32, 36, 41): '"""targets"""', (36, 43, 36, 58): '"""baremetal-sdk"""', (36, 60, 36, 71): '"""curie-bsp"""', (36, 73, 36, 84): '"""jerry_app"""', (36, 86, 36, 93): '"""quark"""'}, {}), "('targets', 'baremetal-sdk', 'curie-bsp', 'jerry_app', 'quark')", False, 'import os\n'), ((41, 25, 41, 61), 'os.path.join', 'os.path.join', ({(41, 38, 41, 45): '"""quark"""', (41, 47, 41, 60): '"""jerryscript"""'}, {}), "('quark', 'jerryscript')", False, 'import os\n'), ((48, 15, 48, 40), 'os.path.islink', 'os.path.islink', ({(48, 30, 48, 39): 'link_name'}, {}), '(link_name)', False, 'import os\n'), ((49, 12, 49, 38), 'os.symlink', 'os.symlink', ({(49, 23, 49, 26): 'src', (49, 28, 49, 37): 'link_name'}, {}), '(src, link_name)', False, 'import os\n'), ((63, 24, 63, 52), 'os.path.join', 'os.path.join', ({(63, 37, 63, 41): 'root', (63, 43, 63, 51): 'filename'}, {}), '(root, filename)', False, 'import os\n'), ((64, 28, 64, 64), 'os.path.relpath', 'os.path.relpath', ({(64, 44, 64, 53): 'file_path', (64, 55, 64, 63): 'root_dir'}, {}), '(file_path, root_dir)', False, 'import os\n'), ((80, 33, 80, 61), 'os.path.normpath', 'os.path.normpath', ({(80, 50, 80, 60): 'jerry_path'}, {}), '(jerry_path)', False, 'import os\n'), ((81, 19, 81, 52), 'os.path.join', 'os.path.join', ({(81, 32, 81, 45): '"""jerryscript"""', (81, 47, 81, 51): 'file'}, {}), "('jerryscript', file)", False, 'import os\n'), ((201, 8, 201, 60), 'os.path.join', 'os.path.join', ({(201, 21, 201, 34): '"""jerryscript"""', (201, 36, 201, 48): '"""jerry-math"""', (201, 50, 201, 59): '"""include"""'}, {}), "('jerryscript', 'jerry-math', 'include')", False, 'import os\n'), ((202, 8, 202, 87), 'os.path.join', 'os.path.join', ({(202, 21, 202, 34): '"""jerryscript"""', (202, 36, 202, 45): '"""targets"""', (202, 47, 202, 62): '"""baremetal-sdk"""', (202, 64, 202, 75): '"""curie-bsp"""', (202, 77, 202, 86): '"""include"""'}, {}), "('jerryscript', 'targets', 'baremetal-sdk', 'curie-bsp', 'include')", False, 'import os\n'), ((137, 51, 137, 83), 'os.path.join', 'os.path.join', ({(137, 64, 137, 76): '"""$(OUT_SRC)"""', (137, 78, 137, 82): 'path'}, {}), "('$(OUT_SRC)', path)", False, 'import os\n'), ((207, 18, 207, 59), 'os.path.join', 'os.path.join', ({(207, 31, 207, 43): 'project_path', (207, 45, 207, 52): '"""quark"""', (207, 54, 207, 58): 'path'}, {}), "(project_path, 'quark', path)", False, 'import os\n'), ((83, 27, 83, 46), 'os.path.split', 'os.path.split', ({(83, 41, 83, 45): 'path'}, {}), '(path)', False, 'import os\n'), ((124, 46, 124, 69), 'os.path.splitext', 'os.path.splitext', ({(124, 63, 124, 68): 'fname'}, {}), '(fname)', False, 'import os\n')]