#=============================================================================
#
#  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 sys
import unittest
import smtk
import smtk.model
import rggsession.session
import rggsession.simulation
import rggsession.simulation.pyarc.export_to_pyarc
import smtk.testing


def readFile(filename, mode="rt"):
    with open(filename, mode) as fin:
        return fin.read()


def validateFile(output_path, logger):
    try:
        import PyArc

        try:
            import PyArc.PyARCModel
            import os
            import subprocess
            abs_path = os.path.abspath(os.path.dirname(PyArc.PyARCModel.__file__))
            sonvalidxml = abs_path+"/bin/sonvalidxml"
            schema = abs_path+"/schema/arc.sch"
            input_file = output_path
            cmd = sonvalidxml + ' ' + schema + ' ' + input_file
            try:
                xmlresult = subprocess.check_output(cmd, shell=True)
            except subprocess.CalledProcessError as e:
                logger.addError(str(e))
                logger.addError('\n' + e.output)
                return False

            from PyArc.wasppy import xml2obj
            document = xml2obj.xml2obj(xmlresult).arc

            msg = 'Output file passed PyARC validity check'
            smtk.InfoMessage(logger, msg)
            return True
        except Exception as e:
            msg = 'Output file failed PyARC validity check'
            smtk.ErrorMessage(logger, msg)
            smtk.ErrorMessage(logger, str(e))
            return False
    except ImportError as e:
        msg = 'Cannot check against PyARC schema for validity'
        smtk.WarningMessage(logger, msg)
        smtk.WarningMessage(logger, str(e))
        return True

def deleteFile(filename):
    os.remove(filename)


