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

""" generate_cross_sections.py:

Generate a cross sections file using PyARC + mcc3.

"""
import sys

from . import generate_cross_sections_xml

import json
import os
import rggsession
import shutil
import smtk
import smtk.attribute
import smtk.io
import smtk.mesh
import smtk.model
import smtk.operation
import subprocess
import sys
import tempfile

import PyArc.PyARC

from .convert_to_pyarc import *
from .pyarc_writer import *

class GenerateCrossSections(smtk.operation.Operation):

    def __init__(self):
        smtk.operation.Operation.__init__(self)
        self.pyarc = PyArc.PyARC.PyARC()

    def name(self):
        return "generate cross sections"

    def is_exe(self, fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    def rm_dir(self, dpath):
        try:
            shutil.rmtree(dpath)
        except OSError as e:
            smtk.WarningMessage(self.log(), 'Could not remove directory \'%s\'' % dpath)

    def which(self, executable):
        """ Find an executable using the following queues (in order):
        1) check user-defined inputs
        2) check relative to current executable
        3) check relative to PATH
        """
        # 1) check user-defined inputs
        file_att = self.parameters().findFile(executable)
        if file_att and file_att.isEnabled():
            exe_file = file_att.value()
            if self.is_exe(exe_file):
                return exe_file

        # 2) check relative to current executable
        current_exe = sys.executable
        fpath, fname = os.path.split(current_exe)

        exe_file = os.path.join(fpath, '../bin', executable)
        if self.is_exe(exe_file):
            return exe_file

        # 3) check relative to PATH
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, executable)
            if self.is_exe(exe_file):
                return exe_file

        return None

    def ableToOperate(self):
        if not smtk.operation.Operation.ableToOperate(self):
            return False

        # Ensure that the necessary executables can be found
        return self.which('mcc3.x') != None or self.is_exe(self.pyarc.user_object.mcc3_executable)

    def operateInternal(self):
        smtk.InfoMessage(self.log(), 'generate cross sections')

        # Access the input model
        model = smtk.model.Entity.CastTo(self.parameters().associations().value(0))

        # Access assygen, coregen and cubit
        mcc3 = self.which('mcc3.x')

        if mcc3:
            smtk.InfoMessage(self.log(), 'mcc3 executable is %s' % mcc3)
            self.pyarc.user_object.mcc3_executable = mcc3

        # Access the output file name
        filename = self.parameters().find('filename').value()

        # Access the MCC3 input attributes
        mcc3Att = smtk.attribute.Attribute.CastTo(
            self.parameters().find('mcc3_atts').value(0))

        # Construct a temporary scratch space for generating input files
        temp_dir = tempfile.mkdtemp()
        temp_inputfile = os.path.join(temp_dir, "input.son")

        writer = PyARCWriter()
        writer.logger = self.log()
        success = writer(temp_inputfile, model, mcc3Att)

        if not success:
            smtk.WarningMessage(self.log(), 'could not generate PyARC input file')
            self.rm_dir(temp_dir)
            return self.createResult(smtk.operation.Operation.Outcome.FAILED)
        else:
            smtk.InfoMessage(self.log(), 'generated PyARC input file')

        options = PyArc.PyARC.RunOptions()
        options.input = temp_inputfile
        self.pyarc = PyArc.PyARC.PyARC()
        self.pyarc.user_object.do_run = True
        self.pyarc.user_object.do_postrun = True

        # pyarc's argparse expects arguments to be passed to the python
        # instance, and errors out when it can't find them. We mollify these
        # checks by inserting dummy arguments at sys scope (see workaround
        # described here: https://github.com/googleapis/oauth2client/issues/642)
        import sys
        if not hasattr(sys, 'argv'):
            sys.argv  = ['']

        self.pyarc.execute(['-i', temp_inputfile, '-w', temp_dir, '-o', temp_dir])

        # Convert PyARC's summary into SMTK messages
        with open(os.path.join(temp_dir, "input.summary"), 'r') as fin:
            messages = [str(), str(), str()] # info, warning, error
            lines = fin.read().split('\n')
            severity = 0
            for line in lines:
                if line.find('INFORMATION MESSAGES') != -1:
                    severity = 0
                    continue
                if line.find('WARNING MESSAGES') != -1:
                    severity = 1
                    continue
                elif line.find('ERROR MESSAGES') != -1:
                    severity = 2
                    continue
                messages[severity] += line + '\n'
            if messages[0]:
                smtk.InfoMessage(self.log(), messages[0])
            if messages[1]:
                smtk.WarningMessage(self.log(), messages[1])
            if messages[2]:
                smtk.ErrorMessage(self.log(), messages[2])

        # Copy the results to the user-specified output file
        from shutil import copyfile
        copyfile(os.path.join(temp_dir, "input.isotxs_R_0"), filename)

        # Clean up the temporary work directory
        self.rm_dir(temp_dir)

        # Return with success
        result = self.createResult(smtk.operation.Operation.Outcome.SUCCEEDED)
        return result

    def createSpecification(self):
        spec = smtk.attribute.Resource.create()
        reader = smtk.io.AttributeReader()
        reader.readContents(spec, generate_cross_sections_xml.description, self.log())
        return spec
