#! 

# LDASTools frameCPP - A library implementing the LIGO/Virgo frame specification
#
# Copyright (C) 2018 California Institute of Technology
#
# LDASTools frameCPP is free software; you may redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 (GPLv2) of the
# License or at your discretion, any later version.
#
# LDASTools frameCPP is distributed in the hope that it will be useful, but
# without any warranty or even the implied warranty of merchantability
# or fitness for a particular purpose. See the GNU General Public
# License (GPLv2) for more details.
#
# Neither the names of the California Institute of Technology (Caltech),
# The Massachusetts Institute of Technology (M.I.T), The Laser
# Interferometer Gravitational-Wave Observatory (LIGO), nor the names
# of its contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# You should have received a copy of the licensing terms for this
# software included in the file LICENSE located in the top-level
# directory of this package. If you did not, you can view a copy at
# http://dcc.ligo.org/M1500244/LICENSE

##
#

#------------------------------------------------------------------------
#------------------------------------------------------------------------
from __future__ import print_function

import ctypes
import numpy
from optparse import OptionParser
from LDAStools import frameCPP

COMPRESSION_STRING = {
    frameCPP.FrVect.BIGENDIAN_RAW : 'RAW (bigendian)',
    frameCPP.FrVect.LITTLEENDIAN_RAW : 'RAW (littleendian)',
    frameCPP.FrVect.BIGENDIAN_GZIP : 'GZIP (bigendian)',
    frameCPP.FrVect.LITTLEENDIAN_GZIP : 'GZIP (littleendian)',
    frameCPP.FrVect.BIGENDIAN_DIFF_GZIP : 'DIFF_GZIP (bigendian)',
    frameCPP.FrVect.LITTLEENDIAN_DIFF_GZIP : 'DIFF_GZIP (littleendian)',
    frameCPP.FrVect.BIGENDIAN_ZERO_SUPPRESS_WORD_2 : 'ZERO_SUPPRESS_WORD_2 (bigendian)',
    frameCPP.FrVect.LITTLEENDIAN_ZERO_SUPPRESS_WORD_2 : 'ZERO_SUPPRESS_WORD_2 (littleendian)',
    frameCPP.FrVect.BIGENDIAN_ZERO_SUPPRESS_WORD_4 : 'ZERO_SUPPRESS_WORD_4 (bigendian)',
    frameCPP.FrVect.LITTLEENDIAN_ZERO_SUPPRESS_WORD_4 : 'ZERO_SUPPRESS_WORD_4 (littleendian)',
    frameCPP.FrVect.BIGENDIAN_ZERO_SUPPRESS_WORD_8 : 'ZERO_SUPPRESS_WORD_8 (bigendian)',
    frameCPP.FrVect.LITTLEENDIAN_ZERO_SUPPRESS_WORD_8 : 'ZERO_SUPPRESS_WORD_8 (littleendian)'
    }

DATA_TYPE_STRING = {
    frameCPP.FrVect.FR_VECT_C : 'FR_VECT_C',
    frameCPP.FrVect.FR_VECT_1U : 'FR_VECT_1U',
    frameCPP.FrVect.FR_VECT_2S : 'FR_VECT_2S',
    frameCPP.FrVect.FR_VECT_2U : 'FR_VECT_2U',
    frameCPP.FrVect.FR_VECT_4S : 'FR_VECT_4S',
    frameCPP.FrVect.FR_VECT_4U : 'FR_VECT_4U',
    frameCPP.FrVect.FR_VECT_8S : 'FR_VECT_8S',
    frameCPP.FrVect.FR_VECT_8U : 'FR_VECT_8U',
    frameCPP.FrVect.FR_VECT_4R : 'FR_VECT_4R',
    frameCPP.FrVect.FR_VECT_8R : 'FR_VECT_8R',
    frameCPP.FrVect.FR_VECT_8C : 'FR_VECT_8C',
    frameCPP.FrVect.FR_VECT_16C : 'FR_VECT_16C'
    }

def DumpChannels( Stream, TOC, FrameOffset ):
    DumpChannelsFrAdcData( Stream, TOC, FrameOffset )
    DumpChannelsFrProcData( Stream, TOC, FrameOffset )

