#!/usr/bin/python3

import sys, os, json, re, subprocess

CONFIG_DIR = "/etc/BackupPC/pc"
PC_DIR = "/var/lib/BackupPC/pc"
BIN_DIR = "/usr/share/BackupPC/bin"
bpc_ls = os.path.join(BIN_DIR, "BackupPC_ls")
bpc_zcat = os.path.join(BIN_DIR, "BackupPC_zcat")
re_spaces = re.compile(b" +")
MB = 1048576
PROGRESS_COUNT = 1024


def perl2json(filename):
    p2j = [
        'perl', '-MJSON', '-e',
        '''my %Conf;\n'''
        + open(filename).read() + ';\n'
        '''print to_json(\\%Conf, {pretty => 1});'''
    ]
    json_data = subprocess.run(p2j, stdout=subprocess.PIPE)
    return json.loads(json_data.stdout)


class backup:
    def __init__(self, host, backup_nr, share="/", bpc_file_count=1):
        self.protocol = 0
        self.cmd = [bpc_ls, "-R", "-i", "-h", host,
                    "-n", backup_nr, "-s", share, "/"]
        self.f = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
        print(" ".join(self.cmd))
        self.bpc_file_count = bpc_file_count
        self.read(self.f.stdout)

    def read(self, fd):
        self.total_size = 0
        self.total_count = 0
        self.progress = 0
        minus = ord("-")
        slash = ord("/")
        colon = ord(":")
        while True:
            row = fd.readline()
            if not row:
                break
            if len(row) < 2 or (row[0] == slash and row[-2] == colon):
                continue
            self.total_count += 1
            cols = re_spaces.split(row.strip())
            # print(cols)
            if len(cols) > 6 and cols[1][0] == minus:
                try:
                    inode, links = cols[0].split(b"/", 1)
                    size, f_date, f_time, filename = cols[3:7]
                    #print(int(size), filename)
                    self.total_size += int(size)/int(links)
                except ValueError as err:
                    print(err)
                    print(row)
                    print(self.cmd)
                    raise
            # else:
            #  print(row.decode("utf8").strip())
            # progress
            if self.total_count > self.progress+PROGRESS_COUNT:
                sys.stderr.write(" %s, ~%4.2f%%\r" % (
                    self.total_count,
                    self.total_count/self.bpc_file_count*100  # %
                ))
                self.progress = self.total_count


if sys.argv[1:]:
    print(
        "Size: %5.3f MB" % (
            backup(
                sys.argv[1],
                sys.argv[2],
                sys.argv[3]
            ).total_size/1048576
        )
    )
else:
    for host in os.listdir(PC_DIR):
        host_dir = os.path.join(PC_DIR, host)
        host_size = 0
        host_count = 0
        for backup_row in open(os.path.join(host_dir, "backups")):
            backup_nr, backup_type, d1, d2, exist_file_count, exist_size, \
                new_file_count, new_size, other = \
                backup_row.split("\t", 8)
            config = perl2json("%s/%s.pl" % (CONFIG_DIR, host))
            for share in config.get("RsyncShareName", "/"):
                sys.stderr.write(
                    "Running on %s/%s:%s ...\n"
                    % (host, backup_nr, share)
                )
                backup2 = backup(
                    host, backup_nr, share,
                    int(exist_file_count)+int(new_file_count)
                )
                host_size += backup2.total_size
                host_count += backup2.total_count
                print(
                    "%s/%s:%s: %5.3f MB / %d files" % (
                        host,
                        backup_nr,
                        share,
                        backup2.total_size/MB,
                        backup2.total_count
                    )
                )
        print(
            "HOST: %s: %8.6f GB / %d files"
            % (host, host_size/MB/1024, host_count)
        )
        sys.stdout.flush()
