#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 26 10:53:32 2026

@author: pjoulaud
"""
import doctest

class Noeud:
    """
    Objet Noeud
    >>> n1 = Noeud()
    >>> n2 = Noeud(1)
    >>> n3 = Noeud(2, n2)
    
    """
    def __init__(self, val:int=None, n=None):
        # assert isinstance(val, int)
        # assert isinstance(n, __main__.Noeud)
        self.valeur = val 
        self.noeud_suivant = n
    def __repr__(self):
        return f"{self.valeur}->{self.noeud_suivant}"
        
class ListeAbstraite:
    """
    Objet ListeAbstraite
    >>> l = ListeAbstraite()
    >>> n1 = Noeud(1)
    >>> l1 = ListeAbstraite(n1)
    
    """
    def __init__(self, n:Noeud=None):
        self.noeud = n
    def __repr__(self):
        return f"[{self.noeud}]"
    
    
    
def vide():
    """
    Créer un objet de class ListAbstraite vide
    >>> l = vide()
    >>> isinstance(l, ListeAbstraite)
    True
    >>> l.noeud==None
    True

    """
    return ListeAbstraite()

def est_vide(l:ListeAbstraite)->bool:
    """
    Fonction qui teste si la ListeAbstraite est vide
    >>> l = vide()
    >>> est_vide(l)
    True
    >>> n = Noeud(1)
    >>> l2 = ListeAbstraite(n)
    >>> est_vide(l2)
    False

    """
    if l.noeud==None:
        return True
    return False

def ajout_en_tete(n:Noeud, l:ListeAbstraite)->ListeAbstraite:
    """
    Fonction qui ajoute un entête à une ListeAbstraite
    >>> l = vide()
    >>> n1 = Noeud(1)
    >>> ajout_en_tete(n1, l)
    [1->None]
    >>> n2 = Noeud(2)
    >>> ajout_en_tete(n2, l)
    [2->1->None]
    >>> n3 = Noeud(3)
    >>> ajout_en_tete(n3, l)
    [3->2->1->None]

    """
    if est_vide(l):
        l.noeud = n
    else :
        n.noeud_suivant = l.noeud
        l.noeud = n
    return l

def suppr_en_tete(l:ListeAbstraite)->ListeAbstraite:
    """
    Fonction qui supprime l'entête d'une ListeAbstraite
    >>> l = vide()
    >>> n1 = Noeud(1)
    >>> ajout_en_tete(n1, l)
    [1->None]
    >>> n2 = Noeud(2)
    >>> ajout_en_tete(n2, l)
    [2->1->None]
    >>> n3 = Noeud(3)
    >>> ajout_en_tete(n3, l)
    [3->2->1->None]
    >>> suppr_en_tete(l)
    [2->1->None]

    """
    if not est_vide(l):
        noeud_a_supprimer = l.noeud
        l.noeud = l.noeud.noeud_suivant
        noeud_a_supprimer.noeud_suivant = None
        del noeud_a_supprimer
    return l

def cons(val:int, l:ListeAbstraite)->ListeAbstraite:
    """
    Fonction qui complète une ListeAbstraite en y ajoutant une valeur
    >>> l = vide()
    >>> cons(0, l)
    [0->None]
    >>> cons(1, l)
    [1->0->None]
    >>> l1 = vide()
    >>> cons(5, cons(4, cons(3, cons (2, cons(1, cons(0,l1))))))
    [5->4->3->2->1->0->None]
    """
    n = Noeud(val)
    if est_vide(l):
        l.noeud = n
    else :
        n.noeud_suivant = l.noeud
        l.noeud = n
    return l

def compte(l:ListeAbstraite)->int:
    """
    Fonction qui compte le nombre d' éléments dans une ListeAbstraite
    >>> l1 = vide()
    >>> cons(5, cons(4, cons(3, cons (2, cons(1, cons(0,l1))))))
    [5->4->3->2->1->0->None]
    >>> compte(l1)
    6
    """
    long = 0
    n = l.noeud
    while n!=None:
        long = long + 1
        n = n.noeud_suivant
    return long
        

doctest.testmod()
