#! /usr/bin/env python2
# -*- coding: utf-8 -*-

import sys, os, stat, pprint
from soma.minf.api import readMinf, writeMinf

def bytesToString( size ):
  unitSize = 0
  unit = None
  if size < 2:
    result = '%(bytes)d byte'
  elif size < 1024:
    result = '%(bytes)d byte'
  else:
    result = '%(unitSize).1f %(unit)s (%(bytes)d bytes)'
    unitSize = int( size ) / 1024.0
    unit = 'Kb'
    if unitSize >= 1024:
      unitSize = int( unitSize ) / 1024.0
      unit = 'Mb'
      if unitSize >= 1024:
        unitSize = int( unitSize ) / 1024.0
        unit = 'Gb'
        if unitSize >= 1024:
          unitSize = int( unitSize ) / 1024.0
          unit = 'Tb'
  return result % { 'unitSize': unitSize, 'unit': unit, 'bytes': size }


if len( sys.argv ) > 1:
  # Build a list of minf file to process.
  minfs = []
  if sys.argv[ 1 ] in ( '-f', '--force' ):
    forceWrite = True
    stack = sys.argv[ 2: ]
  else:
    forceWrite = False
    stack = sys.argv[ 1: ]
  minfTotalSize = 0
  while stack:
    item = stack.pop( 0 )
    s = os.stat( item )
    if stat.S_ISDIR( s.st_mode ):
      try:
        stack += [os.path.join(item, i) for i in os.listdir( item )]
      except OSError, e:
        print >> sys.stderr, 'Ignoring directory', repr( item ) +' :',e.strerror
    elif item.endswith( '.minf' ):
      minfTotalSize += s.st_size
      minfs.append( item )
  print 'Found', len( minfs ), 'minf files'
  print 'Total size:', bytesToString( minfTotalSize )

  # Processing minf files
  totalAttributesDeleted = 0
  totalMinfsModified = 0
  totalMinfsDeleted = 0
  totalUnreadable = 0
  newTotalSize = 0
  count = 1
  for minf in minfs:
    sys.stdout.write( '\rProcessing %d on %d' % ( count, len(minfs) ) )
    sys.stdout.flush()
    # Read minf file in m
    m = {}
    try:
      minfFileContent = open( minf ).read()
      m = readMinf( minf )[ 0 ]
      if m is None:
        m = {}
    except Exception, e:
      totalUnreadable += 1
      print >> sys.stderr, '\nCannot read "' + minf + '" (', e, ')'
      m = None
    # Remove attributes from minf file
    if m:
      rewrite = False
      for key in [i for i in m.keys() if \
          i.startswith( 'pool_header' ) or i == 'byte_swapping']:
        totalAttributesDeleted += 1
        rewrite = True
        del m[ key ]
      # Write minf file if modified
      if rewrite:
        totalMinfsModified += 1
      if rewrite or forceWrite:
        if m:
          writeMinf( minf, ( m, ) )
          # Check that written minf has nor error
          m2 = {}
          try:
            m2 = readMinf( minf )[ 0 ]
          except:
            m2 = None
          if m2 != m:
            f = open( minf, 'w' )
            f.write( minfFileContent )
            f.close()
            print >> sys.stderr, '-'*50 + '\n' + newMinfContent + '\n' + '-'*50
            raise RuntimeError( 'Error while checking modification of "' + minf + '" (initial content restored)' )
        else:
          # No more attributes in minf => file is deleted
          totalMinfsDeleted += 1
          os.remove( minf )
    elif m is not None:
      # minf was empty => file is deleted
      totalMinfsDeleted += 1
      os.remove( minf )
      
    if os.path.exists( minf ):
      newTotalSize += os.stat( minf ).st_size
    count += 1
  print '\nRemoved', totalAttributesDeleted, 'attributes in', \
        totalMinfsModified, 'files'
  print 'Deleted', totalMinfsDeleted , 'empty minf files'
  print 'New total size:', bytesToString( newTotalSize )
  if totalUnreadable:
    print totalUnreadable, 'files where not readable'
else:
  print >> sys.stderr, '''Read minf files, remove unused attributes, rewrite them in XML format
and check the written file is correct (otherwise initial content is kept).

Usage: cleanMinf [options] <filesOrDirectories>
Options:
  -f or --force : Force writing of minf files even if no attribute have been 
                  changed (can be used to convert to XML format).
'''
