import re


def is_dotted_chain(atom_expr):
    """
    Assert whether the given atom_expr is a dotted chain

    Examples:

    batch(a)(b)
    .sample(
        frac=param1,
        rs=param2,
    )
    .reset_index(drop1=True)(drop2=True)
    .reset_index(drop=True).reset_index(drop=True)
    --> True

    batch
    (batch)
    --> False

    batch,
    batch,
    --> False

    batch
    .batch
    --> True

    batch
    .batch(
        x=4,
    )
    --> True

    """
    # print(atom_expr.get_code())
    # print(atom_expr)
    children = atom_expr.children

    # first node should start with \n + tabs (sapces multiple of 4)
    prefix_child1 = children[0].get_first_leaf().prefix
    if not re.match(r"\n(?:\s{4})+", prefix_child1):
        return False

    # more than one child needed to be a dotted chain
    if len(children) < 2:
        return False

    # all children after the first one that start with \n + tabs should have a . afterwards
    # otherwise it's not a dotted chain
    for child in children[1:]:
        code = child.get_code()
        if re.match(r"\n(?:\s{4})+", code):
            if not code.strip().startswith("."):
                return False

    return True