text: # -*- coding: utf-8 -*-
  ##############################################################################
  # Copyright (c), Gianfranco Ulian and Giovanni Valdre'.                      #
  # All rights reserved.                                                       #
  #                                                                            #
  # This file is part of the Quantas code.                                     #
  #                                                                            #
  # For further information on the license, see the LICENSE file               #
  ##############################################################################
  
  """
  This module contains a class used to export data generated by Quantas from the
  HDF5 format to text file.
  
  Formatting constants, functions and classes are employed to export data in
  different file formats.
  """
  
  import os
  from quantas.IO.hdf5_reader import QuantasHDF5Reader
  
  
  class QuantasHDF5Export(object):
  
      def __init__(self):
          return
  
      def run(self):
          """
          This method begins the export of the data contained in the HDF5 file
          generated by Quantas.
          """
          stop = False
          while not stop:
              print()
              print('Select quantity to export')
              print("[type 'help' to see available results, or 'quit' to exit]")
              var = input('Selection: ')
              if var.lower() == 'help':
                  self.report_input_data()
                  continue
              elif var.lower() == 'quit':
                  stop = True
                  continue
              elif not self._reader.has_data(var):
                  print('Error: {}'.format(self._reader.has_data(var)))
                  continue
              else:
                  outfile = self._outbase + '_{}'.format(var) + '.dat'
                  self.export_data(var, outfile)
                  print()
                  msg = 'Would you like to export other results? [y/N] '
                  choice = 'go'
                  while (choice.lower() != 'n' or choice.lower() != 'y'
                         or choice != ''):
                      choice = input(msg)
                      if choice == '' or choice.lower() == 'n':
                          stop = True
                          break
                      elif choice.lower() == 'y':
                          break
          return True
  
      def read_input(self, hdf5file):
          error = None
          self._hdf5file = hdf5file
          self._outbase = os.path.splitext(self._hdf5file)[0]
          #
          self._reader = QuantasHDF5Reader(self._hdf5file)
          self._reader.read()
          if 'This file was created with Quantas.' not in self._reader.info:
              error = 'The selected file does not appear as a Quantas output'
              return error
          self.get_file_data()
          return error
  
      def report_input_data(self):
          print(self._reader.info)
          return
  
      def get_file_data(self):
          if '(HA)' in self._reader.info:
              self._type = 'ha'
              self._x1 = 'T'
              self._x2 = 'V'
          if '(QHA)' in self._reader.info:
              self._type = 'qha'
              self._x1 = 'T'
              self._x2 = 'P'
          return
  
      def export_data(self, varname, outfile):
          tmpfile = input(
              'Select output file for the selected data: ({})'.format(outfile)
              )
          if tmpfile != '':
              outfile = tmpfile
          if self._type == 'qha' or self._type == 'ha':
              data = QHATableFile(
                  outfile,
                  self._reader.get_data(self._x1),
                  self._reader.get_attribute(self._x1, 'desc'),
                  self._reader.get_attribute(self._x1, 'unit'),
                  self._reader.get_data(self._x2),
                  self._reader.get_attribute(self._x2, 'desc'),
                  self._reader.get_attribute(self._x2, 'unit'),
                  self._reader.get_data(varname),
                  self._reader.get_attribute(varname, 'desc'),
                  self._reader.get_attribute(varname, 'unit'),
                  self._reader.get_attribute(varname, 'desc')
                  )
              data.write()
          print('Results exported correctly!')
          return
  
  
  # -----------------------------------------------------------------------------#
  # Formatting constants
  # -----------------------------------------------------------------------------#
  sep = '{s:{c}<{w}}{s}'                          # Row separator format
  head = '{s}{v1:{c}^{w1}}{s}{v2:{c}^{w2}}{s}'    # Header format
  subhd = '{s}{v:{c}<{w}}{s}'                     # Sub-Header format
  t_space = 10                                    # Space for T values
  t_line = '{s}{t:{c}^{w}}'                       # T format
  d_space = 20                                    # Space for data values
  d_line = '{s}{d:{c}^{w}}'                       # Data format
  endrow = '{s:{c}>{w}}'                          # End of row format
  ttype = '%.2f'                                  # T numeric format
  etype = '%.12E'                                 # Energy numeric format
  vtype = '%.8f'                                  # Volume numeric format
  ptype = '%.8f'                                  # Pressure numeric format
  stype = '%.s'                                   # Text format
  nl = '\n'                                       # New line
  fileHeader = '*- This file was created using Quantas -*\n'
  
  
  # -----------------------------------------------------------------------------#
  # Writing functions
  # -----------------------------------------------------------------------------#
  def calc_space(n):
      totw = (n * d_space) + t_space + (n + 1)
      dataw = (n * d_space) + (n - 1)
      return totw, dataw
  
  
  def separator(totw, sym, char):
      return sep.format(s=sym, w=totw, c=char)
  
  
  def header(dataw, tag1, tag2):
      return head.format(s=' ', v1=tag1, w1=t_space, v2=tag2, w2=dataw, c=' ')
  
  
  def subhead(totw, tag):
      return subhd.format(s=' ', v=tag, w=totw-1, c='')
  
  
  def put_data(x, dtype):
      if x == '':
          value = t_line.format(s=' ', t='', w=t_space, c=' ')
      elif dtype == ttype:
          value = t_line.format(s=' ', t=str(dtype % x), w=t_space, c=' ')
      elif dtype == stype:
          value = d_line.format(s=' ', d=(x), w=d_space, c=' ')
      else:
          value = d_line.format(s=' ', d=str(dtype % x), w=d_space, c=' ')
      return value
  
  
  def newrow():
      return endrow.format(s=' \n', w=0, c=' ')
  
  
  # -----------------------------------------------------------------------------#
  # Writing classes
  # -----------------------------------------------------------------------------#
  class QHATableFile():
      """
      File export class for (Q)HA results. It exports data in a table format
      in selected file.
  
      Parameters
      ----------
  
      outfile = str
          name of the file where data will be saved
  
      var1 = ndarray
          First independent variable data
  
      var1Name = str
          Name of the variable of var1
  
      var1Unit = str
          Measurement unit of var1
  
      var2 = ndarray
          Second independent variable data
  
      var2Name = str
          Name of the variable of var2
  
      var2Unit = str
          Measurement unit of var1
  
      res = ndarray
          Results in a 2D-array format (1D or 2D)
  
      resName = str
          Name of the result data
  
      resUnit = str
          Measurement unit of result data
  
      desc = str, optional
          Description to be included in the file header
  
      """
      def __init__(self, outfile,
                   x, xname, xunit,
                   y, yname, yunit,
                   z, zname, zunit,
                   description=None):
          self.outfile = outfile
          #
          # Set x data and style
          self.x = x
          self.xname = xname
          self.xstyle, self.xlabel = self._set_style(xname, xunit)
          #
          # Set variable 2 data and style
          self.y = y
          self.yname = yname
          self.ystyle, self.ylabel = self._set_style(yname, yunit)
          #
          # Set results data and style
          self.z = z
          self.zname = zname
          self.zunit = zunit
          self.zstyle, self.zlabel = self._set_style(zname, zunit)
          #
          # Set description in the file, if any
          if description != ('' or None):
              self.description = description
          else:
              self.description = None
          return
  
      def _set_style(self, name, unit):
          if name == 'Temperature':
              style = ttype
              label = 'T (' + unit + ')'
          elif 'volume' in name.lower():
              style = vtype
              label = 'Volume (' + unit + ')'
          elif 'bulk modulus' in name.lower() or name == 'Pressure':
              style = ptype
              label = 'Pressure (' + unit + ')'
          else:
              style = etype
              label = name + ' (' + unit + ')'
          return style, label
  
      def write(self):
          f = open(self.outfile, 'wt', encoding='utf8')
          totw, dataw = calc_space(len(self.y))
          # Write the header
          f.write(fileHeader)
          f.write(nl)
          if not isinstance(self.description, type(None)):
              f.write(self.description)
          f.write(nl)
          f.write('Data in ' + self.zunit + ' units')
          f.write(nl)
          f.write(nl)
          # Start constructing the table
          f.write(separator(totw, '+', '-'))
          f.write(nl)
          f.write(header(dataw, self.xlabel, self.ylabel))
          f.write(nl)
          f.write(put_data('', ttype))
          for i in range(len(self.y)):
              f.write(put_data(self.y[i], self.ystyle))
          f.write(newrow())
          f.write(separator(totw, '+', '='))
          f.write(nl)
          for i in range(len(self.x)):
              f.write(put_data(self.x[i], self.xstyle))
              for j in range(len(self.y)):
                  f.write(put_data(self.z[i][j], self.zstyle))
              f.write(newrow())
          f.write(separator(totw, '+', '='))
          f.close()
          return
  