package CFX5::Simulation::Configuration::CCL2MF ;

use base 'CFX5::Simulation::Subtask' ;

use CFX5::Output qw(:all error_text) ;
use CFX5::FileTests ;

use CFX5::PathManip qw(dirname basename fullpath join_file normalize_filename) ;
use CFX5::FileOps qw(create_empty_file create_directory
                     append_to_file set_file_contents copy_file move_file
                     link_files concatenate_files) ;

use CFX5::Config qw(%Config export_conf) ;

use CFX5::CCLI ;

use CFX5::Simulation::Util '_check_defined' ;

use CFX5::PkgLoader qw(cfx5_require) ;

use strict ;

sub _load_aslapi_load {
  my $from=shift ;

  _debug("Attempting to load ASLPI from $from.") ;
  #_debug("Before use lib, \@INC=", @INC) ;
  'lib'->import($from) ;
  # on NT under the Perl compiler, the lib->import fails.  Not sure
  # why.  So we also put the directory onto the lib path.
  unshift @INC, $from ;
  #_debug("After use lib, \@INC=", @INC) ;
  eval { require ASLAPI ; } ;
  if ($@) {
    internal_error "Error loading ASLAPI from $from:\n\n $@" ;
  }
  1 ;
}

{
  my $aslapi_loaded=0 ;
  sub _load_aslapi {
    if ($aslapi_loaded) {
      return 1 ;
    } elsif (exists $ENV{CFX5LIBDIR} and -d "$ENV{CFX5LIBDIR}/../ccl") {
      _load_aslapi_load("$ENV{CFX5LIBDIR}/../ccl")
        and $aslapi_loaded=1 ;
    } elsif (defined $Config{CFX5LIBDIR} and -d "$Config{CFX5LIBDIR}/../ccl") {
      _load_aslapi_load("$Config{CFX5LIBDIR}/../ccl")
        and $aslapi_loaded=1 ;
    }
    return $aslapi_loaded ;
  }
}                             

################################################################################
################################################################################
##
## Main Processing
##
################################################################################
################################################################################

