#!/usr/bin/env python

from lxml import etree
import regex

# XXX: this doesn't work for from patterns that use the ?: in (?:www\.)?
#      (one of many examples in Zoosk.com.xml)
# XXX: this doesn't figure out if a target host causes a particular rule
#      to be completely inapplicable (in which case it should probably be
#      ignored) for determining simplicity
# XXX: this doesn't catch simple rules that use alternation with
#      backreferences, like from="^http://(foo|bar)\.example\.com/"
#      to="\1.example.com"

def simple(f):
    tree = etree.parse(f)
    targets = [target.attrib["host"] for target in tree.xpath("/ruleset/target")]
    return all([
    # ruleset must not be default_off
    "default_off" not in tree.xpath("/ruleset")[0].attrib,
    # ruleset must not contain a match_rule
    "match_rule" not in tree.xpath("/ruleset")[0].attrib,
    # XXX: maybe also check for platform="mixedcontent" here
    # ruleset must not apply any securecookie patterns
    not tree.xpath("/ruleset/securecookie"),
    # ruleset must not contain any exclusions
    not tree.xpath("/ruleset/exclusion"),
    # targets must not contain any wildcards
    not any("*" in target for target in targets),
    # ruleset must not contain any downgrade rules
    not any("downgrade" in rule.attrib for rule in tree.xpath("/ruleset/rule")),
    # and every rule must itself be simple according to the criteria below
    all(simple_rule(rule, targets) for rule in tree.xpath("/ruleset/rule"))
    ])

def simple_rule(rule, targets):
    """Is this rule a simple rule?  A simple rule rewrites a single hostname,
    perhaps with an optional leading www\., to itself or to itself plus www.,
    at the top level with no other effects."""
    rule_from = rule.attrib["from"]
    rule_to = rule.attrib["to"]
    # Simple rule with no capture
    if regex.match(r"^\^http://[-A-Za-z0-9.\\]+/$", rule_from):
        applicable_host = unescape(regex.search(r"^\^http://([-A-Za-z0-9.\\])+/$", rule_from).groups()[0])
        if regex.match(r"^https://%s/" % applicable_host, rule_to) or regex.match("r^https://%s/" % applicable_host, rule_to):
            return True
        else:
            return False
    # Optional www
    if regex.match(r"^\^http://\(www\\\.\)\?[-A-Za-z0-9.\\]+/$", rule_from):
        applicable_host = unescape(regex.search(r"^\^http://\(www\\\.\)\?([-A-Za-z0-9.\\]+)/$", rule_from).groups()[0])
        if regex.match(r"^https://www\.%s/" % applicable_host, rule_to) or regex.match(r"^https://%s/" % applicable_host, rule_to):
            return True
        else:
            return False
    return False

def unescape(s):
    return s.replace(r"\.", ".")