def DumpChannelsFrAdcData( Stream, TOC, FrameOffset ):
    #--------------------------------------------------------------------
    # ADC channels
    #--------------------------------------------------------------------
    toc_adc = TOC.GetADC( );
    for k, v in toc_adc.items( ):
        print( "FrAdcData: %s channelID: %d groupID: %d"
               % (
                   k, v[0], v[1]
               ) )
        adc = Stream.ReadFrAdcData( FrameOffset, k );
        print( ( "\tname: %s\n"
                 + "\tcomment: %s\n"
                 + "\tchannelGroup: %d\n"
                 + "\tchannelNumber: %d\n"
                 + "\tnBits: %d\n"
                 + "\tbias: %g\n"
                 + "\tslope: %g\n"
                 + "\tunits: %s\n"
                 + "\tsampleRate: %g\n"
                 + "\ttimeOffset: %g\n"
                 + "\tfShift: %g\n"
                 + "\tphase: %g\n"
                 + "\tdataValid: %d" )
               % (
                   adc.name,
                   adc.comment,
                   adc.channelGroup,
                   adc.channelNumber,
                   adc.nBits,
                   adc.bias,
                   adc.slope,
                   adc.units,
                   adc.sampleRate,
                   adc.timeOffset,
                   adc.fShift,
                   adc.phase,
                   adc.dataValid
               ) )
        #------------------------------------------------------------
        # Dump the vector information.
        #------------------------------------------------------------
        print( "\tdata:" )
        for data in adc.RefData( ):
            DumpFrVect( data )

def DumpChannelsFrProcData( Stream, TOC, FrameOffset ):
    #--------------------------------------------------------------------
    # FrProcData channels
    #--------------------------------------------------------------------
    toc_proc = TOC.GetProc( );
    for cur_proc in toc_proc:
        print( "FrProcData: %s" % ( cur_proc ) )
        proc = Stream.ReadFrProcData( FrameOffset, cur_proc )
        print( ( "\tname: %s\n"
                 + "\tcomment: %s\n"
                 + "\ttype: %d\n"
                 + "\tsubType: %d\n"
                 + "\ttimeOffset: %g\n"
                 + "\ttRange: %g\n"
                 + "\tfShift: %g\n"
                 + "\tphase: %g\n"
                 + "\tfRange: %g\n"
                 + "\tBW: %g" )
               % (
                   proc.name,
                   proc.comment,
                   proc.type,
                   proc.subType,
                   proc.timeOffset,
                   proc.tRange,
                   proc.fShift,
                   proc.phase,
                   proc.fRange,
                   proc.BW
               ) )
        #----------------------------------------------------------------
        # Dump the vector information.
        #----------------------------------------------------------------
        print( "\tdata:" )
        for vect in proc.data:
            DumpFrVect( vect )
        #----------------------------------------------------------------
        # Dump the aux information.
        #----------------------------------------------------------------
        print( "\taux:" )
        for aux in proc.aux:
            DumpFrVect( aux )
        #----------------------------------------------------------------
        # Dump the table information.
        #----------------------------------------------------------------
        print( "\ttable:" )
        for table in proc.table:
            DumpFrTable( table )
        #----------------------------------------------------------------
        # Dump the history information.
        #----------------------------------------------------------------
        print( "\thistory:" )
        for history in proc.history:
            DumpFrHistory( history )

def DumpFrHistory( History ):
    print( ( "\t\tname: %s\n"
             + "\t\tcomment: %s" )
           % (
               History.name,
               History.comment ) )

def DumpFrTable( Table ):
    print( ( "\t\tname: %s\n"
             + "\t\tcomment: %s" )
           % (
               Table.name,
               Table.comment ) )
    for col in Table.column:
        DumpFrVect( col )

def DumpFrVect( Vector ):
    dim_str = ""
    #for i in range( 0, Vector.GetNDim( ) ):
    #    dim = Vector.GetDim( i )
    #    dim_str += ( ( "\t\t\tnx: %d"
    #                 + " dx: %g"
    #                 + " startX: %g"
    #                 + " unitX: %s\n" )
    #                 % (
    #        dim.nx,
    #        dim.dx,
    #        dim.startX,
    #        dim.unitX )
    print( ( "\t\tname: %s\n"
             + "\t\tcompress: %s\n"
             + "\t\ttype: %s\n"
             + "\t\tnData: %d\n"
             + "\t\tnBytes: %d\n"
             + "\t\tnDim: %d\n"
             + "%s\t\tunitY: %s" )
           % (
               Vector.name,
               COMPRESSION_STRING[ Vector.compress ],
               DATA_TYPE_STRING[ Vector.type ],
               Vector.nData,
               Vector.nBytes,
               Vector.nDim,
               dim_str,
               Vector.unitY
           ) )
    #--------------------------------------------------------------------
    # Interface to the data using ctype
    #--------------------------------------------------------------------
    DumpFrVectData( Vector.GetDataUncompressed( ),
                    ndata = Vector.GetNData( ),
                    data_type = Vector.GetType( ),
                    prefix = "\t\tData(ctype): ",
                    end=10 )
    #--------------------------------------------------------------------
    # Interface to the data using numpy
    #--------------------------------------------------------------------
    DumpFrVectData( Vector.GetDataArray( ),
                    prefix = "\t\tData(numpy): ",
                    end=10 )

