"""
Reusable stuff.
"""

import struct

def bytes_to_hex_str(bytes):
  """  
  Get the hex string representation of the bytes.  
  """
  return ''.join([byte_to_hex(byte) for byte in bytes])

def byte_to_hex(byte):
  """
  Convert byte to hex representation: 'A' -> '41'
  """
  hi = ord(byte)/16
  lo = ord(byte)%16
  if hi>9: hi=hi+7
  if lo>9: lo=lo+7
  return chr(48+hi)+chr(48+lo)

def get_printable_string(str):
  """
  Replace non-printable chars with '.'
  """
  new_str = ''
  for char in str:
    if ord(char) < 32 or ord(char) > 127:
      char = '.'
    new_str = new_str + char
  return new_str

class FileReader:

  TYPES_DICT = {'SIGNEDINTEGER': 'i', 'INTEGER': 'I', 'SHORT': 'h', 'BYTE': 'B', 'FLOAT': 'f', 'LONG': 'L', 'DOUBLE': 'd'}
  FORMATS_DICT = {'SIGNEDINTEGER': '%08X', 'INTEGER': '%08X', 'INTEGER': '%08X', 'SHORT': '%04X', 'BYTE': '%02X', 
                  'FLOAT': '%04X', 'LONG': '%08X', 'DOUBLE': '%08X',
                  'BYTES': '%s'
                  }
  
  def __init__(self, filename):
    self._input = open(filename, 'rb')
    
  def read(self, type):
    offset = self._input.tell()
    translated_type = FileReader.TYPES_DICT[type]         # right type for struct
    size = struct.calcsize(translated_type)
    data = self._input.read(size)#[::-1]                  # read and reverse (struct could do this)
    value = struct.unpack('>' + translated_type, data)[0] # unpack + [0]
    return offset, value, data
  
  def read_raw(self, length):
    offset = self._input.tell()
    return offset, self._input.read(length)

  def read_and_raw(self, type):
    offset = self._input.tell()
    translated_type = FileReader.TYPES_DICT[type]        # right type for struct
    size = struct.calcsize(translated_type)
    bytes = self._input.read(size)
    data = bytes[::-1]                                   # read and reverse
    value = struct.unpack(translated_type, data)[0]      # unpack + [0]
    return offset, value, bytes