sub _Do {
  my $self=shift ;

  # make sure we've got something sensible here
  my $do=shift ;
  internal_error("First argument must be 0 or 1 or 2")
    unless defined $do and ($do eq 0 or $do eq 1 or $do eq 2) ;

  return 1 unless $self->prep_ansys();

  _load_aslapi()
    or _error "Unable to find ASLAPI" ;
  
  if($do){
    my $outfile=$self->processed_ansys_input();
    
    CFX5::FileTests::datafile_w($outfile, "CCL2MF output file") or return 0 ;
    CFX5::FileTests::datafile($self->ansys_input(), "ANSYS Input File") or return 0 ;

    $self->OutFileHeader("Processing ANSYS Input File (Running CCL2MF)") ;

    my %interfaceMap ;
    my $unitsys ; 
    my $rv=ASLAPI::getNameMap($self->ansys_input(), \%interfaceMap, \$unitsys) ;
    if($rv < 0 ){
      my %aslapierr={
          -1 => "ASLAPI error: Invalid call",
          -2 => "ASLAPI error: Memory error",
          -3 => "ASLAPI error: Cannot open file"
      } ;
      _error($aslapierr{$rv}) ;
    }

    # Connect to the CCL and pickup the ANSYS job name 
    my $cclapi=$self->ccl_api_obj() ;
    my $jobName=$self->ansys_jobname() ;
    
    # Get the solution Time Units for later use
    my $timeSolnUnit ;
    $cclapi->getStringValue("/".$self->flow_name()."/SOLUTION UNITS/Time Units",\$timeSolnUnit) ;
    $timeSolnUnit=~/\[\s*(\w)\s*\]/ ;
    $timeSolnUnit=$1 ;

    # Define two variables related to adaptive time stepping that will need to be reused between command types
    my $adaptiveTimestepping = 0 ;
    my $targetCplgIter = 0 ;

    # Open the Output file
    unless(open(OUT,">$outfile")){
      _error ("Can't open file $outfile for writing: $!") ;
      return 0 ;
    }

    #
    ##############################################################################
    # Input file Preprocessing
    ##############################################################################
    #
    # Preprocess prep7 input file to add \BATCH command (required for Linux i/o redirection)
    #
    if ($self->mfx_run_type() eq "ANSYS MultiField via Prep7") {
      unless(open(INP,"<".$self->ansys_input()) ) {
        _error("Can't open Input file $self->ansys_input():$!") ;
        close(OUT) ;
        return 0 ;
      }
      
      print OUT "/batch\n" ;
      while(<INP>){
        print OUT $_ ;
      }
      close(INP);
      return 1;
    }
    #
    ## Restart -- Essentially create our own input file
    #
    
    if ($self->is_mfx_restart()) {
      my $mfrsType ;
      my $restartType=$self->mfx_restart_type() ;
      my $dbname=basename($self->mfx_restart_db()) ;
      $dbname=~s/\.db//gi ;
      print OUT "/batch\n" ;
      if   ($restartType eq "Singleframe") {
        print OUT "resume,".$dbname.",db\n" ;
        $mfrsType = "SING"
      }
      elsif($restartType eq "Multiframe"){
        $mfrsType = "MULT"
      }
      else{
        _error "MFX restart type not recognised." ;
        close(OUT) ;
        return 0 ;
      }
      
      print OUT "/SOLU\n" ;
      print OUT "MFAN,ON\n" ;
      print OUT "MFCLEAR,MFLC\n" ;

      # Set the Time value
      #
      my $initTime ;
      $cclapi->getStringValue("/".$self->flow_name()."/ANALYSIS TYPE/EXTERNAL SOLVER COUPLING/COUPLING TIME CONTROL/COUPLING INITIAL TIME/Time",\$initTime) ;

      my ($timeVal,$unit) ;
      if (defined($initTime)) {
         #get the value and units of the Inital Time
         ($timeVal,$unit) = $self->splitValue($initTime) ;
         #Convert from Inital Time units to Solution Units
         $timeVal = $self->convertTime($timeVal,$unit,$timeSolnUnit) ;
         if(not defined $timeVal){
           close(OUT) ;
           return 0 ;
         }
       }
       else {
         $timeVal = "-1" ;
       }
       
       # Write the restart command
       #
       print OUT "MFRS,$timeVal,$mfrsType\n" ;   

    #
    ## Not a restart -- Find place to start appending MF settings
    #
    
    }
    else {
      #
      # Read the ANSYS Input file
      unless(open(INP,"<".$self->ansys_input()) ) {
        _error("Can't open Input file $self->ansys_input():$!") ;
        close(OUT) ;
        return 0 ;
      }
      
      print OUT "/batch\n" ;
      while(<INP>){
#       Break copy/write from input file at first solve command
        last if ($_ =~ /^solve/i) ;
#       Don't copy/write /eof commands        
        if      ( ($_ !~ /^\/eof/i) && 
                  ($_ !~ /^deltim,0.,0.,0./i)) {
          print OUT $_ ;
        }  
      }
      close(INP) ;

      print OUT "MFAN,ON\n" ;
    }

    #
    ##############################################################################
    # General ANALYSIS TYPE Processing
    ##############################################################################
    #

    #
    ## Process Coupling Time Duration
    #

    my $timeDuration ;
    $cclapi->getStringValue("/".$self->flow_name()."/ANALYSIS TYPE/EXTERNAL SOLVER COUPLING/COUPLING TIME CONTROL/COUPLING TIME DURATION/Total Time",\$timeDuration) ;
    if (!defined($timeDuration)) {
       _error "COUPLING TIME DURATION/Total Time not defined." ;
       close(OUT) ;
       return 0 ;
    }

    # Get the value and units of the Time Duration
    my ($value,$unit) = $self->splitValue($timeDuration) ;

    # Convert from Time Duration units to Solution Units
    $value = $self->convertTime($value,$unit,$timeSolnUnit) ;
    if(not defined $value){
      close(OUT) ;
      return 0 ;
    }
    print OUT "MFTI,$value\n" ;

    #
    ## Process Coupling Time Steps
    #
    
    my $cplgTimeStepPath = "/".$self->flow_name()."/ANALYSIS TYPE/EXTERNAL SOLVER COUPLING/COUPLING TIME CONTROL/COUPLING TIME STEPS" ;

    my $timeStepOpt ;
    $cclapi->getStringValue("$cplgTimeStepPath/Option",\$timeStepOpt) ;
    if (!defined($timeDuration)) {
      _error "COUPLING TIME STEPS/Option not defined." ;
      close(OUT) ;
      return 0 ;
    }

    # 
    # Fixed Timesteps
    if ($timeStepOpt eq "Timesteps") {
      my $timesteps ;
      $cclapi->getStringValue("$cplgTimeStepPath/Timesteps",\$timesteps) ;
      if (!defined($timesteps)) {
        _error "COUPLING TIME STEPS/Timesteps not defined." ;
        close(OUT) ;
        return 0 ;
      }

      # Get the value and units the time and convert value to Time Solution Units
      my ($value,$unit) = $self->splitValue($timesteps) ;
      $value = $self->convertTime($value,$unit,$timeSolnUnit) ;
      if(not defined $value){
        close(OUT) ;
        return 0 ;
      }

      print OUT "MFDT,$value,$value,$value,OFF\n" ;

    # 
    # Adaptive Timesteps
    }
    elsif ($timeStepOpt eq "Adaptive") {
      my ($initTstep,$maxTstep,$minTstep,$unit,$adaptiveOpt) ;
      $adaptiveTimestepping = 1 ;
      $cclapi->getStringValue("$cplgTimeStepPath/Initial Timestep",\$initTstep) ;
      $cclapi->getStringValue("$cplgTimeStepPath/COUPLING TIMESTEP ADAPTION/Option",\$adaptiveOpt) ;
      $cclapi->getStringValue("$cplgTimeStepPath/COUPLING TIMESTEP ADAPTION/Maximum Timestep",\$maxTstep) ;
      $cclapi->getStringValue("$cplgTimeStepPath/COUPLING TIMESTEP ADAPTION/Minimum Timestep",\$minTstep) ;
      $cclapi->getStringValue("$cplgTimeStepPath/COUPLING TIMESTEP ADAPTION/Target Number of Coupling Iterations",\$targetCplgIter) ;
      if (!defined($initTstep) ||
          !defined($maxTstep)  ||
          !defined($minTstep)  ||
          !defined($targetCplgIter)) {
        _error "COUPLING TIMESTEP ADAPTION information incomplete.\n",
               "  Initial Timestep                    : $initTstep\n",
               "  Maximum Timestep                    : $maxTstep\n",
               "  Minimum Timestep                    : $minTstep\n",
               "  Target Number of Coupling Iterations: $targetCplgIter\n"  ;
        close(OUT) ;
        return 0 ;
      }
      if ($adaptiveOpt ne "Scale with Iterations") {
        _error "COUPLING TIMESTEP ADAPTION invalid option: $adaptiveOpt" ;
        close(OUT) ;
        return 0 ;
      }

      # Get the value and units the times and convert value to Time Solution Units
      ($initTstep,$unit) = $self->splitValue($initTstep) ;
      $initTstep = $self->convertTime($initTstep,$unit,$timeSolnUnit) ;
      if(not defined $initTstep){
        close(OUT) ;
        return 0 ;
      }
      ($maxTstep,$unit) = $self->splitValue($maxTstep) ;
      $maxTstep = $self->convertTime($maxTstep,$unit,$timeSolnUnit) ;
      if(not defined $maxTstep){
        close(OUT) ;
        return 0 ;
      }
      ($minTstep,$unit) = $self->splitValue($minTstep) ;
      $minTstep = $self->convertTime($minTstep,$unit,$timeSolnUnit) ;
      if(not defined $minTstep){
        close(OUT) ;
        return 0 ;
      }

      print OUT "MFDT,$initTstep,$minTstep,$maxTstep,OFF\n" ;
    }
    else {
      _warn "COUPLING TIME STEPS Option not recognized.  MFDT command not written.\n" ;
    }

    #
    ##############################################################################
    # Process all Boundary Objects
    ##############################################################################
    #

    my @boundaryList ;
    $cclapi->getObjectsByType("BOUNDARY",\@boundaryList) ;

    foreach my $boundary (@boundaryList) {
      my $opt="" ;

      #
      ## Mesh Motion BCs 
      #

      $cclapi->getStringValue("$boundary/BOUNDARY CONDITIONS/MESH MOTION/Option",\$opt) ;
      if ($opt eq "ANSYS MultiField") {
              
        #
        # Handle Receive Data
        my ($bcname,$intNo,$DTType,$sendData,$recvData) ;
        $bcname = $cclapi->getName($boundary) ;
        $cclapi->getStringValue("$boundary/BOUNDARY CONDITIONS/MESH MOTION/ANSYS Interface",\$intNo) ;
        $cclapi->getStringValue("$boundary/BOUNDARY CONDITIONS/MESH MOTION/Receive from ANSYS",\$recvData) ;
        if (!defined($bcname) ||
            !defined($intNo)  ||
            !defined($recvData)) {
          _error "MESH MOTION interface information incomplete for $boundary." ;
          close(OUT) ;
          return 0 ;
        }

        # Convert interface name 
        $intNo=$interfaceMap{$intNo} ;

        # Write MFLC for Receive data      
        print OUT "MFLC,SURF,ANSYS,$intNo,DISP,CFX,\'$bcname\',\'$recvData\',NONC\n" ;

        #
        # Handle send Data
        $cclapi->getStringValue("$boundary/BOUNDARY CONDITIONS/MESH MOTION/Send to ANSYS",\$sendData) ;
        if ($sendData eq "Total Force" ) {
          print OUT "MFLC,SURF,CFX,\'$bcname\',\'$sendData\',ANSYS,$intNo,FORC,CPP\n" ;
        }
        elsif ($sendData ne "None") {
          _error "Send to ANSYS, $sendData, not recognized for MESH MOTION on $boundary." ;
          close(OUT) ;
          return 0 ;
        }
      }

      #
      ## Thermal BCs
      #

      my $pathHT = "$boundary/BOUNDARY CONDITIONS/HEAT TRANSFER" ;
      $cclapi->getStringValue("$pathHT/Option",\$opt) ;
      if   ($opt eq "ANSYS MultiField") {
        my $fluid ; 
        if (!$self->MFLC_HeatTransfer($cclapi,$boundary,$fluid,$pathHT,*OUT,\%interfaceMap)) {
          _error "Thermal boundary analysis failed." ;
          close(OUT) ;
          return 0 ;
        }
      }
      elsif($opt eq "Fluid Dependent") {
        my @objList ;
        $cclapi->getChildObjectList($boundary,\@objList) ;
        foreach my $obj (@objList) {
          $obj =~/(.*):(.*)/ ;  #get type & name
          my $objType=$1 ;
          my $fluid=$2 ;
          if ($objType eq "FLUID") {
            my $pathFluid="$boundary/$obj/BOUNDARY CONDITIONS/HEAT TRANSFER" ;
            $cclapi->getStringValue("$pathFluid/Option",\$opt) ;
            if ($opt eq "ANSYS MultiField") {
              if (!$self->MFLC_HeatTransfer($cclapi,$boundary,$fluid,$pathFluid,*OUT,\%interfaceMap)) {
                _error "Thermal boundary analysis failed for fluid dependent conditions." ;
                close(OUT) ;
                return 0 ;
              }
            }
          }
        }
      }

      #
      ## Custom Data Transfer (Send) Objects
      #

      my @objList ;
      $cclapi->getChildObjectList($boundary,\@objList) ;
      foreach my $obj (@objList) {
        # get type & name
        if ($obj =~/(.*):(.*)/ && $1 eq "COUPLING DATA TRANSFER") {
          $cclapi->getStringValue("$boundary/$obj/Option",\$opt) ;
          if ($opt eq "ANSYS MultiField") {
          
            #get the interface details
            my ($bcname,$intNo,$cfxVar,$ansVar,$DTType) ;
            $bcname = $cclapi->getName($boundary) ;
            $cclapi->getStringValue("$boundary/$obj/ANSYS Interface",\$intNo) ;
            $cclapi->getStringValue("$boundary/$obj/CFX Variable",\$cfxVar) ;
            $cclapi->getStringValue("$boundary/$obj/ANSYS Variable",\$ansVar) ;
            $cclapi->getStringValue("$boundary/$obj/Coupling Data Transfer Type",\$DTType) ;
            if (!defined($bcname)   ||
                !defined($intNo)    ||
                !defined($cfxVar)   ||
                !defined($ansVar)   ||
                !defined($DTType)) {
              _error "$obj interface information incomplete for $boundary.\n",
                     "  ANSYS Interface    = $intNo\n",
                     "  CFX Variable       = $cfxVar \n",
                     "  ANSYS Variable     = $ansVar \n",
                     "  Data Transfer Type = $DTType \n" ; 
              close(OUT) ;
              return 0 ;
            }

            # convert interface name
            $intNo=$interfaceMap{$intNo} ;

            $DTType = $self->translateDTType($DTType,$boundary) ;

            if (defined($cfxVar)) {
               print OUT "MFLC,SURF,CFX,\'$bcname\',\'$cfxVar\',ANSYS,$intNo,$ansVar,$DTType\n" ;
            }
          }
        }
      }
    } # end boundary list loop

    #
    ##############################################################################
    # Process Solver and Data Transfer Controls
    ##############################################################################
    #

    #
    # Coupling iteration controls
    #

    my ($maxCplgIt,$minCplgIt) ;
    $cclapi->getStringValue("/".$self->flow_name()."/SOLVER CONTROL/EXTERNAL SOLVER COUPLING CONTROL/COUPLING STEP CONTROL/Maximum Number of Coupling Iterations ",\$maxCplgIt) ;
    $cclapi->getStringValue("/".$self->flow_name()."/SOLVER CONTROL/EXTERNAL SOLVER COUPLING CONTROL/COUPLING STEP CONTROL/Minimum Number of Coupling Iterations ",\$minCplgIt) ;
    if (!defined($maxCplgIt) ||
        !defined($minCplgIt)) {
      _error "COUPLING STEP CONTROL information incomplete." ;
      close(OUT) ;
      return 0 ;
    }

    if ($adaptiveTimestepping) {
      print OUT "MFIT,$maxCplgIt,$minCplgIt,$targetCplgIter\n" ;
    }
    else {
      print OUT "MFIT,$maxCplgIt,$minCplgIt,$maxCplgIt\n" ;
    }

    #
    # Convergence target & relaxation factor
    #

    my $dataObj = "/".$self->flow_name()."/SOLVER CONTROL/EXTERNAL SOLVER COUPLING CONTROL/COUPLING DATA TRANSFER CONTROL" ;
    my ($convTarget,$rlx) ;
    $cclapi->getStringValue("$dataObj/Convergence Target",\$convTarget) ;
    $cclapi->getStringValue("$dataObj/Under Relaxation Factor",\$rlx) ;
    if (!defined($convTarget) || !defined($rlx)) {
      _error "$dataObj information incomplete." ;
      close(OUT) ;
      return 0 ;
    }
    print OUT "MFCO,ALL,$convTarget\n" ;
    print OUT "MFRE,ALL,$rlx,RELX\n" ;

    my @objList ;
    $cclapi->getChildObjectList($dataObj,\@objList) ;

    foreach my $obj (@objList) {
      $obj =~/(.*):(.*)/ ;  #get type & name
      my $type = $1 ;
      my $ansVar = $2 ;
      undef $convTarget ;
      undef $rlx ;
      if ($type eq "ANSYS VARIABLE") {
        $cclapi->getStringValue("$dataObj/$obj/Convergence Target",\$convTarget) ;
        if (defined($convTarget)) {
          print OUT "MFCO,$ansVar,$convTarget\n" ;
        }
        $cclapi->getStringValue("$dataObj/$obj/Under Relaxation Factor",\$rlx) ;
        if (defined($rlx)) {
          print OUT "MFRE,$ansVar,$rlx,RELX\n" ;
        }
      }
    }

    # 
    # Field Solver Sequencing
    #

    my $solveOrder ;
    $cclapi->getStringValue("/".$self->flow_name()."/SOLVER CONTROL/EXTERNAL SOLVER COUPLING CONTROL/COUPLING STEP CONTROL/SOLUTION SEQUENCE CONTROL/Solve ANSYS Fields",\$solveOrder) ;
    if (!defined($solveOrder)) {
      _error "SOLUTION SEQUENCE CONTROL not defined." ;
      close(OUT) ;
      return 0 ;
    }

    if ($solveOrder eq "After CFX Fields") {
      print OUT "MFPS,group1,ANSYS\n" ;
      print OUT "MFPS,group2,CFX\n" ;
      print OUT "MFSO,group2,group1\n" ;
    }
    elsif ($solveOrder eq "Before CFX Fields") {
      print OUT "MFPS,group1,ANSYS\n" ;
      print OUT "MFPS,group2,CFX\n" ;
      print OUT "MFSO,group1,group2\n" ;
    }
    elsif ($solveOrder eq "At Same Time as CFX Fields") {
      print OUT "MFPS,group1,ANSYS,CFX\n" ;
      print OUT "MFSO,group1\n" ;
    }
    else {
      _error "SOLUTION SEQUENCE CONTROL \'$solveOrder\' not recognized." ;
      close(OUT) ;
      return 0 ;
    }

    #
    ##############################################################################
    # Process output control objects (Deactivated due to DE5961)
    ##############################################################################
    #
    
    # my $outInterval = 999999 ;
    
    # my $dataObj1 = "/".$self->flow_name()."/OUTPUT CONTROL" ;
    # my @objList1 ;
    # $cclapi->getChildObjectList($dataObj1,\@objList1) ;

    # foreach my $obj (@objList1) {
    #   $obj =~/(.*):(.*)/ ;  #get type & name
    #   if ($1 eq "BACKUP RESULTS" || $1 eq "TRANSIENT RESULTS") {
    #     my ($outOpt,$outInt) ;
    #     $cclapi->getStringValue("${dataObj1}/$obj/OUTPUT FREQUENCY/Option",\$outOpt) ;
    #     if (defined($outOpt)) {
    #       if      ($outOpt eq "Every Coupling Step") {
    #         $outInterval = 1  ;
    #       }
    #       elsif ($outOpt eq "Coupling Step Interval") {
    #         $cclapi->getIntegerValue("${dataObj1}/$obj/OUTPUT FREQUENCY/Coupling Step Interval",\$outInt) ;
    #           if ($outInt < $outInterval) {
    #           $outInterval = $outInt  ;
    #         }
    #       }
    #     }
    #   }
    # }
    
    # if ($outInterval < 999999) {
    #   print OUT "MFOU,$outInterval\n" ;
    # }
    
    #
    ##############################################################################
    #  Closure
    ##############################################################################
    #
    
    print OUT "CMWRITE,$jobName,cm\n" ;
    print OUT "KBC,1\n" ;
    print OUT "/GST,ON,ON\n" ;
    print OUT "SOLVE\n" ;
    print OUT "SAVE\n" ;
    print OUT "CMWRITE,$jobName,cm\n" ;
    print OUT "FINISH\n" ;
    print OUT "/EXIT\n" ;
  
    close(OUT);  #DONE!

    $outfile=$self->outobj();
    $outfile->output('print', undef, undef, "Created ".$self->processed_ansys_input());
    return 1;
  }
  1 ;
}