def DumpFrVectData( data, ndata = 0, data_type = None, prefix="", end=10 ):
    elipse = ''
    print( "%s" % ( prefix ), end='' )
    if ( isinstance( data, numpy.ndarray ) ):
        if ( ( end > -1 ) and ( len( data) > end ) ):
            elipse = '...'
        for d in ( data[:end] ):
            print( d, end='' )
            print( ", ", end='' )
    else:
        if ( ( end > -1 ) and ( ndata > end ) ):
            elipse = '...'
        step = 1;
        if data_type == frameCPP.FrVect.FR_VECT_C:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_byte ) )
            format = "%d"
        elif data_type == frameCPP.FrVect.FR_VECT_1U:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_ubyte ) )
            format = "%d"
        elif data_type == frameCPP.FrVect.FR_VECT_2S:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_short ) )
            format = "%d"
        elif data_type == frameCPP.FrVect.FR_VECT_2U:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_ushort ) )
            format = "%d"
        elif data_type == frameCPP.FrVect.FR_VECT_4S:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_int ) )
            format = "%d"
        elif data_type == frameCPP.FrVect.FR_VECT_4U:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_uint ) )
            format = "%d"
        elif data_type == frameCPP.FrVect.FR_VECT_8S:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_longlong ) )
            format = "%ld"
        elif data_type == frameCPP.FrVect.FR_VECT_8U:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_ulonglong ) )
            format = "%ld"
        elif data_type == frameCPP.FrVect.FR_VECT_4R:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_float ) )
            format = "%g"
        elif data_type == frameCPP.FrVect.FR_VECT_8R:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_double ) )
            format = "%g"
        elif data_type == frameCPP.FrVect.FR_VECT_8C:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_float ) )
            format = "(%g, %g)"
            step = 2
        elif data_type == frameCPP.FrVect.FR_VECT_16C:
            datap = ctypes.cast( data.__long__( ), ctypes.POINTER( ctypes.c_double ) )
            format = "(%g, %g)"
            step = 2
        else:
            print( " WARNING: Currently don't support printing of %s"
                   % ( DATA_TYPE_STRING[ data_type ] ) )
            return
        if ( step == 2 ):
            # Printing of complex numbers
            for i in range(0, end, step ):
                print( ( " " + format ) % ( datap[i], datap[i+1] ) )
        else:
            # Printing of non-complex numbers
            for i in range(0, end, step ):
                print( ( " " + format ) % ( datap[i] ), end='' )
    print( '%s' % ( elipse ) )

def ProcessFile( Filename ):
  print( "Filename: %s" % Filename )
  fs = frameCPP.IFrameFStream( Filename )
  print( "There are %d frame(s)." % fs.GetNumberOfFrames( ) )
  toc = fs.GetTOC( );
  #----------------------------------------------------------------------
  # GTimeS
  #----------------------------------------------------------------------
  print( "GTimeS: ", end='' )
  for s in toc.GTimeS:
      print( " %d" % ( s ), end='' )
  print( "" )
  #----------------------------------------------------------------------
  # GTimeN
  #----------------------------------------------------------------------
  print( "GTimeN: ", end='' )
  for s in toc.GTimeN:
      print( " %09d" % ( s ), end='' )
  print( "" )
  #----------------------------------------------------------------------
  # Detector information
  #----------------------------------------------------------------------
  dn = toc.GetNameDetector( );
  print( "There are %d detectors" % len( dn ) )
  if len( dn ) > 0:
    for name in dn:
      detector = fs.ReadDetector( name )
      print( ( "Detector Info: %s\n"
            + "\tprefix: %2.2s\n"
           + "\tlatitude: %g longitude: %g elevation: %g\n"
            + "\tazimuth: x-arm: %g y-arm: %g\n"
            + "\taltitude: x-arm: %g y-arm: %g\n"
            + "\tmidpoint: x-arm: %g y-arm: %g\n"
            + "\tlocal time: %d" )
            % (
              name,
              detector.GetPrefix( ),
              detector.GetLatitude( ),
              detector.GetLongitude( ),
              detector.GetElevation( ),
              detector.GetArmXazimuth( ), detector.GetArmYazimuth( ),
              detector.GetArmXaltitude( ), detector.GetArmYaltitude( ),
              detector.GetArmXmidpoint( ), detector.GetArmYmidpoint( ),
              detector.GetLocalTime( )
            ) )
      # for - end
    # if - end
  #----------------------------------------------------------------------
  # Dump the Channels
  #----------------------------------------------------------------------
  DumpChannels( fs, toc, 0 )


#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
def dump_objects_main():
    parser = OptionParser( )

    (options, args) = parser.parse_args( )
    for filename in args:
        ProcessFile( filename )

#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
if __name__ == "__main__":
    dump_objects_main( )
