#!/usr/bin/env python

# python3 status: compatible

# system libraries
import sys, os, glob

# AFNI libraries
from afnipy import option_list as OL
from afnipy import afni_util as UTIL
from afnipy import lib_afni1D as LD

# ----------------------------------------------------------------------
# globals

g_help_string = """
=============================================================================
read_matlab_files.py    - describe or convert MATLAB files (to 1D)

   Describe the contents of matlab files, and possibly convert them to 1D.

   Using only -infiles, all file objects (names not starting with '__') will
   be reported.  With the addition of -prefix, all numpy matrices will be
   converted to 1D format.

------------------------------------------
examples:

   1. Describe the contents of all matlab files.

      read_matlab_files.py -infiles *.mat

   1. Convert all matlab files in the current directory to test.*.1D

      read_matlab_files.py -infiles *.mat -prefix test

------------------------------------------
terminal options:

   -help                : show this help
   -hist                : show the revision history
   -ver                 : show the version number

------------------------------------------
process options:

   -infiles             : specify input files
   -overwrite           : overwrite any output file
   -prefix PREFIX       : prefix for output file names

        Using -prefix, output files will have the naming format:

           PREFIX.INDEX.KEY.1D

              PREFIX    : as specified with -prefix
              INDEX     : 1-based index of objects found in file
              KEY       : key (label) corresponding to the given object

------------------------------------------
R Reynolds    January 2015
=============================================================================
"""

g_todo = """
   todo list:
"""

g_history = """
   read_matlab_files.py history:

   0.0  Jan 14, 2015 - initial version
   0.1  May 11, 2020 - python3 compatible
"""

g_version = "read_matlab_files.py version 0.1, May 11, 2020"


class MyInterface:
   """interface class for MyLibrary (whatever that is)
   """
   def __init__(self, verb=1):
      # main variables
      self.valid_opts      = None
      self.user_opts       = None

      # control
      self.verb            = 1

      # process vars
      self.infiles         = []
      self.prefix          = ''
      self.overwrite       = 0

      # initialize valid_opts
      self.valid_opts = self.get_valid_opts()

   def get_valid_opts(self):
      vopts = OL.OptionList('valid opts')

      # short, terminal arguments
      vopts.add_opt('-help', 0, [], helpstr='display program help')
      vopts.add_opt('-hist', 0, [], helpstr='display the modification history')
      vopts.add_opt('-ver', 0, [], helpstr='display the current version number')

      # general options
      vopts.add_opt('-infiles', -1, [],
                    helpstr='specify input files')
      vopts.add_opt('-overwrite', 0, [],
                    helpstr='flag to overwrite any existing output files')
      vopts.add_opt('-prefix', 1, [],
                    helpstr='specify prefix for output files')
      vopts.add_opt('-verb', 1, [], helpstr='set the verbose level (def=1)')

      vopts.sort()

      return vopts

   def process_options(self):
      """return  1 on valid and exit
         return  0 on valid and continue
         return -1 on invalid
      """

      argv = sys.argv

      # process any optlist_ options
      self.valid_opts.check_special_opts(argv)

      # process terminal options without the option_list interface
      # (so that errors are not reported)

      # if no arguments are given, do default processing
      if '-help' in argv or len(argv) < 2:
         print(g_help_string)
         return 1

      if '-hist' in argv:
         print(g_history)
         return 1

      if '-show_valid_opts' in argv:
         self.valid_opts.show('', 1)
         return 1

      if '-ver' in argv:
         print(g_version)
         return 1

      # ============================================================
      # read options specified by the user
      self.user_opts = OL.read_options(argv, self.valid_opts)
      uopts = self.user_opts            # convenience variable
      if not uopts: return -1           # error condition

      # ------------------------------------------------------------
      # process verb first

      val, err = uopts.get_type_opt(int, '-verb')
      if val != None and not err: self.verb = val

      # ------------------------------------------------------------
      # process options sequentially, to make them like a script
      errs = 0
      for opt in self.user_opts.olist:
         # check for anything to skip
         if opt.name == '-verb': pass

         elif opt.name == '-infiles':
            self.infiles, err = uopts.get_string_list('', opt=opt)
            if self.infiles == None or err:
               print('** failed to read -infiles list')
               errs +=1

         elif opt.name == '-overwrite':
            self.overwrite = 1

         elif opt.name == '-prefix':
            val, err = uopts.get_string_opt(opt=opt)
            if val != None and not err: self.prefix = val

      # allow early and late error returns
      if errs: return -1

      # ------------------------------------------------------------
      # apply any trailing logic

      # if here, require input files
      if len(self.infiles) < 1:
         print('** missing -infiles option')
         errs += 1

      # if no -prefix and no -verb, default verb to 2
      if not self.user_opts.find_opt('-verb') and self.prefix == '':
         self.verb = 2

      if errs: return -1

      return 0

   def process_matlab_file(self, fname, index=0):
      """process matlab files
      """

      try:
         import scipy.io
         import numpy
      except:
         print('** missing library: scipy.io')
         print('   (please install scipy)')
         return 1

      if not os.path.isfile(fname):
         print("** missing file '%s'" % fname)
         return 1

      mfile = scipy.io.loadmat(fname)
      if mfile == None: return 1

      # prepare output prefix
      prefix = self.prefix
      if prefix != '' and len(self.infiles) > 1:
         prefix = '%s.%02d' % (self.prefix, index+1)

      klist = [key for key in list(mfile.keys()) if key[0:2] != '__']
      maxlen = max([len(key) for key in klist])

      if self.verb:
         if self.verb > 1: print()
         print('-- file %s has %d key(s)' % (fname, len(klist)))

      for key in klist:
         obj = mfile[key]
         if self.verb > 1:
            if type(obj) is numpy.ndarray:
               shstr = ' shape %s' % str(obj.shape)
            else:
               shstr = ''
            print('   %-*s %s%s' % (maxlen, key, type(obj), shstr))

         # maybe write any numpy data
         if prefix != '' and type(obj) is numpy.ndarray:
            # convert object to Afni1D and transpose
            olist = obj.tolist()
            adata = LD.Afni1D(from_mat=1, matrix=olist, verb=self.verb)
            adata.transpose()

            # if model, break apart, else just write
            if key == 'model' and adata.nvec >= 2:
               self.write_model_files(adata, prefix)
            else:
               ofile = '%s.%s.1D'%(prefix,key)
               print('++ writing ndarry to %s' % ofile)
               adata.write(ofile, overwrite=self.overwrite)

      return 0

   def write_model_files(self, adata, prefix):
      """break model matrix into many 1D files
      """

      if adata.nvec < 1: return 0

      for ind in range(adata.nvec):
         avec = LD.Afni1D(from_mat=1, matrix=[adata.mat[ind]], verb=self.verb)
         ofile = '%s.model.%02d.1D' % (prefix, ind+1)
         print('++ writing model file %s' % ofile)
         avec.write(ofile, overwrite=self.overwrite)

      return 0

   def process_files(self):
      """process matlab files
      """

      print('-- have %d files to process' % len(self.infiles))

      # check file existence first
      for ind, ifile in enumerate(self.infiles):
         if self.process_matlab_file(ifile, ind): return 1

      return 0
         
def main():
   me = MyInterface()
   if not me: return 1

   rv = me.process_options()
   if rv > 0: return 0  # exit with success
   if rv < 0:           # exit with error status
      print('** failed to process options...')
      return 1

   if me.process_files(): return 1

   return 0

if __name__ == '__main__':
   sys.exit(main())


