'''

ARGOMENTI:
---------------------------------------------------------------------
      liste annidate (matrici),  
      
      reportlab: canvas, units, pagesizes, colors
      
'''
from math import log
from reportlab.pdfgen.canvas import Canvas
from reportlab.lib.colors import black, white, yellow
from reportlab.lib.units import mm
from reportlab.lib.pagesizes import A4 


#-----------------------------------------------------------------------
# Concatena i numeri all'interno di una stringa 
# "skippando" tutto il resto e converte il risultato in un intero. 
# Restituisce -1 se non vi sono numeri all'interno della stringa
#-----------------------------------------------------------------------
def f_cnvStr2Int(s): # stringa
	listaNumeri = ["0","1","2","3","4","5","6","7","8","9"]
	sNum=""
	Tro=False
	for i in s:
		if i in listaNumeri:
			sNum=sNum+i
			Tro=True
	if not Tro:				# se nella stringa non vi sono numeri
		sNum=-1
	return int(sNum)

#-----------------------------------------------------------------------
# Calcola il logaritmo in base 2 del numero inserito, 
# "tronca" il risultato e aggiunge 1
#-----------------------------------------------------------------------
def f_getNumCartelle(nIns): # numero inserito
	return int(log(nIns,2))+1 



#-----------------------------------------------------------------------
# Converte i numeri in in una stringa di cifre binarie
#-----------------------------------------------------------------------
'''
	La conversione decimale > binario restituisce solo i valori significativi:
	
		Es.  "5" viene rappresentato in questo modo 0b101", 
		pero' a me serve la seguente rappresentazione "0000101".
		Quindi devo devo eliminare i due caratteri iniziali "0b" ed
		aggiungere, sempre all'inizio, una serie di 0 fino ad arrivare,
		con il "numero delle cifre", al "numero delle cartelle".
		
		Per lavorare meglio converto tutto in "stringhe"
		
'''
def f_getListaBinary(nIns, nCar): # numero inserito, numero di cartelle
	lista=[]
	for i in range (1, nIns+1):
		# converto in in binario e poi in stringa elimindo i primi due caratteri
		sBin=str(bin(i))[2:]   
		# aggiungo gli "0" all'inizio della stringa
		for j in range (len(sBin), nCar):
			# print ("       >>>",j,len(sBin))       	TEST
			sBin="0"+sBin
		lista.append(sBin) 
		# print (" >>>",sBin)							TEST
	return lista
	
	
	
#-----------------------------------------------------------------------
# Restituisce una matrice con l'elenco delle cartelle dove, ogni cartella
# contiene i relativi numeri
#-----------------------------------------------------------------------
def f_getCartelle(listaNumBin, nCar,nIns): # lista numeri in binario, numero di cartelle, numero inserito
	# creo un numero di liste vuote pari al numero delle cartelle
	# e le inserisco in una matrice
	matrice=[]
	for i in range (0,nCar):
		matrice.append([])
	# print (matrice)									TEST


	# scansiono la lista dei numeri in binario
	for n in range (1, nIns+1):
		nb=listaNumBin[n-1]
		# scansiono la stringa del numero binario partendo dalla prima cifra
		for c in range (0, nCar):  
			# nel controllo devo partire dall'ultimo carattere
			if nb[nCar-c-1]=="1":
				#inserisco il numero della relativa cartella 
				matrice[c].append(str(n))	
	return matrice

	
