# =============================================================================
#
#  Copyright (c) Kitware, Inc.
#  All rights reserved.
#  See LICENSE.txt for details.
#
#  This software is distributed WITHOUT ANY WARRANTY; without even
#  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#  PURPOSE.  See the above copyright notice for more information.
#
# =============================================================================

import os
import shutil
import sys

import smtk
import smtk.attribute
import smtk.operation
import smtk.project
import smtk.resource
import smtk.testing

PROJECT_NAME = 'foam.windtunnel'
OP_SUCCEEDED = int(smtk.operation.Operation.Outcome.SUCCEEDED)


class TestSolverOp(smtk.testing.TestCase):
    def setUp(self):
        smtk.workflows_folder = os.path.join(smtk.testing.SOURCE_DIR, 'simulation-workflows')

        # Initialize resource & operation managers
        self.res_manager = smtk.resource.Manager.create()
        self.op_manager = smtk.operation.Manager.create()

        smtk.attribute.Registrar.registerTo(self.res_manager)
        smtk.attribute.Registrar.registerTo(self.op_manager)

        smtk.operation.Registrar.registerTo(self.op_manager)
        self.op_manager.registerResourceManager(self.res_manager)

        self.proj_manager = smtk.project.Manager.create(self.res_manager, self.op_manager)
        smtk.project.Registrar.registerTo(self.proj_manager)

        self.proj_manager.registerProject(PROJECT_NAME, set(), set(), '1.0.0')

        self.project_dir = os.path.join(smtk.testing.TEMP_DIR, 'python', 'test_create')

        self.managers = smtk.common.Managers.create()
        self.managers.insert_or_assign(self.res_manager)
        self.managers.insert_or_assign(self.op_manager)
        self.managers.insert_or_assign(self.proj_manager)
        self.op_manager.setManagers(self.managers)

    def tearDown(self):
        self.res_manager = None
        self.op_manager = None
        self.proj_manager = None

    def test_icoFoam(self):
        project = self._read_project()
        solver = 'icoFoam'
        self._set_analysis(project, solver)
        self._solver_setup(project, solver)

    # def test_simpleFoam(self):
    #     project = self._read_project()
    #     solver = 'simpleFoam'
    #     self._set_analysis(project, solver)

    #     # Set turbulence model
    #     att_resource_set = project.resources().findByRole('attributes')
    #     att_resource = att_resource_set.pop()
    #     turb_att = att_resource.findAttribute('TurbulenceModel')
    #     turb_item = turb_att.findString('TurbulenceModel')
    #     turb_item.setValue('RAS')

    #     self._solver_setup(project, solver)

    def _read_project(self):
        """"""
        # Read the project generated by the setup_project test
        project_file = os.path.join(self.project_dir, 'test_create.project.smtk')

        read_op = self.op_manager.createOperation('smtk::project::Read')
        read_op.parameters().findFile('filename').setValue(project_file)
        read_result = read_op.operate()
        read_outcome = read_result.findInt('outcome').value()
        self.assertEqual(read_outcome, OP_SUCCEEDED, 'read project outcome {}'.format(read_outcome))

        project = read_result.findResource('resourcesCreated').value()
        self.assertIsNotNone(project, 'project is null')

        return project

    def _set_analysis(self, project, solver):
        """"""
        att_resource_set = project.resources().findByRole('attributes')
        att_resource = att_resource_set.pop()
        analysis_att = att_resource.findAttribute('Analysis')
        analysis_item = analysis_att.findString('Analysis')
        analysis_item.setValue(solver)

    def _solver_setup(self, project, solver):
        # Import the test operation (solver)
        import_op = self.op_manager.createOperation('smtk::operation::ImportPythonOperation')
        self.assertIsNotNone(import_op)

        relative_path = 'smtk/simulation/windtunnel/operations/{}.py'.format(solver.lower())
        path = os.path.join(smtk.testing.SOURCE_DIR, relative_path)
        self.assertTrue(os.path.exists(path), 'operation file not found: {}'.format(path))

        import_op.parameters().findFile("filename").setValue(path)
        import_res = import_op.operate()
        import_outcome = import_res.findInt('outcome').value()
        self.assertEqual(import_outcome, OP_SUCCEEDED,
                         'import python op outcome {}'.format(import_outcome))

        # Instantiate and run the operation
        op_name = import_res.findString('unique_name').value()
        setup_op = self.op_manager.createOperation(op_name)
        self.assertIsNotNone(setup_op, '{} operation is null'.format(solver))
        setup_op.parameters().associate(project)
        setup_op.parameters().findString('run').setIsEnabled(False)  # don't run OpemFOAM app
        setup_result = setup_op.operate()
        setup_outcome = setup_result.findInt('outcome').value()
        if setup_outcome != OP_SUCCEEDED:
            print(setup_op.log().convertToString())
            self.assertTrue(False, 'operation outcome {}'.format(setup_outcome))

        print(setup_op.log().convertToString())

        # Check for generated files
        case_dir = os.path.join(self.project_dir, 'foam', solver)
        rel_paths = [
            '0.orig/p', '0.orig/U', '0.orig/include/initialConditions',
            'constant/transportProperties', 'system/fvSchemes', 'system/fvSolution',
        ]

        if solver == 'simpleFoam':
            rel_paths += [
                '0.orig/epsilon', 'constant/turbulenceProperties',
            ]

        for rel_path in rel_paths:
            path = os.path.join(case_dir, rel_path)
            self.assertTrue(os.path.exists(path), path)


if __name__ == '__main__':
    smtk.testing.process_arguments()
    smtk.testing.main()
