#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#créé par Pierre, Danrun

import os, re
from bs4 import BeautifulSoup


#fonction pour nettoyage
def nettoyage(chaine):
	nvl_chaine = re.sub(r"(« | »|« | »)", '"', re.sub(r'<.*?>', '', chaine)).replace("’","'") #on retire les balises <br> (cf corpus 2016) <title> et <description>, puis connerie des espaces normales anormales
	if nvl_chaine and nvl_chaine[-1].isalnum() : #pas de ?.
		nvl_chaine += '.'
	return nvl_chaine


#dictionnaire qui permet de gérer les catégories, le compteur des archives, et les doublons en fonction des noms de fichier
#structure: 'nom_fichier': ['catégorie', compteur, 0/set_doublons, 0/objet wrapper xml, 0/objet wrapper txt]

cat_name = {
	'0,2-3236,1-0,0.xml': ['actualite-medias', 0, 0, 0, 0],
	'0,2-3234,1-0,0.xml': ['economie', 0, 0, 0, 0],
	'0,2-3210,1-0,0.xml': ['international', 0, 0, 0, 0],
	'0,57-0,64-823353,0.xml': ['politique', 0, 0, 0, 0],
	'0,2-3242,1-0,0.xml': ['sport', 0, 0, 0, 0],
	'0,2-3238,1-0,0.xml': ['vous', 0, 0, 0, 0],
	'0,2-3476,1-0,0.xml': ['cinema', 0, 0, 0, 0],
	'0,2-3214,1-0,0.xml': ['europe', 0, 0, 0, 0],
	'0,2-3260,1-0,0.xml': ['livres', 0, 0, 0, 0],
	'env_sciences.xml': ['sciences', 0, 0, 0, 0],
	'0,2-651865,1-0,0.xml': ['technologies', 0, 0, 0, 0],
	'0,2-3546,1-0,0.xml': ['voyage', 0, 0, 0, 0],
	'0,2-3246,1-0,0.xml': ['culture', 0, 0, 0, 0],
	'0,2-3232,1-0,0.xml': ['idees', 0, 0, 0, 0],
	'0,2-3244,1-0,0.xml': ['planete', 0, 0, 0, 0],
	'0,2-3224,1-0,0.xml': ['societe', 0, 0, 0, 0],
	'0,2-3208,1-0,0.xml': ['une', 0, 0, 0, 0],
}


###############################################################################################################################
'''
cette partie (facultative) permet de rendre le programme plus 'pérenne'
il permet de mettre le dictionnaire à jour en fonction du contenu de nos fichiers
ainsi nous pouvons ajouter quelques flux rss et relancer le programme, les doublons et les compteurs seront gérés correctement
'''
if os.path.exists("./SORTIE_V10"):
	for cat in os.listdir('./SORTIE_V10'):
		for ele in cat_name.values():
			if ele[0] == cat:
				with open('./SORTIE_V10/{0}/{0}.xml'.format(cat),'r', encoding = 'UTF-8', newline = '\n') as fichierxml:
					contenu = fichierxml.read()
					title_list = re.findall('<title>.*?</title>', contenu)
					nbarchive = len(title_list)
					titles = set(title_list)
					ele[1], ele[2] = nbarchive, titles

###############################################################################################################################

#on affiche et demande les catégories à l'utilisateur
for i in cat_name.values():
	print(i[0])

demande = input('Indiquez une ou plusieurs catégories (séparées par espace)\n> ')

cat_demande = re.findall(r'[\w-]+', demande.lower())

#dictionnaire pour renommer les mois
months = {
	'Jan': '01',
	'Feb': '02',
	'Mar': '03',
	'Apr': '04',
	'May': '05',
	'Jun': '06',
	'Jul': '07',
	'Aug': '08',
	'Sep': '09',
	'Oct': '10',
	'Nov': '11',
	'Dec': '12',
}

#on renomme les mois en nombre latin pour traiter dans l'ordre 
for dir in os.listdir('./2018'):
	try:
		despath = './2018/' + months[dir]
		dirpath = './2018/' + dir
		os.rename(dirpath, despath)
	except:
		pass

