# Works flawlessly with http://www.dynamicdrive.com/style/csslibrary/item/jquery_multi_level_css_menu_horizontal_blue/

class Menu(list):
    def render(self, ul=True):
        html = ''
        if ul:
            html += '<ul>'
        for menuitem in self:
            html += menuitem.render()
        if ul:
            html+= '</ul>'
        return html

    def add( self, title, url=None ):
        item = MenuItem( title, url )
        self.append( item )
        return item

class MenuItem(Menu):
    def __init__(self, title, url = None):
        super(MenuItem, self).__init__()
        
        self.title = title
        if not url:
            self.url = ''
        else:
            self.url = url

    def render_inside(self):
        html = '<a href="' + self.url + '" title="' + self.title + '">' + self.title + '</a>'
        return html

    def render(self):
        inside = self.render_inside()
        if len(self) == 0:
            html = '<li>' + inside + '</li>'
        else:
            html = '<li>' + inside + '<ul>'
            for menuitem in self:
                html += menuitem.render()
            html+= '</ul></li>'
        return html

    def append_to_menus( self, menus ):
        for menu in menus:
            menu.append( self )
        return self

class MenuFactories(object):
    def __init__(self, source, menu=None):
        self.source = source
        if not menu:
            menu = Menu()
        self.menu = menu

        if isinstance(source, dict):
            self.parse_dict(self.source, self.menu)

    def parse_dict(self, source, menu):
        for k, v in source.items():
            if isinstance(v, dict):
                self.parse_dict( v, menu.add(k ) )
            else:
                menu.add( k, v )

        return menu


# Example context processor:
def nav( request ):
    nav = {}
    immo = "Immobilier"
    user = "Utilisateur"
    admin = "Administration"

    menu = Menu()
    immo = menu.add( immo )
    user = menu.add( user )

    acheter = immo.add( "Acheter" )
    investissement = acheter.add( "Investissement locatif" )
    accession = acheter.add( "Accession" )
    louer = immo.add( "Louer" )

    menus = investissement, accession, louer
    
    MenuItem( "Chambres", "/cherche/chambres/accession/profil" ).append_to_menus( menus )
    MenuItem( "Appartements", "/cherche/appartements/accession/profil" ).append_to_menus( menus )
    MenuItem( "Villas, Maisons, Pavillons ...", "/cherche/villas-maisons-pavillons/accession/profil" ).append_to_menus( menus )
    MenuItem( "Masionn de ville, village ...", "/cherche/maisons-de-ville-village/accession/profil" ).append_to_menus( menus )
    MenuItem( "Maisons de caractère", "/cherche/maisons-de-caractère/accession/profil" ).append_to_menus( menus )
    MenuItem( "Parking, garages ...", "/cherche/parkings-garages/accession/profil" ).append_to_menus( menus )
    MenuItem( "Programmes neufs" ).append_to_menus( menus )

    if request.user.is_staff:
        admin = menu.add( "Administration" )
        admin.add( "Rechercher des utilisateurs", "/profiles/" )
        admin.add( "Interface Complête", "/admin" )

    if request.user.is_authenticated():
        # if "Partenaires" in request.user.groups.all()
        user.add( "Mes dernières recherches", "/mesrecherches/" )
        user.add( "Mes coordonnées", "/profiles/edit" )
        user.add( "Déconnection", "/accounts/logout" )
    else:
        user.add( "Recevoir un nouveau mot de passe", "/accounts/password/reset/" )
        user.add( "Enregistrement d'un nouveau compte", "/accounts/register/" )
        user.add( "Authentification", "/accounts/login" )
    # in the template, use {{ nav|safe }}
    return { 'nav': menu.render() }

# Example using the factory:
def nav( request ):
    menu = menus.Menu()

    if request.user.is_staff:
        nav = {
            "Portefeuille": {
                "Saisie d'une nouvelle location": '/admin/immo/location/add/',
                "Saisie d'un nouveau LCP (Immo d'entreprise)": '/admin/immo/lcp/add',
                "Saisie d'un nouveau terrain": '/admin/immo/terrain/add/',
                "Saisie d'un nouveau lot": '/admin/immo/lot/add/',
                "Statistique visite lot": '/statistiques/',
                "Rapprochement lot/contact": '/admin/immo/rapprochement/add/',
                "Rapprochement contact/lot": '/admin/immo/rapprochement/add/',
            },
            "Contact": {
                "Saisie d'un nouveau contact": '/admin/auth/user/add/',
                "Liste des contacts": '/admin/auth/user/',
                "Liste des demandes": '/admin/immo/demande/',
            },
            "Evenement": {
                "Saisie d'un evenement": '/admin/crm/evenement/add/',
                "Liste des evenements": '/admin/crm/evenement/'
            },
            "Reservation": {
                "Saisie de reservation de location": '/admin/resa/location/add/',
                "Liste des reservations de location": '/admin/resa/location/',
                "Saise de compromis de vente": '/admin/resa/vente/add/',
                "Liste des compromis de ventes": '/admin/resa/vente/',
            },
            "Administration": {
                "Analyse du portefeuille": {
                    "LCP (Immo d'entreprise)": '/admin/immo/lcp/',
                    "Terrain": '/admin/immo/terrain/',
                    "Lot": '/admin/immo/lot/',
                },
                "Analyse des activités des négociateur": '/?/',
                "Synthèse des rémunérations": '/?/',
                "Gestion des utilisateurs": '/admin/auth/user/',
                "Documents agence": '/admin/immo/document/',
                "Paramétrage du logiciel": '/admin/',
                "Paramétrage site Agence": '/admin/flatpages/flatpage/',
            },
        }
        f = menus.MenuFactories(nav, menu)