#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import re

import argparse
import concurrent.futures as cf
import functools
import os
import subprocess
import urllib.request


DEFAULT_PARALLEL_DOWNLOADS = 8


class Downloader:

    def get_file_list(self, prefix, filter=None):
        def traverse(directory, files, directories):
            url = f'{self.URL_ROOT}/{directory}'
            response = urllib.request.urlopen(url).read().decode()
            paths = re.findall('<a href="(.+?)"', response)
            for path in paths:
                path = re.sub(f'^{re.escape(url)}',
                              '',
                              path)
                if path == '../':
                    continue
                resolved_path = f'{directory}{path}'
                if filter and not filter(path):
                    continue
                if path.endswith('/'):
                    directories.append(resolved_path)
                else:
                    files.append(resolved_path)
        files = []
        if prefix != '' and not prefix.endswith('/'):
            prefix += '/'
        directories = [prefix]
        while len(directories) > 0:
            directory = directories.pop()
            traverse(directory, files, directories)
        return files

    def download_files(self, files, dest=None, num_parallel=None,
                       re_match=None):
        """
        Download files from Bintray in parallel. If file already exists, will
        overwrite if the checksum does not match what Bintray says it should be

        Parameters
        ----------
        files : List[Dict]
            File listing from Bintray
        dest : str, default None
            Defaults to current working directory
        num_parallel : int, default 8
            Number of files to download in parallel. If set to None, uses
            default
        """
        if dest is None:
            dest = os.getcwd()
        if num_parallel is None:
            num_parallel = DEFAULT_PARALLEL_DOWNLOADS

        if re_match is not None:
            regex = re.compile(re_match)
            files = [x for x in files if regex.match(x)]

        if num_parallel == 1:
            for path in files:
                self._download_file(dest, path)