#!/usr/bin/env python

import os
import re
import math

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

import GridSimTk
import UtilitiesSimTk
import LogSimTk 

endOfLine                  = '\n'
machineEpsilon             = 1.0e-05

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

class IsimGridSimTk( GridSimTk.GridSimTk ): # {
   """Isim potential"""

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

   def __init__( self ): # {
      """Constructor for IsimGridSimTk"""
     
      GridSimTk.GridSimTk.__init__( self )

   # } end of __init__(

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

   # box range accessors for class

   def _setGridParameters( self ): # {
      """Set accessor for box range"""

      # indices into sort list to min/max and middle

      lowIndex     = 0
      highIndex    = self.getTotalGridPoints() - 1
      # originIndex  = ( self.getTotalGridPoints() )/2
      originIndex  = 0

      xCount      = int( pow( self.getTotalGridPoints(), 1.0/3.0 ) + machineEpsilon )

      self._xGrid = xCount
      self._yGrid = xCount
      self._zGrid = xCount

      # sort coordinates

      xList = self._xCoordinateList[:]
      xList.sort( )

      yList = self._yCoordinateList[:]
      yList.sort( )

      zList = self._zCoordinateList[:]
      zList.sort( )
      
      self._boxRange = [ 
                         [ xList[lowIndex], xList[highIndex] ],
                         [ yList[lowIndex], yList[highIndex] ],
                         [ zList[lowIndex], zList[highIndex] ],
                       ]

      self._xOrigin = xList[originIndex]
      self._yOrigin = yList[originIndex]
      self._zOrigin = zList[originIndex]

      firstIndex    = self._getFirstDiffInList( xList, 0 ) 
      self._xDelta  = xList[firstIndex+1] - xList[firstIndex]

      firstIndex    = self._getFirstDiffInList( yList, 0 ) 
      self._yDelta  = yList[firstIndex+1] - yList[firstIndex]

      firstIndex    = self._getFirstDiffInList( zList, 0 ) 
      self._zDelta  = zList[firstIndex+1] - zList[firstIndex]

      return None

   # } end of _setGridParameters

   def _getFirstDiffInList( self, sortedList, startIndex ): # {
      """Find first index in list where elements differ by more than machine epsilon
         start at startIndex (if not set, then start at 0
      """

      if startIndex == None:
          startIndex = 0

      maxIndex = len( sortedList ) - 1

      while abs( sortedList[startIndex+1] - sortedList[startIndex] ) < machineEpsilon and startIndex < maxIndex:
          startIndex += 1

      if startIndex == maxIndex:
          return -1
      else:
          return startIndex

   # } end of_getFirstDiffInList 

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

   def readIsimGridPotentialFile( self, isimPotentialFileName ): # {
      """A method to read ISIM a formatted potential
   
      """
    
      # This procedure reads in a ISIM potential grid
   
      # log info
   
      logReference = self.getLogReference()

      parsedPath   = UtilitiesSimTk.parseFileName( __file__ )
      methodName   = parsedPath[1] + '::readIsimGridPotentialFile';
      message      = methodName + '\n   reading file=<' + isimPotentialFileName + '>'
      logReference.info( message )
   
      # ----------------------------------------------------------------------------------------------
   
      # open file -- log error if file can not be opened and return None
   
      try:
         isimPotentialFile = open( isimPotentialFileName, "r" )
      except IOError:
         logReference.error( methodName + ' file=<' + isimPotentialFileName + '> could not be opened.' );
         return None
    
      # ----------------------------------------------------------------------------------------------
   
      # read in grid and grid potential values
   
      self._xCoordinateList = []
      self._yCoordinateList = []
      self._zCoordinateList = []
      self._potentialList   = []
      count          = 0
      logReference.info( 'Reading in grid values' )
   
      for nextLine in isimPotentialFile:
         nextLine   = nextLine[:-1] 
         lineTokens = nextLine.split()
         self._xCoordinateList.append( float( lineTokens[0] ) )
         self._yCoordinateList.append( float( lineTokens[1] ) )
         self._zCoordinateList.append( float( lineTokens[2] ) )
         self._potentialList.append( float( lineTokens[3] ) )
         self.addGridPoint( count,
                            self._xCoordinateList[count],
                            self._yCoordinateList[count],
                            self._zCoordinateList[count],
                            self._potentialList[count],
                            None, None )
         count     += 1
   
      isimPotentialFile.close()
      self.setTotalGridPoints( len( self._xCoordinateList ) )
      self._setGridParameters()

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

      # log stats

      message = self.getBoxStats()
      logReference.info( message )

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

   # } end of readIsimGridPotentialFile

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

# } end of class IsimGridSimTk

#gridPotentialFileName         = 'GRID_POTENTIAL_0000600'
#gridChargeDensityFileName     = 'GRID_CHARGE_DENSITY_0000600'
#gridNumberDensitiesFileName   = 'GRID_NUMBER_DENSITIES_0000600'
#gridPotentialDxFileName       = 'GRID_POTENTIAL_0000600.dx'
#
#directoryName                 = '/Users/simbios/friedrim/data/isim'
#
#grid                          = IsimGridSimTk()
#grid.setWorkingDirectory( directoryName )
#
#grid.setGridPotentialFileName( gridPotentialFileName, 1 )
#grid.setGridChargeDensityFileName( gridChargeDensityFileName, 1 )
#grid.setGridNumberDensityFileName( gridNumberDensitiesFileName, 1 )
#grid.setGridPotentialDxFileName( gridPotentialDxFileName, 1 )
#
#f1 = grid.getGridPotentialFileName( );
#f2 = grid.getGridChargeDensityFileName( );
#f3 = grid.getGridNumberDensityFileName( );
#f4 = grid.getGridPotentialDxFileName( );
#print "\nf1=<" + str( f1 ) + '>\nf2=' + str( f2 ) + '>\nf3=<' + str( f3 ) + ">\nf4=<" + str( f4 ) + ">\n";
#
#grid.readIsimGridPotentialFile( grid.getGridPotentialFileName( ) )
#grid.writeIsimGridPotentialDxFile( grid.getGridPotentialDxFileName( ) )
#grid.writeIsimGridPotentialDxFile( grid.getGridPotentialDxFileName( ) )
