# =============================================================================
#
#  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.io
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 TestSnappyHexMesh(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_setup(self):
        project = self._read_project()
        self._add_refinement_region(project)
        self._setup_snappymesh(project)

    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 _add_refinement_region(self, project):
        """"""
        att_resource_set = project.resources().findByRole('attributes')
        att_resource = att_resource_set.pop()
        defn = att_resource.findDefinition('RefinementRegion')

        # Next two atts for manual testing
        # att1 = att_resource.createAttribute(defn)
        # mode_item = att1.findString('mode')
        # mode_item.setValue('inside')
        # mode_item.findChild('level', smtk.attribute.SearchStyle.IMMEDIATE_ACTIVE).setValue(3)
        # inc_item = mode_item.findChild(
        #     'levelIncrement', smtk.attribute.SearchStyle.IMMEDIATE_ACTIVE)
        # inc_item.setIsEnabled(True)
        # range_item = inc_item.find(0, 'range')
        # range_item.setValue(0, 2)
        # range_item.setValue(1, 5)
        # split_item = inc_item.find(0, 'split')
        # split_item.setValue(0, 1)
        # split_item.setValue(1, 2)
        # split_item.setValue(2, 3)

        # att2 = att_resource.createAttribute(defn)
        # mode_item = att2.findString('mode')
        # mode_item.setValue('distance')
        # dl_group = mode_item.findChild(
        #     'distance-levels', smtk.attribute.SearchStyle.IMMEDIATE_ACTIVE)
        # distance_item = dl_group.find('distance')
        # distance_item.setValue(0.5)
        # level_item = dl_group.find('level')
        # level_item.setValue(4)

        # self._write_project(project)

    def _write_project(self, project):
        write_op = self.op_manager.createOperation('smtk::project::Write')
        self.assertIsNotNone(write_op)
        write_op.parameters().associate(project)
        write_result = write_op.operate()
        write_outcome = write_result.findInt('outcome').value()
        self.assertEqual(write_outcome, OP_SUCCEEDED,
                         'write project op outcome {}'.format(write_outcome))

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

        path = os.path.join(
            smtk.testing.SOURCE_DIR, 'smtk/simulation/windtunnel/operations/snappyhexmesh.py')
        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()
        if import_outcome != OP_SUCCEEDED:
            print(import_op.log().convertToString())
            self.assertTrue(False, 'import outcome {}'.format(import_outcome))

        # Instantiate and run the SnappyHexMesh operation
        op_name = import_res.findString('unique_name').value()
        setup_op = self.op_manager.createOperation(op_name)
        self.assertIsNotNone(setup_op, 'SnappyHexMesh operation is null')
        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))

        # Check for copied and generated files
        case_dir = os.path.join(self.project_dir, 'foam/snappyHexMesh')
        rel_paths = [
            'constant/include/snappyHexMeshConfig', 'system/controlDict', 'system/fvSchemes',
            'system/fvSolution', 'system/meshQualityDict', 'system/snappyHexMeshDict',
            'system/surfaceFeatureExtractDict']
        for rel_path in rel_paths:
            path = os.path.join(case_dir, rel_path)
            if not os.path.exists(path):
                self.assertTrue(False, 'file not found: {}'.format(path))


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