################################################################################
################################################################################
##
## Helper Routines
##
################################################################################
################################################################################

#
################################################################################
# Convert the CCL to APDL data tranfer type
################################################################################
#

sub translateDTType {
 my $self=shift ;
 my ($DTType,$boundary) = @_ ;
 if ($DTType eq "Conservative") {
   $DTType = "CPP" ;
 } elsif ($DTType eq "Profile Preserving") {
   $DTType = "NONC" ;
 } else {
    print "Warning: Data Tranfer Type for $boundary not recognized.  Using \'NONC\'.\n" ;
  $DTType = "NONC" ;
 }
 return $DTType ;
}

#
################################################################################
# Does a conversion of the time value from/to the specified units
################################################################################
#

sub convertTime {
  my $self=shift ;
  my $value=shift ;
  my $fromUnit=shift ;
  my $toUnit=shift ;

  # Fill in a hash table of recongised time units and a conversion factor to seconds
  my $table = {} ;
  $table->{ms} = 1e-3 ;
  $table->{msec} = 1e-3 ;
  $table->{msecond} = 1e-3 ;
  $table->{s} = 1 ;
  $table->{sec} = 1 ;
  $table->{second} = 1 ;
  $table->{min} = 60 ;
  $table->{minute} = 60 ;
  $table->{h} = 3600 ;
  $table->{hr} = 3600 ;
  $table->{hour} = 3600 ;
  $table->{day} = 86400 ;

  #check we are using recognised units
  if (!defined($table->{$toUnit})) {
    _error "Time units of \'$toUnit\' (tounit) not recognized." ;
    return undef ;
  }
  if (!defined($table->{$fromUnit})) {
    _error "Time units of \'$fromUnit\' not recognized." ;
    return undef ;
  }

  #Convert from Inital Time units to Solution Units
  $value = $value*$table->{$fromUnit}/$table->{$toUnit} ;
  return $value ;
}