#-----------------------------------------------------------------------
# Inserisce le schede in un file PDF
#-----------------------------------------------------------------------
'''
		Questo pezzo di codice dovrebbe risiedere nel MAIN PROGRAM.
		Per comodita' e' stata costruita questa funzione.
		Per questo motivo non gli passo alcun parametro, ma 
		utilizzo le variabili "globali"
		
'''
def f_costruisciPDF():     
	
	# Definizione del canvas -------------------------------------------
	filePDF = Canvas(nomeFile) 
	filePDF.setPageSize((A4))

	# Impostazioni i colori ed il font ---------------------------------
	titFG = black					
	titBG = yellow
	txtFG = black
	txtBG = white
	
	
	cart=0
	while cart < nCartelle:
	
		# TITOLO
		
		# currentX e currentY sono i valori correnti della posizione in cui "stampare"
		margineX=20*mm; currentX=margineX
		margineY=40*mm; currentY=A4[1]-margineY
		
		filePDF.setFont('Helvetica', 40)
		filePDF.setFillColor(titBG)
		filePDF.setStrokeColor(titFG)
		rectBase=A4[0]-2*margineX
		rectAlte=40+4*mm
		filePDF.rect(currentX,currentY,rectBase,rectAlte,True,True)
		
		# alla fine della stampa dei numeri si dovra' costruire un
		# rettangolo di un' altezza che va dalla posizione currentY,
		# che si trova piu' in basso dell'ultima riga di numeri,
		# ad un punto piu' in alto della prima riga di numeri: 
		# remeberY ricorda questa posizione 
		rememberY= currentY
		
		currentX+=3*mm
		currentY+=4*mm
		filePDF.setFillColor(titFG)
		filePDF.drawString(currentX,currentY,"Cartella "+str(cart+1))
		
		
		# NUMERI
		dimFont=20
		filePDF.setFont('Courier', dimFont)
		filePDF.setFillColor(txtFG)
		filePDF.setStrokeColor(txtBG)
		
		currentX=margineX
		currentY-=20*mm
		# definisco i passi X e Y per la stampa di ogni numero
		passoX=3*dimFont
		passoY=1.5*dimFont
		
		for i in range(0,len(listaCartelle[cart])):
			filePDF.drawString(currentX+20,currentY,listaCartelle[cart][i])
			currentX+=passoX
			# se si supera il margine destro X si riazzera il margine
			# X e si incrementa il currentY
			if currentX>= A4[0]-2*margineX:
				currentX=margineX
				currentY-=passoY
		
		# RETTANGOLO DI CONTORNO AI NUMERI
		filePDF.setFont('Helvetica', 40)
		filePDF.setStrokeColor(txtFG)
		rectBase=A4[0]-2*margineX
		rectAlte=rememberY-currentY+passoY
		filePDF.rect(margineX,currentY-passoY,rectBase,rectAlte,True,False)
		
		# chiude la pagina	
		filePDF.showPage()
		cart+=1   
	# salva il PDF
	filePDF.save()

	
	
	
	
#-----------------------------------------------------------------------
# MAIN PROGRAM
# Utilizzo una forma predichiarativa per comodita'
#-----------------------------------------------------------------------
nMin=32	
nMax=255	    
nInserito=-1
nCartelle=0
listaNumBin=[]
listaCartelle=[]
nomeFile="FileCartelle.pdf"
	
while True:	
	sel = input("\n\nInserisci un numero da "+str(nMin)+" a "+ str(nMax) + "/x=abbandona: ")
	if sel in ("x","X"):
		break
	elif sel =="":
		print (" >>> OPZIONE NON VALIDA")
	else:
		nInserito=f_cnvStr2Int(sel)
		print (" >>> Numero inserito:", nInserito)
		if nInserito in range (nMin,nMax+1):
			nCartelle=f_getNumCartelle(nInserito)
			print(" >>> Numero di cartelle da costruire:", nCartelle)
			listaNumBin=f_getListaBinary(nInserito,nCartelle)
			print(" >>> Lista numeri in binario: \n\n", listaNumBin)
			listaCartelle=f_getCartelle(listaNumBin, nCartelle,nInserito)
			print(" >>> Lista delle cartelle: \n\n", listaCartelle)
			f_costruisciPDF()			
			print("\n\n >>> L'elenco delle cartelle si trova all'interno del file:", nomeFile)
		else:
			print (" >>> Il numero da inserire deve essere compreso tra", nMin, "e", nMax)
			
print ("\n CIAO!")



