#!/usr/bin/env python

# ----------------------------------------------------------------------------------------------------

import os, math
import re

# ----------------------------------------------------------------------------------------------------

import traceback

# ----------------------------------------------------------------------------------------------------

# SimTk modules

import BaseObjectSimTk
from UtilitiesSimTk import *
import LogSimTk 

# ----------------------------------------------------------------------------------------------------

def strToNumericCmpIReverse( x, y ):
   return int( y ) - int( x )

def strToNumericCmpI( x, y ):
   return int( x ) - int( y )

# ----------------------------------------------------------------------------------------------------

class IsimGridFileSimTk( BaseObjectSimTk.BaseObjectSimTk ): # {

   # -------------------------------------------------------------------------------------------------

   def __init__( self, isimDisplay, fileName ): # {

      """Constructor for IsimGridFileSimTk"""

      BaseObjectSimTk.BaseObjectSimTk.__init__( self )
 
      # attributes

      self._isimDisplay                     = isimDisplay
      self._fileName                        = fileName 

      # the file prefix will be set in derived classes

      self._filePrefix                      = None 
      self._fileFormat                      = None 

      # step index

      if fileName is not None:
         generateStepGivenFileName( fileName )
         self.setFileFormatBasedOnFileName()
      else:
         self._stepIndex                    = 0

   # } end of __init__

   # -------------------------------------------------------------------------------------------------

   # accessors for file name 

   def setFileName( self, fileName ): # {
      """Set accessor for FileName"""

      if fileName is not self._fileName:
         self.setStepIndexGivenFileName( fileName )

      self._fileName = fileName 

   # } end of setFileName

   # -------------------------------------------------------------------------------------------------

   def getFileName( self ): # {
      """Get accessor for FileName"""
      return self._fileName;
   # } end of getFileName

   # -------------------------------------------------------------------------------------------------

   # accessors for file prefix 

   def setFilePrefix( self, filePrefix ): # {
      """Set accessor for FilePrefix"""
      self._filePrefix = filePrefix 

   # } end of setFilePrefix

   # -------------------------------------------------------------------------------------------------

   def getFilePrefix( self ): # {
      """Get accessor for FilePrefix"""
      return self._filePrefix;
   # } end of getFilePrefix

   # -------------------------------------------------------------------------------------------------

   # accessors for file format

   def setFileFormat( self, fileFormat ): # {

      """Set accessor for file format"""

      self._fileFormat = fileFormat

   # } end of setFileFormat

   # -------------------------------------------------------------------------------------------------

   def getFileFormat( self ): # {

      """Get accessor for file format"""

      return self._fileFormat

   # } end of getFileFormat

   # -------------------------------------------------------------------------------------------------

   # accessors for step index

   def setStepIndex( self, stepIndex ): # {

      """Set accessor for step index"""

      self._stepIndex = stepIndex

   # } end of setStepIndex

   def getStepIndex( self ): # {

      """Get accessor for step index"""

      return self._stepIndex

   # } end of getStepIndex

   # -------------------------------------------------------------------------------------------------

   # accessors for Isim display

   def setIsimDisplay( self, isimDisplay ): # {

      """Set accessor for Isim display"""

      self._isimDisplay = isimDisplay

   # } end of setIsimDisplay

   # -------------------------------------------------------------------------------------------------

   def getIsimDisplay( self ): # {

      """Get accessor for Isim display"""

      return self._isimDisplay

   # } end of getIsimDisplay

   # -------------------------------------------------------------------------------------------------

   # generate format string used in building file names

   def getFullFileName( self, mcStep, fileSuffix = None, ionIndex = -1 ): # {
      """Get full file name"""

      return self._isimDisplay.buildFullFileName( self.getFilePrefix(), mcStep, fileSuffix, ionIndex )

   # } end of getFullFileName

   # -------------------------------------------------------------------------------------------------

   # get file name

   def getFileName( self, mcStep, fileSuffix = None, ionIndex = -1 ): # {
      """Get file name"""

      return self._isimDisplay.buildFileName( self.getFilePrefix(), mcStep, fileSuffix, ionIndex )

   # } end of getFileName

   # -------------------------------------------------------------------------------------------------

   # generate file name give MC step

   def generateFileNameGivenStep( self, step, fileSuffix=None, requiredDigits=None ): # {
      """Helper method to generate file names
         Step is the MC step index
         fileSuffix is optional -- appended to file name
         requiredDigits number of digits in step name (defaults to 7)
         file name prefix is obtained via self.getFilePrefix()
      """

      return self._isimDisplay.buildPartialFileNameGivenStep( self.getFilePrefix(), step, fileSuffix, requiredDigits )

   # } end of generateFileNameGivenStep

   # -------------------------------------------------------------------------------------------------

   # parse MC step from file name

   def generateStepGivenFileName( fileName, stepIndex = -1, separator = '_' ): # {
      """Helper method to get MS step from file name: 'GRID_POTENTIAL_0000600.dx' would
         return 600
      """

      numberDensityMatch = re.compile( 'GRID_NUMBER_DENSITIES' )
      if numberDensityMatch.match( fileName ):
         stepIndex = -3
      else:
         stepIndex = -1

      # (1) remove file suffix, if present
      # (2) split name by '_'
      # (3) remove initial zeros

      fileName    = UtilitiesSimTk.removeSuffix( fileName )
      sections    = fileName.split( separator )
      stepSection = sections[stepIndex]
      # print "QQQ In generateStepGivenFileName stepIndex=" + str( stepIndex ) + ' step=' + stepSection + ' file=' + fileName
      return stepSection.lstrip( '0' )

   generateStepGivenFileName = staticmethod( generateStepGivenFileName )

   # } end of generateStepGivenFileName

   # -------------------------------------------------------------------------------------------------

   # get files of specified type (grid_potential, charge density, number density) 

   def getAvailableFiles( workingDirectory, fileType, ionIndex = None ): # {
      """Get files of the specified type present in the working directory"""

      # get list of all files of specified type

      regExMatchType = re.compile( fileType )  
      fileList       = UtilitiesSimTk.getFilesInDirectory( workingDirectory,
                                                           regExMatchType, None )

      # diagnostics

      # print "QQQ  getAvailableFiles: Files in fileList type=" + fileType
      # print str( fileList )

      # filter ion types if ionIndex was set

      if ionIndex is not None:
         regExMatchTypeId     = re.compile( '_' + str( ionIndex ) + '_' )  
         regExMatchTypeSuffix = re.compile( '.dx$' )  
         newFileList = []
         for file in fileList:
            if regExMatchTypeId.search( file ) and regExMatchTypeSuffix.search( file ):
               newFileList.append( file )
         fileList = newFileList

      return fileList

   # designate method as a static method for class

   getAvailableFiles= staticmethod( getAvailableFiles )

   # } end of getAvailableFiles

   # -------------------------------------------------------------------------------------------------

   # get MC steps for files of specified type

   def getAvailableMcStepsForFileOfSpecifiedType( workingDirectory, fileType, ionIndex = None ): # {
      """Get MC steps for the specified file type present in the working directory"""
      fileList = IsimGridFileSimTk.getAvailableFiles( workingDirectory, fileType, ionIndex )
      stepDict = {}
      for file in fileList:
         value = IsimGridFileSimTk.generateStepGivenFileName( file )
         if value.isdigit():
            stepDict[value] = 1

      stepList = stepDict.keys()

      if stepList is not None: 
         # stepList.sort( cmp=strToNumericCmpIReverse )
         stepList.sort( strToNumericCmpIReverse )

      return stepList

   getAvailableMcStepsForFileOfSpecifiedType = staticmethod( getAvailableMcStepsForFileOfSpecifiedType )

   # } end of getAvailableMcStepsForFileOfSpecifiedType

   # -------------------------------------------------------------------------------------------------

   def getInstanceGivenFilePrefix( filePrefix, isimDisplay ): # {

      """Factory method to get class instance given file prefix"""

      rePrefix = re.compile( filePrefix )

      if rePrefix.match( IsimPotentialFileSimTk.getFilePrefix() ):
         return IsimPotentialFileSimTk( isimDisplay )
      elif rePrefix.match( IsimChargeDensityFileSimTk.getFilePrefix() ):
         return IsimChargeDensityFileSimTk( isimDisplay )
      elif rePrefix.match( IsimNumberDensityFileSimTk.getFilePrefix() ):
         return IsimNumberDensityFileSimTk( isimDisplay )
      else:
         raise valueError, ('filePrefix=<' + filePrefix + '> unrecognized.')

   getInstanceGivenFilePrefix = staticmethod( getInstanceGivenFilePrefix )

   # } end of getInstanceGivenFilePrefix

   # -------------------------------------------------------------------------------------------------

