#!/usr/bin/env python3
# -*- coding: utf-8 -*-
###############################################################################
#
#  Project:  GDAL samples
#  Purpose:  Display the list of files in a virtual directory, like /vsicurl or /vsizip
#  Author:   Even Rouault <even dot rouault at spatialys.com>
#
###############################################################################
#  Copyright (c) 2011-2014, Even Rouault <even dot rouault at spatialys.com>
#
# SPDX-License-Identifier: MIT
###############################################################################

import os
import stat
import sys

from osgeo import gdal


def needsVSICurl(filename):
    return (
        filename.startswith("http://")
        or filename.startswith("https://")
        or filename.startswith("ftp://")
    )


def iszip(filename):
    return filename.endswith(".zip") or filename.endswith(".ZIP")


def istgz(filename):
    return (
        filename.endswith(".tgz")
        or filename.endswith(".TGZ")
        or filename.endswith(".tar.gz")
        or filename.endswith(".TAR.GZ")
    )


def display_file(fout, dirname, prefix, filename, longformat, check_open=False):

    statBuf = None
    filename_displayed = prefix + filename

    if dirname.endswith("/"):
        dirname_with_slash = dirname
    else:
        dirname_with_slash = dirname + "/"

    version_num = int(gdal.VersionInfo("VERSION_NUM"))
    if longformat:
        if version_num >= 1900:
            statBuf = gdal.VSIStatL(
                dirname_with_slash + filename,
                gdal.VSI_STAT_EXISTS_FLAG
                | gdal.VSI_STAT_NATURE_FLAG
                | gdal.VSI_STAT_SIZE_FLAG,
            )
    else:
        if version_num >= 1900:
            statBuf = gdal.VSIStatL(
                dirname_with_slash + filename,
                gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG,
            )

    if statBuf is None and check_open:
        if version_num >= 1900:
            f = None
        else:
            f = gdal.VSIFOpenL(dirname_with_slash + filename, "rb")
        if f is None:
            sys.stderr.write("Cannot open %s\n" % (dirname_with_slash + filename))
            return
        gdal.VSIFCloseL(f)

    if (
        statBuf is not None
        and statBuf.IsDirectory()
        and not filename_displayed.endswith("/")
    ):
        filename_displayed = filename_displayed + "/"

    if longformat and statBuf is not None:
        import time

        bdt = time.gmtime(statBuf.mtime)
        if stat.S_IMODE(statBuf.mode) != 0:
            permissions = stat.filemode(statBuf.mode)
        elif statBuf.IsDirectory():
            permissions = "dr-xr-xr-x"
        else:
            permissions = "-r--r--r--"
        line = "%s  1 unknown unknown %12d %04d-%02d-%02d %02d:%02d %s\n" % (
            permissions,
            statBuf.size,
            bdt.tm_year,
            bdt.tm_mon,
            bdt.tm_mday,
            bdt.tm_hour,
            bdt.tm_min,
            filename_displayed,
        )
    else:
        line = filename_displayed + "\n"

    fout.write(line)


def readDir(
    fout,
    dirname,
    prefix,
    longformat,
    recurse,
    depth,
    recurseInZip,
    recurseInTGZ,
    first=False,
):

    if depth <= 0:
        return

    if needsVSICurl(dirname):
        dirname = "/vsicurl/" + dirname
        prefix = "/vsicurl/" + prefix

    if recurseInZip and iszip(dirname) and not dirname.startswith("/vsizip"):
        dirname = "/vsizip/" + dirname
        prefix = "/vsizip/" + prefix

    if recurseInTGZ and istgz(dirname) and not dirname.startswith("/vsitar"):
        dirname = "/vsitar/" + dirname
        prefix = "/vsitar/" + prefix

    lst = gdal.ReadDir(dirname)
    if lst is None:
        if first:
            original_dirname = dirname
            (dirname, filename) = os.path.split(dirname)
            if gdal.ReadDir(dirname) is None:
                sys.stderr.write("Cannot open %s\n" % original_dirname)
                return
            if dirname == "":
                dirname = "."
                prefix = ""
            else:
                prefix = dirname + "/"
            display_file(fout, dirname, prefix, filename, longformat, True)
    else:
        for filename in lst:
            if filename == "." or filename == "..":
                continue

            display_file(fout, dirname, prefix, filename, longformat)

            if recurse:
                new_prefix = prefix + filename
                if not new_prefix.endswith("/"):
                    new_prefix += "/"
                readDir(
                    fout,
                    dirname + "/" + filename,
                    new_prefix,
                    longformat,
                    recurse,
                    depth - 1,
                    recurseInZip,
                    recurseInTGZ,
                )


def Usage():
    print(
        "Usage: gdal_ls [-l] [-r] [-depth d] [-Rzip] [-Rtgz] name_of_virtual_directory"
    )
    print("")
    print("Display the list of files in a virtual directory, like /vsicurl or /vsizip")
    print("")
    print("Options :")
    print(" -l : use a long listing format (same as ls -l)")
    print(" -r : list subdirectories recursively")
    print(" -depth d : recurse until depth d")
    print(" -Rzip : list content of .zip archives")
    print(
        " -Rtgz : list content of .tar.gz/.tgz archives (potentially slow on /vsicurl/)"
    )
    return 2


def gdal_ls(argv, fout=sys.stdout):
    longformat = False
    recurse = False
    recurseInZip = False
    recurseInTGZ = False
    display_prefix = True
    dirname = None
    depth = 1024

    argv = gdal.GeneralCmdLineProcessor(argv)
    if argv is None:
        return 0

    i = 1
    argc = len(argv)
    while i < argc:
        if argv[i] == "-l":
            longformat = True
        elif argv[i] == "-lr":
            longformat = True
            recurse = True
        elif argv[i] == "-R" or argv[i] == "-r":
            recurse = True
        elif argv[i] == "-Rzip":
            recurseInZip = True
        elif argv[i] == "-Rtgz":
            recurseInTGZ = True
        elif argv[i] == "-noprefix":
            display_prefix = False
        elif argv[i] == "-depth" and i < len(argv) - 1:
            depth = int(argv[i + 1])
            i = i + 1
        elif argv[i][0] == "-":
            sys.stderr.write("Unrecognized option : %s\n" % argv[i])
            return Usage()
        elif dirname is None:
            dirname = argv[i]
        else:
            sys.stderr.write("Unexpected option : %s\n" % argv[i])
            return Usage()

        i = i + 1

    if dirname is None:
        return Usage()

    # Remove trailing
    if dirname[-1] == "/":
        dirname = dirname[0 : len(dirname) - 1]

    if needsVSICurl(dirname):
        dirname = "/vsicurl/" + dirname

    # if iszip(dirname) and not dirname.startswith('/vsizip'):
    #    dirname = '/vsizip/' + dirname

    # if istgz(dirname) and not dirname.startswith('/vsitar'):
    #    dirname = '/vsitar/' + dirname

    prefix = ""
    if display_prefix:
        prefix = dirname + "/"
    readDir(
        fout,
        dirname,
        prefix,
        longformat,
        recurse,
        depth,
        recurseInZip,
        recurseInTGZ,
        True,
    )
    return 0


def main(argv=sys.argv):
    return gdal_ls(argv)


if __name__ == "__main__":
    # hack to force load the Zarr driver and /vsikerchunk if it is built as a driver
    with gdal.quiet_errors():
        gdal.Open("ZARR:")

    sys.exit(main(sys.argv))
