#!/usr/bin/env python
# encoding: utf-8
# Copyright (c) 2019 a1batross

'''
Subproject tool

Helps you have standalone environment for each subproject(subdirectory)

Usage:
		def options(opt):
			opt.load('subproject')

		def configure(conf):
			conf.add_subproject('folder1 folder2')

		def build(bld):
			bld.add_subproject('folder1 folder2')
'''

from waflib import Configure, Logs, Options, Utils
import os, sys

def opt(f):
	"""
	Decorator: attach new option functions to :py:class:`waflib.Options.OptionsContext`.

	:param f: method to bind
	:type f: function
	"""
	setattr(Options.OptionsContext, f.__name__, f)
	return f

def get_waifulib_by_path(path):
	if not os.path.isabs(path):
		path = os.path.abspath(path)
	
	waifulib = os.path.join(path, 'scripts', 'waifulib')
	if os.path.isdir(waifulib):
		return waifulib
	return None

def check_and_add_waifulib(path):
	waifulib = get_waifulib_by_path(path)
	
	if waifulib:
		sys.path.insert(0, waifulib)

def remove_waifulib(path):
	waifulib = get_waifulib_by_path(path)
	
	if waifulib:
		sys.path.remove(waifulib)

@opt
def add_subproject(ctx, names, prepend = None):
	names_lst = Utils.to_list(names)

	for name in names_lst:
		if not os.path.isabs(name):
			# absolute paths only
			wscript_dir = os.path.join(ctx.path.abspath(), name)
		else: wscript_dir = name
		
		wscript_path = os.path.join(wscript_dir, 'wscript')

		if not os.path.isfile(wscript_path):
			# HACKHACK: this way we get warning message right in the help
			# so this just becomes more noticeable
			ctx.add_option_group('Cannot find wscript in ' + wscript_path + '. You probably missed submodule update')
		else:
			check_and_add_waifulib(wscript_dir)
			ctx.recurse(name)
			remove_waifulib(wscript_dir)

def options(opt):
	grp = opt.add_option_group('Subproject options')

	grp.add_option('-S', '--skip-subprojects', action='store', dest = 'SKIP_SUBDIRS', default=None,
		help = 'don\'t recurse into specified subprojects. Use only directory name.')

def get_subproject_env(ctx, path, log=False):
	# remove top dir path
	path = str(path)
	if path.startswith(ctx.top_dir):
		if ctx.top_dir[-1] != os.pathsep:
			path = path[len(ctx.top_dir) + 1:]
		else: path = path[len(ctx.top_dir):]

	# iterate through possible subprojects names
	folders = os.path.normpath(path).split(os.sep)
	# print(folders)
	for i in range(1, len(folders)+1):
		name = folders[-i]
		# print(name)
		if name in ctx.all_envs:
			if log: Logs.pprint('YELLOW', 'env: changed to %s' % name)
			return ctx.all_envs[name]
	if log: Logs.pprint('YELLOW', 'env: changed to default env')
	raise IndexError('top env')

@Configure.conf
def add_subproject(ctx, dirs, prepend = None):
	'''
	Recurse into subproject directory
	
	:param dirs: Directories we recurse into
	:type dirs: array or string
	:param prepend: Prepend virtual path, useful when managing projects with different environments
	:type prepend: string
	
	'''
	if isinstance(ctx, Configure.ConfigurationContext):
		if not ctx.env.IGNORED_SUBDIRS and ctx.options.SKIP_SUBDIRS:
			ctx.env.IGNORED_SUBDIRS = ctx.options.SKIP_SUBDIRS.split(',')

		for prj in Utils.to_list(dirs):
			if ctx.env.SUBPROJECT_PATH:
				subprj_path = list(ctx.env.SUBPROJECT_PATH)
			else:
				subprj_path = []

			if prj in ctx.env.IGNORED_SUBDIRS:
				ctx.msg(msg='--X %s' % '/'.join(subprj_path), result='ignored', color='YELLOW')
				continue
			
			if prepend:
				subprj_path.append(prepend)
			conf_name = prj
			if os.path.isabs(prj):
				conf_name = prj.replace('/','_').replace('\\','_')
			
			subprj_path.append(conf_name)
			
			saveenv = ctx.env
			
			ctx.setenv('_'.join(subprj_path), ctx.env) # derive new env from previous
			
			ctx.env.ENVNAME = prj
			ctx.env.SUBPROJECT_PATH = list(subprj_path)
			
			ctx.msg(msg='--> %s' % '/'.join(subprj_path), result='in progress', color='BLUE')
			check_and_add_waifulib(os.path.join(ctx.path.abspath(), prj))
			ctx.recurse(prj)
			remove_waifulib(os.path.join(ctx.path.abspath(), prj))
			ctx.msg(msg='<-- %s' % '/'.join(subprj_path), result='done', color='BLUE')
			
			ctx.setenv('') # save env changes
			
			ctx.env = saveenv # but use previous
	else:
		if not ctx.all_envs:
			ctx.load_envs()

		for prj in Utils.to_list(dirs):
			if prj in ctx.env.IGNORED_SUBDIRS:
				continue

			if ctx.env.SUBPROJECT_PATH:
				subprj_path = list(ctx.env.SUBPROJECT_PATH)
			else:
				subprj_path = []
			
			if prepend:
				subprj_path.append(prepend)

			conf_name = prj
			if os.path.isabs(prj):
				conf_name = prj.replace('/','_').replace('\\','_')
			
			subprj_path.append(conf_name)
			saveenv = ctx.env
			try:
				ctx.env = ctx.all_envs['_'.join(subprj_path)]
			except:
				ctx.fatal('Can\'t find env cache %s' % '_'.join(subprj_path))
			
			check_and_add_waifulib(os.path.join(ctx.path.abspath(), prj))
			ctx.recurse(prj)
			remove_waifulib(os.path.join(ctx.path.abspath(), prj))
			ctx.env = saveenv