# } end of class IsimGridFileSimTk

class IsimPotentialFileSimTk( IsimGridFileSimTk ): # {

   # -------------------------------------------------------------------------------------------------

   def __init__( self, isimDisplay, fileName = None ): # {

      """Constructor for IsimPotentialFileSimTk"""

      IsimGridFileSimTk.__init__( self, isimDisplay, fileName )
 
      # attributes

      self._filePrefix                      = IsimPotentialFileSimTk.getFilePrefix()

   # } end of __init__

   # -------------------------------------------------------------------------------------------------

   def getFilePrefix( ): # {
      """IsimPotentialFileSimTk"""
      return 'GRID_POTENTIAL_'
   getFilePrefix = staticmethod( getFilePrefix )

   # } end of getFilePrefix

   def getAbbreviation( self ): # {
      """IsimPotentialFileSimTk"""
      return 'P'

   # } end of getAbbreviation

# } end of class IsimPotentialFileSimTk

class IsimChargeDensityFileSimTk( IsimGridFileSimTk ): # {

   # -------------------------------------------------------------------------------------------------

   def __init__( self, isimDisplay, fileName = None ): # {

      """Constructor for IsimChargeDensityFileSimTk"""

      IsimGridFileSimTk.__init__( self, isimDisplay, fileName )
 
      # attributes

      self._filePrefix                      = IsimChargeDensityFileSimTk.getFilePrefix()

   # } end of __init__

   # -------------------------------------------------------------------------------------------------

   def getFilePrefix( ): # {
      """IsimChargeDensityFileSimTk"""
      return 'GRID_CHARGE_DENSITY_'
   getFilePrefix = staticmethod( getFilePrefix )

   # } end of getFilePrefix

   def getAbbreviation( self ): # {
      """Get abbreviation for file type"""
      return 'CD'

