# =============================================================================
#
#  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.
#
# =============================================================================

"""SurfaceFeatureExtract operation"""

import io
import os
import shutil
import sys

import smtk
import smtk.attribute
import smtk.io
import smtk.operation
import smtk.project

OP_SUCCEEDED = int(smtk.operation.Operation.Outcome.SUCCEEDED)

# Make sure __file__ is set when using modelbuilder
import inspect
source_file = os.path.abspath(inspect.getfile(inspect.currentframe()))
__file__ = source_file

# Make sure this folder is in sys.path
source_dir = os.path.dirname(__file__)
if source_dir not in sys.path:
    sys.path.insert(0, source_dir)

from foam_mixin import FoamMixin


class SurfaceFeatureExtract(smtk.operation.Operation, FoamMixin):
    """Generates controlDict and surfaceFeatureExtractDict files for project analysis mesh."""

    def __init__(self):
        smtk.operation.Operation.__init__(self)
        FoamMixin.__init__(self)

        # Do NOT store any smtk resources as member data (causes memory leak)

    def name(self):
        return "Setup and run surfaceFeaturesExtract"

    def createSpecification(self):
        spec = self._create_specification(app='surfaceFeatureExtract')
        return spec

    def operateInternal(self):
        """"""
        project = self._get_project()
        if project is None:
            return self.createResult(smtk.operation.Operation.Outcome.UNABLE_TO_OPERATE)

        att_resource = self._get_attribute_resource(project)
        # print('att_resource:', att_resource)
        if att_resource is None:
            return self.createResult(smtk.operation.Operation.Outcome.UNABLE_TO_OPERATE)

        # Check validity of controlDict and target attributes
        att_names = ['controlDict', 'Target']
        if not self._check_attributes(att_resource, att_names):
            return self.createResult(smtk.operation.Operation.Outcome.UNABLE_TO_OPERATE)

        # Create case directories if needed
        project_dir = os.path.abspath(os.path.dirname(project.location()))
        case_dir = os.path.join(project_dir, 'foam/snappyHexMesh')
        constant_dir = os.path.join(case_dir, 'constant')
        system_dir = os.path.join(case_dir, 'system')
        logs_dirs = os.path.join(case_dir, 'logs')

        for path in [constant_dir, system_dir, logs_dirs]:
            if not os.path.exists(path):
                os.makedirs(path)

        # Generate controlDict file
        if not self.cd_writer.generate_controlDict(case_dir, att_resource):
            return self.createResult(smtk.operation.Operation.Outcome.FAILED)

        # Future read-transform-write the native model file
        target_att = att_resource.findAttribute('Target')
        target_filename = target_att.findString('Filename').value()
        native_model_path = os.path.join(project_dir, 'assets', target_filename)
        geom_dir = os.path.join(constant_dir, 'triSurface')
        if not os.path.exists(geom_dir):
            os.makedirs(geom_dir)
        shutil.copy(native_model_path, geom_dir)

        filename = 'surfaceFeatureExtractDict'
        native_model_filename = os.path.basename(native_model_path)
        if not self._write_surfaceFeatureExtractDict(target_att, system_dir, filename, native_model_filename):
            return self.createResult(smtk.operation.Operation.Outcome.FAILED)

        # Check "Run" option
        run_item = self.parameters().findString('run')
        if run_item.isEnabled():
            if not self._run_openfoam('surfaceFeatureExtract', case_dir, run_item):
                return self.createResult(smtk.operation.Operation.Outcome.FAILED)

        result = self._create_result()
        return result

    def _write_surfaceFeatureExtractDict(self, target_att, directory, filename, native_model_filename):
        """"""
        # Generate feature list
        kv_list = list()
        kv = ('extractionMethod', 'extractFromSurface')
        kv_list.append(kv)

        angle = None
        angle_item = target_att.itemAtPath('Edges')
        option = angle_item.value()
        if option == 'none':
            angle = 0
        elif option == 'all':
            angle = 180
        else:
            value_item = angle_item.findChild('Angle', smtk.attribute.SearchStyle.IMMEDIATE_ACTIVE)
            angle = value_item.value()
        kv = ('includedAngle', angle)
        kv_list.append(kv)

        tolerance = 0.001  # default
        tolerance_item = target_att.itemAtPath('Tolerance')
        if tolerance_item is not None:
            tolerance = tolerance_item.value()
        kv = ('tolerance', tolerance)
        kv_list.append(kv)

        path = os.path.join(directory, filename)
        complete = False
        with open(path, 'w') as fp:
            self.cd_writer.write_foamfile_header(fp, filename)
            fp.write('\n')

            # Write native model section
            fp.write('{}\n'.format(native_model_filename))
            fp.write('{\n')
            self.cd_writer.write_kvlist(fp, kv_list, indent=4, column0=20)
            fp.write('}\n')
            complete = True

        return complete
