"""ACT Units Module

This module provides helper functions to convert and manipulate units.

"""

import System
import clr
clr.AddReference("Ans.Core")
clr.AddReference("Ans.Utilities")

import Ansys.Core.Units
import Ansys.Utilities
from Ansys.Utilities import ApplicationConfiguration

def ConvertUnit(value, fromUnit, toUnit, quantityName=None):
    """Return the given value converted to the given units.
    
    Keyword arguments:
    value -- the value to convert
    fromUnit -- the unit of the given value
    toUnit -- the target unit
    quantityName -- the quantity name (default None)

    """
    return Ansys.Core.Units.UnitsManager.ConvertUnit(value,fromUnit,toUnit,quantityName)

def ConvertUserAngleUnitToDegrees(api, value):
    """Return the value converted from the current angle unit to degrees.

    Keyword arguments:
    api -- Extension API (ExtAPI)
    value -- the angle value to convert

    """
    user = api.DataModel.CurrentUnitFromQuantityName("Angle")
    return ConvertUnit(value, user, "degree", "Angle")
    
def ConvertToSolverConsistentUnit(api, value, quantityName, analysis):
    """Return the value converted to solver consistent unit of the given quantity.
    The value is in user unit of the given quantity.

    Keyword arguments:
    api -- Extension API (ExtAPI)
    value -- the value to convert, in user unit.
    quantityName -- name of the quantity
    analysis -- current analysis object

    """
    userUnit = api.DataModel.CurrentUnitFromQuantityName(quantityName)
    solverUnit = analysis.CurrentConsistentUnitFromQuantityName(quantityName)
    return ConvertUnit(value, userUnit, solverUnit, quantityName)
    
def ConvertToUserUnit(api, value, fromUnit, quantityName):
    """Return the value converted to user unit of the given quantity.

    Keyword arguments:
    api -- Extension API (ExtAPI)
    value -- the value to convert
    fromUnit -- the unit of the given value
    quantityName -- name of the quantity

    """
    userUnit = api.DataModel.CurrentUnitFromQuantityName(quantityName)
    return ConvertUnit(value, fromUnit, userUnit, quantityName)

def ConvertUnitToSolverConsistentUnit(api, value, fromUnit, quantityName, analysis):
    """Return the value converted to solver consistent unit of the given quantity.

    Keyword arguments:
    api -- Extension API (ExtAPI)
    value -- the value to convert
    fromUnit -- the unit of the given value
    quantityName -- name of the quantity
    analysis -- current analysis object
    """
    solverUnit = analysis.CurrentConsistentUnitFromQuantityName(quantityName)
    return ConvertUnit(value, fromUnit, solverUnit, quantityName)

def GetMeshToUserConversionFactor(api):
    """Return the length factor to convert mesh values to user values.
    
    Keyword arguments:
    api -- Extension API (ExtAPI)
    """
    meshUnit = api.DataModel.MeshDataByName("Global").Unit
    userUnit = api.DataModel.CurrentUnitFromQuantityName("Length")
    return ConvertUnit(1, meshUnit, userUnit)

def MeshToUserConversionFactor(api):
    """Obsolete method, use 'GetMeshToUserConversionFactor' instead."""
    api.Log.WriteWarning("Obsolete method 'MeshToUserConversionFactor' in 'units' module: use 'GetMeshToUserConversionFactor' instead.")
    return GetMeshToUserConversionFactor(api)

def GetCurrentCompactUnitString(api, field):
    """Return a compact unit string for the supplied field.
    for example, on an acceleration object acc (in MKS & NMM, respectively):
    -  acc.Magnitude.Output.Unit ==> 'm sec^-1 sec^-1' , 'm sec^-1 sec^-1'
    -  GetCurrentCompactUnitString(ExtAPI, acc.Magnitude) ==> 'm/s²' , 'mm/s²'
    
    Keyword arguments:
    api -- Extension API (ExtAPI)
    field -- Ansys.ACT.Mechanical.Fields.Field
    """
    def GetApplicableUnitSystemObject(mechanical_unit_system, assistant):
        system_objects = assistant.UnitSystems
        for index in range(1, system_objects.Count+1):
            system_object = system_objects[index]
            system_object_enum = System.Enum.ToObject(Ansys.ACT.Interfaces.Common.MechanicalUnitSystemEnum, system_object.Type)
            if mechanical_unit_system.Equals(system_object_enum):
                return system_object

    def GetUnitString(unit_system, unit_label):
        unit_categories = unit_system.UnitCategories
        for index in range(1, unit_categories.Count+1):
            unit_category = unit_categories[index]
            if unit_category.Name == unit_label:
                return unit_category.UnitString

    clr.AddReference("Ansys.Common.Interop." + ApplicationConfiguration.DefaultConfiguration.VersionInfo.VersionString)
    assistant = Ansys.Common.Interop.WBUtils.WBUnitAssistant()
    mechanical_unit_system = api.Application.ActiveUnitSystem
    quantity_name = field.Output.QuantityName
    unit_system = GetApplicableUnitSystemObject(mechanical_unit_system, assistant)
    return GetUnitString(unit_system, quantity_name)
