#! /usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright © 2016, IOhannes m zmölnig, IEM

# This file is part of virtshaus
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with iaem-downloader. If not, see <http://www.gnu.org/licenses/>.

import os

VERSION = "2.0"


def post(s):
    print(s)


def parseCmdlineArgs():
    import argparse

    parser = argparse.ArgumentParser()
    DEFAULT_CONFIGDIR = "/etc/virtshaus/iemsync.d/hosts.cfg"

    parser.add_argument(
        "config",
        nargs="*",
        help="configfiles or directories with configfiles" "(ending in .conf)",
    )

    parser.add_argument(
        "-s", "--source", help="source directory (overrides single configfile"
    )
    parser.add_argument(
        "-t", "--target", help="target directory (overrides single configfile"
    )
    parser.add_argument(
        "-f", "--filter", action="append", default=[], help="additional filter file"
    )

    parser.add_argument(
        "-C",
        "--cron",
        action="store_true",
        help="cron-mode (only print, if an error occured)",
    )
    parser.add_argument(
        "-v",
        "--verbose",
        action="count",
        default=0,
        help="raise verbosity (can be given multiple times",
    )
    parser.add_argument(
        "-q",
        "--quiet",
        action="count",
        default=0,
        help="lower verbosity (can be given multiple times",
    )
    parser.add_argument(
        "-d",
        "--debug",
        action="store_true",
        help="debug mode (print command before running them)",
    )
    parser.add_argument(
        "-n",
        "--dry-run",
        action="store_true",
        help="just print the cmdlines (don't do anything)",
    )
    parser.add_argument(
        "-V",
        "--version",
        action="version",
        version="%%(prog)s %s" % (VERSION,),
        help="print version number and exit",
    )

    args = parser.parse_args()
    args.verbose = args.verbose - args.quiet
    del args.quiet
    return args


def find_file(filename, searchpaths):
    for p in [""] + searchpaths:
        f = os.path.join(p, filename)
        if os.path.exists(f):
            return os.path.realpath(f)
    return None


def find_unique_files(files, searchpaths):
    result = []
    for f in files:
        f = find_file(f, searchpaths)
        if f and f not in result:
            result.append(f)
    return result


def readConf(configfile, source=None, target=None, filters=[]):
    try:
        import configparser
    except ImportError:
        import ConfigParser as configparser
    config = configparser.ConfigParser()
    config.read(configfile)
    configdir = os.path.dirname(configfile)
    cfg = config.defaults()
    if config.sections():
        section = config[config.sections()[0]]
        cfg = {k: v for k, v in section.items()}
    source = source or cfg.get("source", None)
    target = target or cfg.get("target", None)
    filters = list(filters)
    f = cfg.get("filter")
    if f:
        filters = [f] + filters
    filters = find_unique_files(filters, [configdir])
    return (source, target, filters)


def expandConfigs(confs):
    result = []
    for c in confs:
        if os.path.isfile(c):
            c = [c]
        elif os.path.isdir(c):
            c = [
                os.path.join(c, f) for f in sorted(os.listdir(c)) if f.endswith(".conf")
            ]
        else:
            post("skipping non-existent config '%s'" % c)
            c = []
        for f in c:
            f = os.path.realpath(f)
            if f not in result:
                result.append(f)
    return result


def runCmd(config, args, dry=False):
    import subprocess

    options = []
    source, target, filters = readConf(config, args.source, args.target, args.filter)

    if args.dry_run:
        options += ["--dry-run"]
    if args.verbose > 0:
        options += ["--stats"]
        options += ["-v"] * (args.verbose - 1)

    # remove extroneous files
    options += ["--delete"]
    # archive mode (permission preservation)
    options += ["-a"]
    # preserve full paths
    options += ["-R"]

    # character translation
    # options += ['--iconv=UTF8,ISO8859-15"']

    if filters:
        options += ["--delete-excluded"]
    for x in filters:
        options += ["--filter", "merge %s" % x]

    options += [source]
    options += [target]

    cmd = ["rsync"] + options

    if args.debug:
        post(cmd)

    if dry:
        cmd = ["echo"] + cmd
    subprocess.call(cmd)


if __name__ == "__main__":
    import sys

    args = parseCmdlineArgs()
    args.config = expandConfigs(args.config)

    for c in args.config:
        runCmd(c, args, False)