# } end of class IsimChargeDensityFileSimTk

class IsimNumberDensityFileSimTk( IsimGridFileSimTk ): # {

   # -------------------------------------------------------------------------------------------------

   def __init__( self, isimDisplay, fileName = None ): # {

      """Constructor for IsimNumberDensityFileSimTk"""

      IsimGridFileSimTk.__init__( self, isimDisplay, fileName )
 
      # attributes

      self._filePrefix                      = IsimNumberDensityFileSimTk.getFilePrefix()
      self._ionIndex                        = -1
      self._ionName                         = None

      self._ionFileNameStepIndex            = -3 
      self._ionFileNameIdIndex              = -2 
      self._ionFileNameIonNameIndex         = -1 

      self._ionAbbreviation                 = None

   # } end of __init__

   # -------------------------------------------------------------------------------------------------

   def getFilePrefix( ): # {
      """IsimNumberDensityFileSimTk"""
      return 'GRID_NUMBER_DENSITIES_'
   getFilePrefix = staticmethod( getFilePrefix )

   # } end of getFilePrefix

   def getAbbreviation( self ): # {
      """Get abbreviation for file type"""
      return self._ionAbbreviation

   # -------------------------------------------------------------------------------------------------

   # accessors for ion index

   def setIonIndex( self, ionIndex ): # {

      """Set accessor for ion index"""

      self._ionIndex = ionIndex

   # } end of setIonIndex

   def getIonIndex( self ): # {

      """Get accessor for ion index"""

      return self._ionIndex

   # } end of getIonIndex

   # -------------------------------------------------------------------------------------------------

   # accessors for ion name

   def setIonName( self, ionName ): # {

      """Set accessor for ion name"""

      self._ionName = ionName

   # } end of setIonName

   def getIonName( self ): # {

      """Get accessor for ion name"""

      return self._ionName

   # } end of getIonName

   # -------------------------------------------------------------------------------------------------

   # accessors for ion abbreviation

   def setIonAbbreviation( self, ionAbbreviation ): # {

      """Set accessor for ion abbreviation"""

      self._ionAbbreviation = ionAbbreviation

   # } end of setIonAbbreviation

   def getIonAbbreviation( self ): # {

      """Get accessor for ion abbreviation"""

      return self._ionAbbreviation

   # } end of getIonAbbreviation

   # -------------------------------------------------------------------------------------------------

   # parse MC step from file name
   # overrides super class method

   def generateStepGivenFileName( self, fileName, stepIndex = -1, separator = '_' ): # {
      """Helper method to get MS step from file name: 'NUMBER_DENSITIES_0000600_1.dx' would
         return 600
      """

      # use -2 index instead of default -1 to get step field

      self._stepIndex = IsimGridFileSimTk.generateStepGivenFileName( self, fileName, self._ionFileNameStepIndex, separator )
      return self._stepIndex

   # } end of generateStepGivenFileName

   # -------------------------------------------------------------------------------------------------

   # parse ion index from file name
   # uses related super class method

   def generateIonIndexGivenFileName( self, fileName, stepIndex = -1, separator = '_' ): # {
      """Helper method to get ion index from file name: 'NUMBER_DENSITIES_0000600_1_CALCIUM.dx' would
         return 1
      """

      # use -1 index to get ion index field

      self._ionIndex = IsimGridFileSimTk.generateStepGivenFileName( self, fileName, self._ionFileNameIdIndex, separator )
      return self._ionIndex

   # } end of generateIonIndexGivenFileName

   # -------------------------------------------------------------------------------------------------

# } end of class IsimNumberDensityFileSimTk