class ExportToPyARC(smtk.testing.TestCase):

    def setUp(self):
        self.modelFile = os.path.join\
            (smtk.testing.DATA_DIR, 'sampleCore.rxf')
        self.mcc3File = os.path.join\
            (smtk.testing.DATA_DIR, '../smtk/simulation/pyarc/templates/mcc3.sbt')
        self.targetFile = os.path.join\
            (smtk.testing.TEMP_DIR, 'sampleCoreTest.son')
        self.validationFile = os.path.join \
            (smtk.testing.DATA_DIR, 'sampleCore.son')

    def addMaterial(self, Name, Label, Color):
        op = smtk.session.rgg.AddMaterial.create()
        op_parameters = op.parameters()
        op_parameters.associate(self.model)
        op_parameters.find('name').setValue(Name)
        op_parameters.find('label').setValue(Label)
        color = [float(c) for c in Color.split(',')]
        for i in range(4):
            op_parameters.find('color').setValue(i, color[i])
        op_parameters.setTemperature(273.)
        op_parameters.setDensity(1.)
        op_parameters.find('component').setValue(0, 'h2')
        op_parameters.find('content').setValue(0, 1.)
        res = op.operate()

        if res.findInt('outcome').value(0) != int(smtk.operation.Operation.SUCCEEDED):
            print(op.log().convertToString(True))
            raise RuntimeError

    def defineMaterials(self):
        self.addMaterial(Name="UnknownMaterial", Label="Unknown", Color="1, 1, 1, 1")
        self.addMaterial(Name="absorber", Label="absorber", Color="0.700008, 0.2, 0.700008, 1")
        self.addMaterial(Name="activecore", Label="activecore", Color="1, 0.500008, 0.300008, 1")
        self.addMaterial(Name="BurnPoison", Label="BP", Color="0.45098, 0.45098, 0.45098, 1")
        self.addMaterial(Name="Cell_Fuel", Label="CF", Color="1, 0.168353, 0.0217288, 1")
        self.addMaterial(Name="CellCoolant", Label="CC", Color="0.728191, 0.939208, 0.992157, 1")
        self.addMaterial(Name="CellFHH", Label="FH", Color="0.780392, 0.913725, 0.752941, 1")
        self.addMaterial(Name="cladding", Label="cladding", Color="0.749996, 0.749996, 0.749996, 1")
        self.addMaterial(Name="ControlCell", Label="CO", Color="0.854902, 0.854902, 0.921569, 1")
        self.addMaterial(Name="controlrod", Label="controlrod", Color="0.729, 0.893996, 0.702007, 1")
        self.addMaterial(Name="coolant", Label="coolant", Color="0.300008, 0.500008, 1, 0.500008")
        self.addMaterial(Name="duct", Label="duct", Color="0.300008, 0.300008, 1, 0.500008")
        self.addMaterial(Name="DuctHandlingSocket", Label="HD", Color="0.945098, 0.411765, 0.0745098, 1")
        self.addMaterial(Name="follower", Label="follower", Color="0.749996, 0.2, 0.749996, 1")
        self.addMaterial(Name="FollowerSodium", Label="FS", Color="0.988235, 0.733333, 0.631373, 1")
        self.addMaterial(Name="fuel", Label="fuel", Color="1, 0.100008, 0.100008, 1")
        self.addMaterial(Name="gap", Label="gap", Color="0, 0, 0, 0")
        self.addMaterial(Name="gasplenum", Label="gasplenum", Color="0.300008, 1, 0.500008, 1")
        self.addMaterial(Name="graphite", Label="graphite", Color="0.4, 0.4, 0.4, 1")
        self.addMaterial(Name="guidetube", Label="guidetube", Color="0.6, 0.6, 0.6, 1")
        self.addMaterial(Name="HandlingSocket", Label="HS", Color="0.254902, 0.670588, 0.364706, 1")
        self.addMaterial(Name="interassemblygap", Label="interassemblygap", Color="0, 0, 0, 0")
        self.addMaterial(Name="loadpad", Label="loadpad", Color="0.4, 0.4, 0.4, 1")
        self.addMaterial(Name="LowerReflector", Label="LR", Color="0.258824, 0.572549, 0.776471, 1")
        self.addMaterial(Name="metal", Label="metal", Color="0.6, 0.6, 0.6, 1")
        self.addMaterial(Name="outerduct", Label="outerduct", Color="0.2, 0.2, 0.2, 1")
        self.addMaterial(Name="reflector", Label="reflector", Color="0.500008, 0.500008, 1, 1")
        self.addMaterial(Name="restraintring", Label="restraintring", Color="0.4, 0.4, 0.4, 1")
        self.addMaterial(Name="shield", Label="shield", Color="0.996002, 0.697993, 0.297993, 1")
        self.addMaterial(Name="SmallCoolant", Label="SC", Color="0.776471, 0.858824, 0.937255, 1")
        self.addMaterial(Name="sodium", Label="sodium", Color="1, 1, 0.4, 0.700008")
        self.addMaterial(Name="SodiumDuct", Label="NA", Color="1, 0.985595, 0.0344549, 0.540002")
        self.addMaterial(Name="water", Label="water", Color="0.650996, 0.740993, 0.859007, 0.500008")

    def testReadRXFFileOp(self):
        # create model
        op = smtk.session.rgg.CreateModel.create()
        res = op.operate()
        if res.findInt('outcome').value(0) != int(smtk.operation.Operation.SUCCEEDED):
            raise ImportError
        self.model = res.find('created').value(0)
        # hold onto the resource so it doesn't go out of scope when this
        # operation's result is replaced by the next operation's result
        self.resource = self.model.resource()
        # read rxf file
        op = smtk.session.rgg.ReadRXFFile.create()
        fname = op.parameters().find('filename')
        fname.setValue(self.modelFile)
        op.parameters().associate(self.model)
        res = op.operate()
        if res.findInt('outcome').value(0) != int(smtk.operation.Operation.SUCCEEDED):
            raise RuntimeError

        # populate materials list with dummy values
        self.defineMaterials()

        # Construct PYARC simulation attributes for MCC3 and DIF3D
        pyarcSimulationAttributes = smtk.attribute.Resource.create()
        logger = smtk.io.Logger()
        reader = smtk.io.AttributeReader()
        # the attribute reader returns true on failure...
        if reader.read(pyarcSimulationAttributes, self.mcc3File, True, logger):
            print("Import PYARC simulation attributes failed\n")
            print(logger.convertToString(True) + "\n")
            return 1

        mcc3Att = pyarcSimulationAttributes.createAttribute("mcc3-instance", "mcc3")

        # export to PyARC
        op = smtk.simulation.export_to_pyarc()
        fname = op.parameters().find('filename')
        fname.setValue(self.targetFile)
        op.parameters().associate(self.model)
        op.parameters().find('mcc3').setValue(mcc3Att)
        res = op.operate()
        if res.findInt('outcome').value(0) != int(smtk.operation.Operation.SUCCEEDED):
            print(op.log().convertToString(True))
            raise RuntimeError

        logger = smtk.io.Logger()
        if not validateFile(self.targetFile, logger):
            print(logger.convertToString(True))
            raise RuntimeError

        deleteFile(self.targetFile)


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