#
################################################################################
# Split value and units string from data
################################################################################
#

sub splitValue {
  my $self=shift ;
  my ($value) = @_ ;
  $value =~/(\S*)\s+\[(\S*)\]/ ;
  return ($1,$2) ;
}

#
################################################################################
# Heat Transfer Boundary Condition Procdessing
# --> Required to facilitate bulk and fluid dependent BCs
################################################################################
#

sub MFLC_HeatTransfer {
  my $self=shift ;
  my $cclapi=shift ;
  my $boundary=shift ;
  my $fluid=shift ;
  my $path=shift ;
  local *FHOut=shift ;
  my $intMap=shift ;
  
  my $opt="" ;
  $cclapi->getStringValue("$path/Option",\$opt) ;
  if ($opt eq "ANSYS MultiField") {

    #
    # Receive and send data handled together to enhance error trapping...
    # --> Send to ANSYS is conditional ; can only trap invalid  state if 
    #     not fluid specific

    my ($bcname,$recvData,$intNo,$sendData) ;
    $sendData="";
    $bcname = $cclapi->getName($boundary) ;
    $cclapi->getStringValue("$path/ANSYS Interface",\$intNo) ;
    $cclapi->getStringValue("$path/Receive from ANSYS",\$recvData) ;
    $cclapi->getStringValue("$path/Send to ANSYS",\$sendData) ;
    if (!defined($bcname) ||
        !defined($intNo)  ||
        !defined($recvData)) {
      if (!defined($fluid)) {        
        _error "HEAT TRANSFER interface information incomplete for $boundary." ;
      }
      else {
        _error "HEAT TRANSFER interface information incomplete for $fluid on $boundary." ;
      }
      return 0 ;
    }

    # convert interface name
    $intNo=$intMap->{$intNo} ;

    # Prefix recieve variable with fluid tag if possible
    if (defined($fluid)) {
      $recvData="$fluid.$recvData" ;
    }

    #
    # Receive Temperature
    if ($recvData =~ /Temperature/) {
      print FHOut "MFLC,SURF,ANSYS,$intNo,TEMP,CFX,\'$bcname\',\'$recvData\',NONC\n" ;

      # Send Wall Heat Flow
      if ($sendData eq "Wall Heat Flow") {
        print FHOut "MFLC,SURF,CFX,\'$bcname\',\'$sendData\',ANSYS,$intNo,HFLU,CPP\n" ;
      }
      # Send Wall Heat Flux
      elsif ($sendData eq "Wall Heat Flux") {
        print FHOut "MFLC,SURF,CFX,\'$bcname\',\'$sendData\',ANSYS,$intNo,HFLU,NONC\n" ;
      }
      elsif ($sendData ne "None" && !defined($fluid)) {
        _error "Send to ANSYS, $sendData, not recognized for HEAT TRANSFER on $boundary." ;
        return 0 ;
      }
    }

    #
    # Receive Wall Heat Flow
    elsif ($recvData =~ /Wall Heat Flow/) {
      print FHOut "MFLC,SURF,ANSYS,$intNo,HFLU,CFX,\'$bcname\',\'$recvData\',CPP\n" ;

      if ($sendData eq "Temperature") {
        print FHOut "MFLC,SURF,CFX,\'$bcname\',\'$sendData\',ANSYS,$intNo,TEMP,NONC\n" ;
      }
      elsif ($sendData ne "None" && !defined($fluid)) {
        _error "Send to ANSYS, $sendData, not recognized for HEAT TRANSFER on $boundary." ;
        return 0 ;
      }
    }

    #
    # Receive Wall Heat Flux
    elsif ($recvData =~ /Wall Heat Flux/) {
      print FHOut "MFLC,SURF,ANSYS,$intNo,HFLU,CFX,\'$bcname\',\'$recvData\',NONC\n" ;

      if ($sendData eq "Temperature") {
        print FHOut "MFLC,SURF,CFX,\'$bcname\',\'$sendData\',ANSYS,$intNo,TEMP,NONC\n" ;
      }
      elsif ($sendData ne "None" && !defined($fluid)) {
        _error "Send to ANSYS, $sendData, not recognized for HEAT TRANSFER on $boundary." ;
        return 0 ;
      }
    }
    else {
      _warn "Receive from ANSYS not recognized on $boundary.  Interface information not written.\n" ;
    }  
  }  
  1 ;
}

1 ;
