

import random

from twisted.application import service
from twisted.application import internet

from nevow import appserver
from nevow import renderer
from nevow import tags


def flatten_menu(data):
    html_menu = "<ul>"
    items = data.items()
    items.sort()
    for k, v in items:
        html_menu += "<li>%s</li>" % k
        html_menu += "<ul>"
        v.sort()
        for i in v:
            if isinstance(i, dict):
                html_menu += flatten_menu(i)
            else:
                html_menu += "<li>%s</li>" % i
        html_menu += "</ul>"
    html_menu += "</ul>"
    return html_menu


class Menus(renderer.Renderer):
    document = tags.html[
    tags.head[tags.title["Hello"]],
    tags.body[
        tags.div(style="border: 1px dotted black; margin: 1em")[
            tags.ul(renderer=tags.directive("menu"))
        ],
        tags.div(style="border: 1px dotted black; margin: 1em")[
            tags.ul(renderer=tags.directive("stan_menu"))
        ]
    ]
]
    def render_menu(self, context, data):
        return tags.xml(flatten_menu(data))

    def render_stan_menu(self, context, data):
        """Render a dictionary of string keys and list of string/dict values."""
        menu = context.tag
        items = data.items()
        items.sort()
        for k, v in items:
            # Add a list item with our key as the label
            menu.children.append(tags.li[k])
            # Add an ul tag to this menu for the submenu
            submenu = tags.ul()
            menu.children.append(submenu)

            # For every element of the value list
            v.sort()
            for i in v:
                # if it's a dict, cause render_stan_menu to be called on it, and the output placed in the submenu tag
                if isinstance(i, dict):
                    submenu.children.append(tags.ul(data=i, renderer=self.render_stan_menu))
                # if it's a string, just add a list item with the string to the menu
                else:
                    submenu.children.append(tags.li[ i ])
        return menu


menu_items = {
    "A": ["a", "b", "c"],
    "B": ["d", "e", "f"],
    "C": ["g", "h", {"i":
        ["x", "y", "z"]
    }]
}


application = service.Application("nestedmenus")
internet.TCPServer(
    8080, 
    appserver.NevowSite(
        Menus(
            menu_items
        )
    )
).setServiceParent(application)
