#! /usr/bin/env python3

"""
Usage:
    prefixspan-cli (frequent | top-k) <threshold> [options] [<file>]

    prefixspan-cli --help


Options:
    --minlen=<minlen>  Minimum length of patterns. [default: 1]
    --maxlen=<maxlen>  Maximum length of patterns. [default: 1000]

    --key=<key>        Custom key function for both frequent and top-k algorithms. [default: ]
                       Must be a Python lambda function in form of "lambda patt, matches: ...".
                       Must be anti-monotone, i.e. for patt1 ⊑ patt2, f(patt1, matches1) ≥ f(patt2, matches2).
                       Returns a float value.

    --filter=<filter>  Custom filter function for both frequent and top-k algorithms. [default: ]
                       Must be a Python lambda function in form of "lambda patt, matches: ...".
                       Returnss a boolean value.

    --nopruning        Disable anti-monotone based pruning. Can be extremely slow.
                       Should only use for non-anti-monotone key function or benchmarking.
"""

import sys
from functools import partial

from docopt import docopt

from prefixspan.api import PrefixSpan

print2 = partial(print, file=sys.stderr)

def checkArg(arg, cond):
    # type: (str, Callable[[int], bool]) -> int
    try:
        val = int(argv[arg])
        if not cond(val):
            raise ValueError
    except ValueError:
        print2("ERROR: Cannot parse {}.".format(arg))
        print2(__doc__)
        sys.exit(1)

    return val


def checkFunc(arg):
    # type: (str) -> Callable[Any, Any]
    try:
        return eval(argv[arg])
    except:
        print2("ERROR: Cannot parse {}.".format(arg))
        print2(__doc__)
        sys.exit(1)


if __name__ == "__main__":
    argv = docopt(__doc__)

    db = [
        [int(v) for v in line.rstrip().split(' ')]
        for line in (open(argv["<file>"]) if argv["<file>"] else sys.stdin)
    ]

    ps = PrefixSpan(db)

    key = checkFunc("--key") if argv["--key"] else None
    filter = checkFunc("--filter") if argv["--filter"] else None

    pruning = not argv["--nopruning"]

    if argv["frequent"]:
        threshold = checkArg("<threshold>", lambda v: key or 0 < v <= len(db))
        func = ps.frequent
    elif argv["top-k"]:
        threshold = checkArg("<threshold>", lambda v: key or v > 0)
        func = ps.topk

    if argv["--minlen"]:
        ps.minlen = checkArg("--minlen", lambda v: v > 0)
    if argv["--maxlen"]:
        ps.maxlen = checkArg("--maxlen", lambda v: v >= ps.minlen)

    for freq, patt in func(threshold, key=key, filter=filter, pruning=pruning):
        print("{} : {}".format(' '.join(str(v) for v in patt), freq))
