"""This is temporary code to parse category
tree, stored in the settings.
The tree is plain text, with levels of branching 
reflected by indentation (2 spaces per level).
example of desired structure, when input is parsed

    cat_tree = [
        ['dummy', 
            [
                ['tires', [
                        ['michelin', [
                                ['trucks', []],
                                ['cars', []],
                                ['motorcycles', []]
                            ]
                        ],
                        ['good year', []],
                        ['honda', []],
                    ]
                ],
                ['abandonment', []],
                ['chile', []],
                ['vulcanization', []],
            ]
        ]
    ]
"""
from askbot.conf import settings as askbot_settings
from django.utils import simplejson

def get_leaf_index(tree, leaf_name):
    children = tree[1]
    for index, child in enumerate(children):
        if child[0] == leaf_name:
            return index
    return None

def _get_subtree(tree, path):
    clevel = tree
    for pace in path:
        clevel = clevel[1][pace]
    return clevel

def get_subtree(tree, path):
    """path always starts with 0,
    and is a list of integers"""
    assert(path[0] == 0)
    if len(path) == 1:#special case
        return tree[0]
    else:
        return _get_subtree(tree[0], path[1:])

def sort_tree(tree):
    """sorts contents of the nodes alphabetically"""
    tree = sorted(tree, lambda x,y: cmp(x[0], y[0]))
    for item in tree:
        item[1] = sort_tree(item[1])
    return tree

def get_data():
    """returns category tree data structure encoded as json
    or None, if category_tree is disabled
    """
    if askbot_settings.TAG_SOURCE == 'category-tree':
        return simplejson.loads(askbot_settings.CATEGORY_TREE)
    else:
        return None

def _get_leaf_names(subtree):
    leaf_names = set()
    for leaf in subtree:
        leaf_names.add(leaf[0])
        leaf_names |= _get_leaf_names(leaf[1])
    return leaf_names

def get_leaf_names(tree = None):
    """returns set of leaf names"""
    data = tree or get_data()
    if data is None:
        return set()
    return _get_leaf_names(data[0][1])

def path_is_valid(tree, path):
    try:
        get_subtree(tree, path)
        return True
    except IndexError:
        return False
    except AssertionError:
        return False

def add_category(tree, category_name, path):
    subtree = get_subtree(tree, path)
    children = subtree[1]
    children.append([category_name, []])
    children = sorted(children, lambda x,y: cmp(x[0], y[0]))
    subtree[1] = children
    new_path = path[:]
    #todo: reformulate all paths in terms of names?
    new_item_index = get_leaf_index(subtree, category_name)
    assert new_item_index != None
    new_path.append(new_item_index)
    return new_path

def _has_category(tree, category_name):
    for item in tree:
        if item[0] == category_name:
            return True
        if _has_category(item[1], category_name):
            return True
    return False

def has_category(tree, category_name):
    """true if category is in tree"""
    #skip the dummy
    return _has_category(tree[0][1], category_name)

def rename_category(
    tree, from_name = None, to_name = None, path = None
):
    if to_name == from_name:
        return
    subtree = get_subtree(tree, path[:-1])
    from_index = get_leaf_index(subtree, from_name)
    #todo possibly merge if to_name exists on the same level
    #to_index = get_leaf_index(subtree, to_name)
    child = subtree[1][from_index]
    child[0] = to_name
    return sort_tree(tree)

def _delete_category(tree, name):
    for item in tree:
        if item[0] == name:
            tree.remove(item)
            return True
        if _delete_category(item[1], name):
            return True
    return False

def delete_category(tree, name, path):
    subtree = get_subtree(tree, path[:-1])
    del_index = get_leaf_index(subtree, name)
    subtree[1].pop(del_index)
    return sort_tree(tree)

def save_data(tree):
    assert(askbot_settings.TAG_SOURCE == 'category-tree')
    tree_json = simplejson.dumps(tree)
    askbot_settings.update('CATEGORY_TREE', tree_json)
