#!/usr/bin/env python3

import sys
sys.dont_write_bytecode = True
sys.path.append('/usr/lib/dcpython')

"""
lsasm - List files in Oracle ASM diskgroups
Copyright (c) 2023 - Bart Sjerps <bart@dirty-cache.com>
License: GPLv3+
"""

import os, re, argparse
try:
    from asm import asm
    from switchuser import switchuser
except ImportError as e:
    print("Import failed:", e)
    sys.exit(20)

asm_query = """\
SET heading {heading} verify off feedback off pages 50000 lines 1000
SET COLSEP '{colsep}'
ALTER SESSION SET nls_date_format='YYYY-MM-DD HH24:MI:SS';

COLUMN DG_NAME    FORMAT A12           HEAD 'Diskgroup'
COLUMN AD         FORMAT A6            HEAD 'IsDir' 
COLUMN SYSCR      FORMAT A6            HEAD 'System'
COLUMN file_type  FORMAT a15           HEAD 'Filetype'
COLUMN mdate      FORMAT A19           HEAD 'Modified'
COLUMN filename   FORMAT A100          HEAD 'Filename'
COLUMN syscreated FORMAT A20           HEAD 'System'
COLUMN SIZE_MB    FORMAT 99,999,999.00 HEAD 'Size (MiB)'
COLUMN BYTES      FORMAT 99999999999   HEAD 'Bytes' 
COLUMN B          FORMAT A13
COLUMN MB         FORMAT A8

SELECT {columns} FROM (
  SELECT ad
  , nvl(file_type,'-') file_type
  , syscr 
  , gname dg_name 
  , bytes 
  , bytes/1048576 size_mb 
  , mdate 
  , concat('+'||gname, sys_connect_by_path(aname, '/')) filename
  FROM (SELECT b.name             gname   
              , a.parent_index    pindex  
              , a.name            aname   
              , a.reference_index rindex
              , a.system_created  syscr
              , a.alias_directory ad
              , c.type            file_type
              , c.bytes           bytes   
              , c.modification_date mdate
        FROM v$asm_alias a, v$asm_diskgroup b, v$asm_file c
        WHERE a.group_number   = b.group_number
        AND a.group_number     = c.group_number(+)
        AND a.file_number      = c.file_number(+)
        AND a.file_incarnation = c.incarnation(+)
       )       
  WHERE 1=1
  {filters}
  START WITH (MOD(pindex, POWER(2, 24))) = 0
  AND rindex IN (
    SELECT reference_index FROM v$asm_alias a
    JOIN v$asm_diskgroup d USING (group_number)
    -- WHERE d.name = 'DATA'
    -- WHERE a.name LIKE 'DEMO06%'
    -- AND filename LIKE '%DEM%' 
  )
  CONNECT BY PRIOR rindex = pindex
)
{file}
ORDER BY filename
/
"""

def lsasm(args):
    if args.nohead:
        heading="OFF"
    else:
        heading="ON"
    file = '--'
    filters = ['--']
    columns = []
    if args.files:
        filters.append('AND bytes IS NOT NULL')
    if args.dirs:
        filters.append('AND bytes IS NULL')
    f = '\n'.join(filters)

    columns.append("ad")
    if args.type:
        columns.append("file_type")

    if args.long:
        columns.append("syscr")

    if not args.dirs:
        if args.mib:
            columns.append("size_mb")
        else:
            columns.append("bytes")
        columns.append('to_char(mdate) mdate')

    columns.append("filename")
    c = '\n, '.join(columns)

    if args.file:
        file=f"WHERE FILENAME LIKE '{args.file}'"

    query = asm_query.format(filters=f, columns=c, colsep=args.colsep, file=file, heading=heading)
    if args.dryrun:
        print(query)
        return
    asm.run(query)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="List files in Oracle ASM diskgroups")
    group = parser.add_mutually_exclusive_group()

    group.add_argument('-f', '--files', action="store_true", help='Files only')
    group.add_argument('-d', '--dirs', action="store_true", help='Directories only')
    parser.add_argument(     '--dryrun', action="store_true", help="Only show SQL script")
    parser.add_argument('-s', '--colsep', help="Separator (default tab)", default="\t")
    parser.add_argument('-n', '--nohead', action="store_true", help="No heading")
    parser.add_argument('-l', '--long', action="store_true", help="Long output")
    parser.add_argument('-m', '--mib', action="store_true", help="Filesize in MiB instead of bytes")
    parser.add_argument('-t', '--type', action="store_true", help="Show filetypes")
    parser.add_argument('file', nargs='?', help="Filter files (use %% as wildcard)")

    args = parser.parse_args()
    try:
        switchuser('oracle')
        lsasm(args)
    except ValueError as e:
        print(e)
        sys.exit(10)