# from osqp import __path__
from __future__ import print_function
import osqp
import os.path
import shutil as sh
from subprocess import call
from glob import glob
from platform import system
import sys

# import utilities
from . import utils


def codegen(work, target_dir, python_ext_name, project_type, compile_python_ext, embedded,
            force_rewrite, float_flag, long_flag):
    """
    Generate code
    """

    # Import OSQP path
    osqp_path = osqp.__path__[0]

    # Path of osqp module
    files_to_generate_path = os.path.join(osqp_path,
                                          'codegen', 'files_to_generate')

    # Module extension
    if system() == 'Linux' or system() == 'Darwin':
        module_ext = '.so'
    else:
        module_ext = '.pyd'

    # Check if interface already exists
    resp = None   # Initialize response
    if os.path.isdir(target_dir):
        if force_rewrite:
            sh.rmtree(target_dir)
        else:
            while resp != 'n' and resp != 'y':
                resp = input("Directory \"%s\" already exists." %
                             target_dir +
                             " Do you want to replace it? [y/n] ")
                if resp == 'y':
                    sh.rmtree(target_dir)

    # Check if python module already exists
    resp = None  # Initialize response
    if any(glob('%s*%s' % (python_ext_name, module_ext))):
        module_name = glob('%s*%s' % (python_ext_name, module_ext))[0]
        if force_rewrite:
            os.remove(module_name)
        else:
            while resp != 'n' and resp != 'y':
                resp = input("Python module \"%s\" already exists." %
                             module_name +
                             " Do you want to replace it? [y/n] ")
                if resp == 'y':
                    os.remove(module_name)

    # Make target directory
    sys.stdout.write("Creating target directories... \t\t\t\t\t")
    sys.stdout.flush()
    target_dir = os.path.abspath(target_dir)
    target_include_dir = os.path.join(target_dir, 'include')
    target_configure_dir = os.path.join(target_dir, 'configure')
    target_include_dir = os.path.join(target_dir, 'include')
    target_src_dir = os.path.join(target_dir, 'src')

    if not os.path.exists(target_dir):
        os.mkdir(target_dir)
    if not os.path.exists(target_include_dir):
            os.mkdir(target_include_dir)
    if not os.path.exists(target_configure_dir):
            os.mkdir(target_configure_dir)
    if not os.path.exists(target_src_dir):
        os.makedirs(os.path.join(target_src_dir, 'osqp'))
    print("[done]")

    # Copy source files to target directory
    sys.stdout.write("Copying OSQP sources... \t\t\t\t\t")
    sys.stdout.flush()
    c_sources = glob(os.path.join(osqp_path, 'codegen', 'sources',
                                  'src', '*.c'))
    if embedded == 1:
        # Remove kkt.c from embedded sources
        c_sources.remove(os.path.join(osqp_path, 'codegen', 'sources',
                                      'src', 'kkt.c'))
    for source in c_sources:
        sh.copy(source, os.path.join(target_src_dir, 'osqp'))

    # Copy header files
    c_headers = glob(os.path.join(osqp_path, 'codegen', 'sources',
                                  'include', '*.h'))
    if embedded == 1:
        # Remove kkt.h from embedded sources
        c_headers.remove(os.path.join(osqp_path, 'codegen', 'sources',
                                      'include', 'kkt.h'))
    for header in c_headers:
        sh.copy(header, target_include_dir)

    # Copy config files
    c_configs = glob(os.path.join(osqp_path, 'codegen', 'sources',
                                  'configure', '*.h.in'))
    for config in c_configs:
        sh.copy(config, target_configure_dir)

    print("[done]")

    # Variables created from the workspace
    sys.stdout.write("Generating customized code... \t\t\t\t\t")
    sys.stdout.flush()
    template_vars = {'rho_vectors':     work['rho_vectors'],
                     'data':            work['data'],
                     'settings':        work['settings'],
                     'linsys_solver':   work['linsys_solver'],
                     'scaling':         work['scaling'],
                     'embedded_flag':   embedded,
                     'python_ext_name': python_ext_name}

    # Add cmake args
    cmake_args = '-DEMBEDDED:INT=%d -DDFLOAT:BOOL=%s -DDLONG:BOOL=%s' % \
                 (embedded, float_flag, long_flag)

    # Render workspace
    utils.render_workspace(template_vars,
                           os.path.join(target_include_dir, 'workspace.h'),
                           os.path.join(target_src_dir, 'osqp', 'workspace.c'))

    # Render setup.py
    utils.render_setuppy(template_vars,
                         os.path.join(target_src_dir, 'setup.py'))

    # Render emosqpmodule.c
    utils.render_emosqpmodule(template_vars,
                              os.path.join(target_src_dir,
                                           '%smodule.c' % python_ext_name))

    # Render CMakelists.txt
    utils.render_cmakelists(template_vars,
                            os.path.join(target_dir, 'CMakeLists.txt'))

    # Copy cmake files
    sh.copy(os.path.join(osqp_path, 'codegen', 'sources', 'src', 'CMakeLists.txt'),
            os.path.join(target_src_dir, 'osqp'))
    sh.copy(os.path.join(osqp_path, 'codegen', 'sources', 'include', 'CMakeLists.txt'),
            os.path.join(target_include_dir))

    # Copy example.c
    sh.copy(os.path.join(files_to_generate_path, 'example.c'), target_src_dir)

    print("[done]")

    # Create a project
    if project_type != '':
        sys.stdout.write("Creating project...\n")
        sys.stdout.flush()
        current_dir = os.getcwd()
        os.chdir(target_dir)
        if os.path.exists('build'):
            sh.rmtree('build')
        os.makedirs('build')
        os.chdir('build')
        call(['cmake', cmake_args, '-G', project_type, '..'])
        os.chdir(current_dir)
        print("[done]")

    # Compile python interface and copy compiled solver
    if compile_python_ext:
        sys.stdout.write("Compiling Python wrapper... \t\t\t\t\t")
        sys.stdout.flush()
        current_dir = os.getcwd()
        os.chdir(target_src_dir)
        call([sys.executable, 'setup.py', '--quiet', 'build_ext', '--inplace'])
        print("[done]")
        sys.stdout.write("Copying code-generated Python solver to current " +
                         "directory... \t")
        sys.stdout.flush()
        module_name = glob('%s*' % python_ext_name + module_ext)
        if not any(module_name):
            raise ValueError('No Python module generated! ' +
                             'Some errors have occurred.')
        module_name = module_name[0]
        sh.copy(module_name, current_dir)
        os.chdir(current_dir)
        print("[done]")