#on parcourt toute l'arborescence
for root, dirs, files in os.walk('./2018'):
	for name in files :
		if name in cat_name and cat_name[name][0] in cat_demande: #on exclut les fichiers non pertinents ex : fil.*.xml et on traite seulement les catégories demandées

			#on récupère la catégorie demandée et le chemin du fichier
			cat = cat_name[name][0]
			filename = os.path.join(root, name)

			#extraction de la date de publication depuis le chemin du fichier
			pubdate_list = re.findall('\d+', root)
			pubdate = '-'.join(pubdate_list[:3])

			#contrôle du progrès de traitement
			print(filename + ' : ' + cat)

			#si aucun dossier ne correspond à la catégorie demandée alors on le crée avec ses fichiers xml et txt, en les ouvrant en mode w+ (création, écriture et lecture)
			try:
				os.makedirs("./SORTIE_V10/" + cat)
				xmltmp = open('./SORTIE_V10/{0}/{0}.xml'.format(cat), 'w+', encoding = 'UTF-8', newline = '\n')
				txttmp = open('./SORTIE_V10/{0}/{0}.txt'.format(cat), 'w+', encoding = 'UTF-8', newline = '\n')
				xmltmp.write('<?xml version="1.0" encoding="UTF8"?>\n<file>\n</file>')
				cat_name[name][2] = set() #on crée un objet set qui permet de gérer les doublons
				
			#si les fichiers existent déjà, on les ouvre en mode r+ (lecture + écriture sans écrasement)
			except:
				xmltmp = open('./SORTIE_V10/{0}/{0}.xml'.format(cat), 'r+', encoding = 'UTF-8', newline = '\n')
				txttmp = open('./SORTIE_V10/{0}/{0}.txt'.format(cat), 'r+', encoding = 'UTF-8', newline = '\n')

			#on met les deux fichiers ouverts dans l'entrée correspondante en remplaçant le 0
			cat_name[name][3] = xmltmp
			cat_name[name][4] = txttmp

			#on télécharge les données depuis le dictionnaire
			cat, counter, titles, sortiexml, sortietxt = cat_name[name]

			#ouverture d'un fichier
			with open(filename, 'rb') as fichier:

				#utilisation du parser xml
				soup = BeautifulSoup(fichier, 'lxml-xml')

				#on récupère le contenu des balises item
				items = soup.find_all('item')

				for item in items:

					#nettoyage avant gestion de doublons: ce sont les titres "nettoyés" qui sont stockés dans notre set (cf lignes 48-57), donc pour bien détecter les doublons, on est obligé de traiter dans cet ordre
					name_title = nettoyage(str(item.title)) #pour régler les &amp;
					name_title_xml = '<title>' + name_title + '</title>'

					#on compte le nombre d'élément dans le set
					prev_len = len(titles)

					#gestion des doublons avec set
					titles.add(name_title_xml)

					#s'il s'agit d'un élément doublon, la fonction add n'a pas d'effet, donc la longueur du set ne change pas; sinon on écrit le titre et la description dans le fichier ouvert précédemment
					if len(titles) != prev_len:
						sortietxt.seek(0, 2) #pb d'écriture en milieu de la phrase
						sortiexml.seek(sortiexml.seek(0,2) - 7)
						sortiexml.write('<archive n="{0}">\n{1}\n'.format(counter, name_title_xml))
						sortietxt.write(name_title + '\n')
						counter += 1

						#gestion des cas particuliers: description manquante
						if item.description and item.description.string:
							name_description = nettoyage(str(item.description)) 
							sortiexml.write('<description>' + name_description + '</description>\n')
							sortietxt.write(name_description + '\n\n')
						else:
							sortietxt.write('\n')

						sortiexml.write('<pubDate>' + pubdate + '</pubDate>\n</archive>\n</file>')

			#on met le dictionnaire à jour
			cat_name[name][1] = counter
			cat_name[name][2] = titles

#fermeture des fichiers ouverts
for fermeture in cat_name.values():
	if fermeture[3] != 0:
		fermeture[3].close()
		fermeture[4].close()
