"""
Copyright (C) 2018 Intel Corporation

SPDX-License-Identifier: MIT
"""
import os

from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, QFileDialog, QMessageBox, QLabel, QCheckBox

import tool
from tool import utils
from tool.core import build, generate_script


class Controller(QWidget):
    def change_state(function):
        def wrapper(self, *args):
            function(self, *args)
            self.check_current_state()

        return wrapper

    def __init__(self, parent, settings, left_side_menu, right_side_menu):
        super().__init__()
        self.parent     = parent
        self.settings   = settings
        self.left       = left_side_menu
        self.right      = right_side_menu

        self.to_right = QPushButton('>>')
        self.to_left  = QPushButton('<<')

        layout = QVBoxLayout()
        layout.addWidget(self.to_right)
        layout.addWidget(self.to_left)
        self.setLayout(layout)

        self.status_message = QLabel()
        self.parent.statusBar().addWidget(self.status_message)

        self.to_right.pressed.connect(self.on_right_press)
        self.to_left.pressed.connect(self.on_left_press)
        self.settings.package_changed.connect(self.check_current_state)
        self.left.autobuild.connect(self.autobuild)
        self.right.save_script.connect(self.save_build_script)

        self.settings.init_settings()

    @change_state
    def on_right_press(self):
        function = self.left.functions_list.currentItem()
        if function:
            self.left.remove_function(function.text())
            self.right.add_function(function.text())

    @change_state
    def on_left_press(self):
        function = self.right.functions_list.currentItem()
        if function:
            self.right.remove_function(function.text())
            self.left.add_function(function.text())

    def check_current_state(self):
        state = self.get_current_state()

        if state == utils.ENABLE_GENERATION_RULES:
            self.enable_generation(True)
            self.status_message.setText("Ready to build custom library")
        else:
            self.enable_generation(False)
            differences = dict(utils.ENABLE_GENERATION_RULES.items() - state.items())
            self.status_message.setText("Select " + sorted(differences, key=len)[0])

    def enable_generation(self, flag):
        self.left.autobuild_button.setEnabled(flag)
        self.right.save_script_button.setEnabled(flag)

    def autobuild(self):
        self.get_selected_configs()

        extension = 'Dynamic library (*' + utils.DYNAMIC_LIB_EXTENSION[utils.HOST_SYSTEM] + ')'
        chosen_path = QFileDialog.getSaveFileName(self,
                                                  'Save custom library as...',
                                                  utils.CONFIGS[utils.CUSTOM_LIBRARY_NAME],
                                                  extension)[0]
        if not chosen_path:
            return
        else:
            utils.CONFIGS[utils.CUSTOM_LIBRARY_NAME] = os.path.basename(os.path.splitext(chosen_path)[0])
            utils.CONFIGS[utils.OUTPUT_PATH]         = os.path.dirname(chosen_path)

        self.parent.setDisabled(True)
        QMessageBox.information(self,
                                'Build',
                                'Building will start after this window is closed. '
                                'Please, wait until process is done.')
        success = build()
        QMessageBox.information(self,
                                'Success' if success else 'Failure',
                                'Build completed!' if success else 'Build failed!')
        self.parent.setDisabled(False)

    def save_build_script(self):
        self.get_selected_configs()

        extension = 'Script (*' + utils.BATCH_EXTENSIONS[utils.HOST_SYSTEM] + ')'
        script_path = QFileDialog.getSaveFileName(self,
                                                  'Save build script as...',
                                                  utils.CONFIGS[utils.BUILD_SCRIPT_NAME],
                                                  extension)[0]
        if not script_path:
            return
        else:
            utils.CONFIGS[utils.BUILD_SCRIPT_NAME] = os.path.basename(os.path.splitext(script_path)[0] +
                                                                      utils.BATCH_EXTENSIONS[utils.HOST_SYSTEM])
            utils.CONFIGS[utils.OUTPUT_PATH]       = os.path.dirname(script_path)

        success = generate_script()
        QMessageBox.information(self,
                                'Success' if success else 'Failure',
                                'Generation completed!' if success else 'Generation failed!')

    def get_current_state(self):
        return {utils.HAVE_PACKAGE   : not self.settings.package.broken,
                utils.HAVE_FUNCTIONS : bool(self.right.functions_list.count())}

    def get_selected_configs(self):
        """
        Collecting all user-specified information about future dynamic library into dictionary
        """
        if not self.settings.package.broken:
            custom_library_name = (self.right.lib_name.text() if self.right.lib_name.text() else
                                   utils.CONFIGS[utils.CUSTOM_LIBRARY_NAME])
            functions_list = []
            for i in range(self.right.functions_list.count()):
                functions_list.append(self.right.functions_list.item(i).text())

            architecture = (utils.IA32 if self.settings.ia32.isChecked() else utils.INTEL64)
            thread_mode  = (utils.SINGLE_THREADED if self.settings.single_threaded.isChecked() else utils.MULTI_THREADED)

            if self.settings.tbb.isChecked():
                tl_type = utils.TBB
            elif self.settings.omp.isChecked():
                tl_type = utils.OPENMP
            else:
                tl_type = ''

            custom_cpu_set = [self.settings.get_formatted_button_name(cpu)
                              for cpu in self.settings.custom_dispatch.findChildren(QCheckBox) if cpu.isChecked()]

            utils.set_configs_dict(package=self.settings.package,
                                   functions_list=functions_list,
                                   architecture=architecture,
                                   thread_mode=thread_mode,
                                   threading_layer_type=tl_type,
                                   custom_library_name=custom_library_name,
                                   custom_cpu_set=custom_cpu_set)

    @change_state
    def set_configs(self, configs):
        self.settings.package = tool.package.Package(configs[utils.PACKAGE])
        self.settings.init_settings()

        if configs[utils.ARCHITECTURE] == utils.IA32:
            self.settings.ia32.setChecked(True)
        if configs[utils.ARCHITECTURE] == utils.INTEL64:
            self.settings.intel64.setChecked(True)

        if configs[utils.THREAD_MODE] == utils.SINGLE_THREADED:
            self.settings.single_threaded.setChecked(True)
        if configs[utils.THREAD_MODE] == utils.MULTI_THREADED:
            self.settings.multi_threaded.setChecked(True)

        if configs[utils.THREADING_LAYER] == utils.TBB:
            self.settings.tbb.setChecked(True)
        if configs[utils.THREADING_LAYER] == utils.OPENMP:
            self.settings.omp.setChecked(True)

        if configs[utils.CUSTOM_CPU_SET]:
            self.settings.custom_dispatch.setChecked(True)
            self.settings.on_switch_custom_dispatch()
            for cpu in self.settings.custom_dispatch.findChildren(QCheckBox):
                cpu_name = self.settings.get_formatted_button_name(cpu)
                if cpu_name in configs[utils.CUSTOM_CPU_SET]:
                    cpu.setChecked(True)

        self.right.lib_name.setText(configs[utils.CUSTOM_LIBRARY_NAME])

        self.right.reset()
        for function in configs[utils.FUNCTIONS_LIST]:
            self.left.remove_function(function)
            self.right.add_function(function)
