#!/usr/bin/python3
#
# client showing use of command_hook_mirror

from simplestreams import mirrors
from simplestreams import log
from simplestreams import util

import argparse
import os
import re
import sys
import yaml


def warn(msg):
    sys.stderr.write("WARN: %s" % msg)


class ItemFilter(object):
    def __init__(self, content, noneval=""):
        rparsefmt="(\w+)[ ]*([!]{0,1}[=~])[ ]*(.*)[ ]*$"
        parsed = re.match(rparsefmt, content)

        if not parsed:
            raise ValueError("Unable to parse expression %s" % content)

        (key, op, val) = parsed.groups()

        if op in ("!=", "="):
            self._matches = val.__eq__
        elif op in ("!~", "~"):
            self._matches = re.compile(val).search
        else:
            raise ValueError("Bad parsing of %s" % content)

        self.negator = (op[0] != "!")
        self.op = op
        self.key = key
        self.value = val
        self.content = content
        self.noneval = noneval


    def __str__(self):
        return "%s %s %s [none=%s]" % (self.key, self.op,
                                       self.value, self.noneval)

    def __repr__(self):
        return self.__str__()

    def matches(self, item):
        val = str(item.get(self.key, self.noneval))
        return (self.negator == bool(self._matches(val)))


def get_filters(filters, noneval=""):
    flist = []
    for f in filters:
        flist.append(ItemFilter(f, noneval=noneval))
    return flist


class FilterMirror(mirrors.BasicMirrorWriter):
    def __init__(self, config=None):
        super(FilterMirror, self).__init__(config=config)
        if config is None:
            config = {}
        self.config = config
        self.filters = config.get('filters', [])
        outfmt = config.get('output_format')
        if not outfmt:
            outfmt = "%s"
        self.output_format = outfmt
            

    def load_products(self, path=None, content_id=None):
        return {'content_id': content_id, 'products': {}}

    def filter_item(self, data, src, target, pedigree):
        # src and target are top level products:1.0
        # data is src['products'][ped[0]]['versions'][ped[1]]['items'][ped[2]]
        data = util.products_exdata(src, pedigree)
        for f in self.filters:
            if not f.matches(data):
                return False
        return True

    def insert_item(self, data, src, target, pedigree, contentsource):
        # src and target are top level products:1.0
        # data is src['products'][ped[0]]['versions'][ped[1]]['items'][ped[2]]
        # contentsource is a ContentSource if 'path' exists in data or None
        data = util.products_exdata(src, pedigree)
        if 'path' in data:
            data.update({'item_url': contentsource.url})

        try:
            print(self.output_format % (data))
        except KeyError as e:
            sys.stderr.write("output format failed. Missing %s\n" % e.args)
            sys.stderr.write("item: %s\n" % data)


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--max', type=int, default=None, dest='max_items',
                        help='store at most MAX items in the target')

    parser.add_argument('--path', default=None,
                        help='sync from index or products file in mirror')

    parser.add_argument('--output-format', '-o', action='store', default=None)
    parser.add_argument('--verbose', '-v', action='count', default=0)
    parser.add_argument('--log-file', default=sys.stderr,
                        type=argparse.FileType('w'))

    parser.add_argument('mirror_url')
    parser.add_argument('filters', nargs='*', default=[])

    cmdargs = parser.parse_args()

    (mirror_url, path) = util.path_from_mirror_url(cmdargs.mirror_url,
                                                   cmdargs.path)

    level = (log.ERROR, log.INFO, log.DEBUG)[min(cmdargs.verbose, 2)]
    log.basicConfig(stream=cmdargs.log_file, level=level)

    smirror = mirrors.UrlMirrorReader(mirror_url)

    filters = get_filters(cmdargs.filters)
    cfg = {'max_items': cmdargs.max_items,
           'filters': filters,
           'output_format': cmdargs.output_format}

    tmirror = FilterMirror(config=cfg)
    tmirror.sync(smirror.reader, path)

if __name__ == '__main__':
    main()

# vi: ts=4 expandtab syntax=python
