#!/usr/bin/python
# __init__.py
# by Walter Dal'Maz Silva
# on 27th September 2016

__version__ = '0.2.0'

# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------

import os
import sys
import glob

# -----------------------------------------------------------------------------
# Class xcompile
# -----------------------------------------------------------------------------

class xcompile:
    def __init__(self, project, compiler='g++', defaults=True):
        self.module_path = project
        self.compiler = compiler
        self.sources, self.includes, self.library = [], [], []
        self.ext_libraries_path, self.ext_libraries, self.options = [], [], []
        if defaults:
            self.includes = [os.path.join(self.module_path, 'include')]
            self.sources = [os.path.join(self.module_path, 'src')]
            self.library = [os.path.join(self.module_path, 'lib')]
        print('\n  Project root directory:\n\t %s\n\n' % self.module_path)

    def _add_to_list(self, content, thelist):
        if type(content) == str: 
            thelist.append(content)
        else:
            for ct in content: thelist.append(ct)

    def add_to_sources(self, sources):
        self._add_to_list(sources, self.sources)

    def add_to_includes(self, includes):
        self._add_to_list(includes, self.includes)

    def add_to_library_path(self, libraries):
        self._add_to_list(libraries, self.ext_libraries_path)

    def add_to_compile_libs(self, libs):
        libs = [''.join(['-l',libn]) for libn in libs]
        self._add_to_list(libs, self.ext_libraries)

    def set_ready(self, notest=False):
        from xutils.xpython.xcompile.__private__ import _get_headers
        from xutils.xpython.xcompile.__private__ import _get_sources
        from xutils.xpython.xcompile.__private__ import _get_headers_in_cpp
        self.hppfiles = [hpp for h in [_get_headers(self.includes)] for hpp in h]
        self.cppfiles = [cpp for c in [_get_sources(self.sources)]  for cpp in c]

        headers_list = list(set(_get_headers_in_cpp(self.cppfiles)))
        headers_found = [os.path.basename(hpp) for hpp in self.hppfiles]
        headers_miss = [head for head in headers_list if head not in headers_found]

        jnt = '\n\t '
        print('\n  Compiling xutils!')
        print('\n  Includes in:\n\t',  jnt.join([inc for inc in self.includes]))
        print('\n  Sources in:\n\t' ,  jnt.join([src for src in self.sources]))
        print('\n  Library in:\n\t',    jnt.join([lib for lib in self.library]))
        print('\n  Files to compile:\n\t', jnt.join([os.path.basename(cpp) for cpp in self.cppfiles]))
        print('\n  Required headers:\n\t', jnt.join([str(rhpp) for rhpp in headers_list]))
        if len(headers_miss) > 0: 
            print('\n  Missing headers:\n\t', jnt.join([str(hpp) for hpp in headers_miss]))
            # TODO allow relative path search in includes to fix this
            if not notest:
                print('\n  Cannot proceed with compilation...')
                exit()
        print('\n\n')

    def xcompile(self, comptype='OBJECT', target=None, install=None, extension='.application'):
        from xutils.xpython.xcompile.__private__ import _compile
        if (comptype != 'OBJECT')  and (target is None):
            sys.exit('\n  Must specify a target for Non-OBJECT compilation')

        cmddict = {'comptype': comptype}
        cmddict['modulept'] = self.module_path
        cmddict['compiler'] = self.compiler
        cmddict['includes'] = self.includes

        if comptype == 'OBJECT':
            print('\n  Compiling OBJECT')
            cmddict['cxxflags'] = ['-std=c++11', '-c', '-fPIC', '-O3', '-Wall', '-Werror']
            for cpp in self.cppfiles:
                print(cpp)
                obj = os.path.join(os.path.dirname(cpp), '.'.join([str(os.path.basename(cpp)).split('.')[0], 'o']))
                cmddict['filename'] = cpp
                cmddict['targetfi'] = obj
                _compile(cmddict, check=True, ext='o')
            return # Stop execution here

        elif comptype == 'LIBRARY':
            print('\n  Compiling LIBRARY')
            libname = ''.join(['lib', target, '.so'])
            cmddict['cxxflags'] = ['-shared'] #, '-g', '-pthread']
            cmddict['targetfi'] = os.path.join(self.library[0], libname)
            cmddict['objects']  = [obj for src in self.sources for obj in sorted(glob.glob('/'.join([src, r'*.o'])))]
            cmddict['libraries'] = self.ext_libraries_path
            cmddict['libnames']  = self.ext_libraries
            _compile(cmddict, check=True, ext='.so')

        elif comptype == 'EXECUTABLE':
            print('\n  Compiling EXECUTABLE')
            libname = ''.join([target, extension])
            cmddict['cxxflags']  = []
            cmddict['targetfi']  = os.path.join(self.module_path, libname)
            cmddict['linkflags'] = ['-g', '-pthread']
            cmddict['libraries'] = self.ext_libraries_path
            cmddict['libnames']  = self.ext_libraries
            cmddict['objects']   = [obj for src in self.sources for obj in sorted(glob.glob('/'.join([src, r'*.o'])))]
            _compile(cmddict, check=True, ext='.exe')

        else:
            sys.exit('\n  Unknown compilation flag')

        # Install
        if (install is not None) and (comptype != 'OBJECT'):
            link = os.path.join(install, libname)
            if os.path.isfile(link): 
                print('\nRemoving outdated version')
                os.unlink(link)

            print('\nInstalling library to', install,'\n\n')
            os.symlink(cmddict['targetfi'], link)

            if install not in os.environ['LD_LIBRARY_PATH']:
                print('\nAdd the following to your .bashrc file:\n\n')
                print(''.join(['export LD_LIBRARY_PATH="',install,':${LD_LIBRARY_PATH}"\n\n']))

# -----------------------------------------------------------------------------
# EOF
# -----------------------------------------------------------------------------
