# Lezione 16 - Esercizio 1 - Lista di funzioni
# Scrivere una funzione per ciascuna delle seguenti operazioni su liste di numeri
# interi, e fornire un programma per collaudare (testing) ciascuna funzione.
# 
# 1. Scambiare tra loro il primo e l’ultimo elemento della lista.
# 2. Far slittare tutti gli elementi della lista di una posizione, spostando
#    l’ultimo elemento nella prima posizione.
#    Ad esempio, la lista 1 4 9 16 25 deve diventare 25 1 4 9 16.
# 3. Sostituire con 0 tutti gli elementi di valore pari.
# 4. Eliminare l’elemento centrale della lista se questa ha dimensione dispari,
#    altrimenti eliminare i due elementi centrali.
# 5. Restituire il secondo valore maggiore della lista.
# 6. Restituire True se e solo se la lista è ordinata in senso crescente.

import random

def scambia_primo_ultimo(lista: list[int]) -> list[int]:
    lista[0], lista[-1] = lista[-1], lista[0]
    return lista

def scambiatore(lista):
    primo_elemento = lista.pop(0)
    ultimo_elemento = lista.pop()
    lista.append(primo_elemento)
    lista.insert(0, ultimo_elemento)
    return lista

def slitta_elementi(lista: list[int]) -> list[int]:
    if len(lista) == 0:
        return []
    ultimo_elemento = lista.pop()
    lista.insert(0, ultimo_elemento)
    return lista

def sostituzione_con_zero(lista: list[int]) -> list[int]:
    for indice, elemento in enumerate(lista):
        if elemento % 2 == 0:
            lista[indice] = 0
    
    return lista

def sostituzione(lista):
    for numero in lista:
        if numero % 2 == 0:
            numero = 0

# es. lista lunga 15, si ha
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
#               ^
# (len(lista) - 1) / 2
# lista lunga 14, si ha
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
#             ^ ^                
# len(lista) / 2
# 0 1 2 3 4 5 6 7 8 9 10 11 12
#             ^
# len(lista) / 2

def elimina_centrali(lista: list[int]) -> list[int]:
    if len(lista) == 0:
        return []
    elif len(lista) % 2 == 0:
        lista.pop(int(len(lista) / 2))
        
    lista.pop(int(len(lista) / 2))
    
    return lista

def elimina(lista: list[int]) -> list[int]:  # 15 / 2 = 7.5 ----- 15 // 2 = 7
    if len(lista) == 0:
        return lista
    middle = len(lista) // 2
    if len(lista) % 2 == 0:
        return lista[:middle-1] + lista[middle+1:]
    else:
        return lista[:middle] + lista[middle+1:]
    
def secondo_maggiore(lista: list[int]) -> int:  # [6, 6, 5, 2, 2, 2, 1]
    valore_maggiore = max(lista)  # 6
    numero_di_massimi = lista.count(valore_maggiore)  # 2
    for _ in range(numero_di_massimi):  # lo fa 2 volte
        lista.remove(valore_maggiore)  # [6, 5, 2, 2, 2, 1] - prima it.
                                       # [5, 2, 2, 2, 1] - seconda it.
    return max(lista)

def valore_maggiore_della_lista(lista):  # [6, 6, 5, 2, 2, 2, 1]
    numero_di_massimi = lista.count(max(lista))  # 2
    lista_ordinata = sorted(lista)  # [1, 2, 2, 2, 5, 6, 6]
    #                                  0  1  2  3  4  5  6
    #                                 -7 -6 -5 -4 -3 -2 -1
    secondo_elemento_maggiore = lista_ordinata[-(numero_di_massimi) - 1]  # -2 - 1 = -3
    return secondo_elemento_maggiore

def secondo_maggiore(lista: list[int]) -> int:
    if len(lista) < 2:
        return None
    
    max_val = max(lista)
    lista_senza_max = []
    for x in lista:  # [6, 6, 5, 2, 2, 2, 1]
        if x != max_val:
            lista_senza_max.append(x)  # [5, 2, 2, 2, 1]
    
    if len(lista_senza_max) == 0:
        return None
    
    return max(lista_senza_max)

def verifica_se_crescente(lista: list[int]) -> list[int]:
    if len(lista) == 1:
        return True
    elif len(lista) == 0:
        return False
    
    crescente = True
    for indice, elemento in enumerate(lista):
        if indice > 0:
            if lista[indice - 1] > elemento:  # indice = 0, elemento = 43 ---- lista[indice - 1] -> lista[-1] 
                return False

    return crescente

def verificozza(data):
    for i in range(0, len(data) - 1):  # len(data) = 9 -- range(0, 8) -> [0, 1, 2, 3, 4, 5, 6, 7]
        if data[i] > data[i+1]:
            return False
    return True

def crescente(lista):
    if lista == sorted(lista):
        return True
    return False

listozza = []
for _ in range(50):
    listozza.append(random.randint(0, 100))

print(f"La lista, attualmente, è:\n{listozza}")
print("Scegli l'operazione che vuoi eseguire:")
print(" a. Scambia il primo e l'ultimo elemento della lista.")
print(" b. Slitta tutti gli elementi della lista di 1.")
print(" c. Cambia tutti gli elementi pari con 0.")
print(" d. Elimina elementi centrali.")
print(" e. Trova il secondo elemento maggiore della lista.")
print(" f. Verifica se la lista è ordinata in modo crescente.")

operazione = input("Scegli: ")
if operazione == "a":
    lista_risultante = scambia_primo_ultimo(listozza)
    print(f"Il risultato è:\n{lista_risultante}")
elif operazione == "b":
    lista_risultante = slitta_elementi(listozza)
    print(f"Il risultato è:\n{lista_risultante}")
elif operazione == "c":
    lista_risultante = sostituzione_con_zero(listozza)
    print(f"Il risultato è:\n{lista_risultante}")
elif operazione == "d":
    lista_risultante = elimina(listozza)
    print(f"Il risultato è:\n{lista_risultante}")
elif operazione == "e":
    print(f"Il secondo elemento maggiore è {secondo_maggiore(listozza)}")
elif operazione == "f":
    print(f"La lista è crescente? {verifica_se_crescente(listozza)}")