# Primera línea con todos los imports que se utilizaran
import collections
import operator
import re
import sqlite3
import unicodedata
import random
import requests
from pprint import pprint

"""
Explanation: Analizando la estructura musical del rock nacional con información de lacuerda
Teniendo hojas con acordes (también tablaturas y otros pero no se trendrán en cuenta) para miles de canciones de rock nacional, voy a tratar de hacer un análisis usando estos datos y el poder de Python y sus librerías
Se tratará de responder preguntas como estas:
* ¿Qué acordes son más utilizados?
* ¿Qué tipo de acordes son más utilizados (mayor, menor, séptima, etc.)
* ¿Cuáles son las "frases" más comunes? (secuencias de acordes que se repiten)
* ¿Cuáles son las tonalidades de acordes más frecuentes?
* ¿Con qué frecuencia se violan estas tonalidades?
Se parte con la base de datos sqlite generada por el crawler de lacuerda para analizar todos los datos.
Se utilizarán como librerías externas:
* sqlite y mongo para analizar datos
* matplotlib para graficar
* mingus para utilizar algunos conceptos de teoría musical
* requests para hacer consultas HTTP
End of explanation
"""


# Scrapeando bandas de wikipedia
def get_textarea_content(url):
    text = requests.get(url).text
    match = re.search(r'<textarea .*?>(.*)</textarea>',
                      text,
                      re.MULTILINE|re.DOTALL)
    assert match is not None, "no se encontró textarea"
    return match.group(1)

print(get_textarea_content('https://es.wikipedia.org/w/index.php?title=Anexo:Las_100_canciones_m%C3%A1s_destacadas_del_rock_argentino_seg%C3%BAn_Rolling_Stone_y_MTV&action=edit&section=1'))

# Busco los artistas de las 100 mejores canciones
text = get_textarea_content('https://es.wikipedia.org/w/index.php?title=Anexo:Las_100_canciones_m%C3%A1s_destacadas_del_rock_argentino_seg%C3%BAn_Rolling_Stone_y_MTV&action=edit&section=1')
re_link = r'\[\[(?!\d+)(?:[^|\]]+\|)?([^\]]+)\]\]'
artistas = []
for line in text.splitlines():
    links = re.findall(re_link, line)
    artistas.extend(links[1:])  # El primer elemento es el título de la canción
artistas = set(artistas)
#pprint(artistas)

# Busco los artistas de los 100 mejores álbumes
text = get_textarea_content('https://es.wikipedia.org/w/index.php?title=Anexo:Los_100_mejores_%C3%A1lbumes_del_rock_argentino_seg%C3%BAn_Rolling_Stone&action=edit&section=4')
artistas_albumes = set()
for line in text.splitlines():
    links = re.findall(re_link, line)
    if not links:
        continue
    artistas_albumes.add(links[0])  # El primer enlace linkea a la banda
#print(len(artistas_albumes), artistas_albumes)
artistas.update(artistas_albumes)  # Añado al set global de artistas

print('Con esto tenemos una lista de', len(artistas), 'artistas para analizar')

"""
Explanation: Lo primero que voy a hacer es generar mi dataset de canciones a utilizar. Para esto voy a tomar los textos que muestren los acordes de las canciones. Se utilizará siempre la mejor versión posible, una por canción. Solamente voy a utilizar artistas de rock nacional populares sacados de estas listas:
    https://es.wikipedia.org/wiki/Anexo:Las_100_canciones_m%C3%A1s_destacadas_del_rock_argentino_seg%C3%BAn_Rolling_Stone_y_MTV
    https://es.wikipedia.org/wiki/Anexo:Los_100_mejores_%C3%A1lbumes_del_rock_argentino_seg%C3%BAn_Rolling_Stone
    http://www.rollingstone.com.ar/1250916
End of explanation
"""


# Obtengo el set de slugs de artistas que hay en la base de datos
conn = sqlite3.connect('lacuerda.db')
artistas_lacuerda = {row[0] for row in conn.execute('select slug from artista')}
print('Artistas en la DB:', len(artistas_lacuerda))

def elimina_tildes(s):
    # Fuente: http://www.leccionespracticas.com/uncategorized/eliminar-tildes-con-python-solucionado
    return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))

def generar_slug(nombre):
    return re.sub(r'\W+', '', elimina_tildes(nombre.lower().replace(' ', '_').replace('-', '_')))

slugs_a_probar = set(map(generar_slug, artistas))
print(len(slugs_a_probar), 'generados de', len(artistas), 'nombres de artistas')
slugs_correctos = artistas_lacuerda.intersection(slugs_a_probar)
print(len(slugs_correctos), 'de', len(slugs_a_probar), 'slugs encontrados automáticamente')

slugs = {}
for artista in artistas:
    slug_a_probar = generar_slug(artista)
    if slug_a_probar in artistas_lacuerda:
        slugs[slug_a_probar] = artista  # Asocio el slug al nombre de la banda
    else:
        # Entrada de datos manual
        while True:
            slug = input('Nombre para %s (dejar en blanco para ignorar): ' % artista)
            if not slug:
                break
            if slug == 'quit':
                raise KeyboardInterrupt()  # No tengo ^C
            if slug not in artistas_lacuerda:
                print('El slug', slug, 'no pertenece a la base datos. Ingrese uno correcto')
            else:
                slugs[slug] = artista
                break
                
pprint(slugs)

"""
Explanation: Ya tenemos los nombres de los artistas. Ahora necesitamos para cada uno obtener el slug que le asignó lacuerda. Por ejemplo, si un artista es "Pescado Rabioso" el slug correcto es "pescado_rabioso". 
Generalmente tienen esta forma, aunque en algunos casos (ej: "Los auténticos decadentes" -> "autenticos") va a ser necesario cargarlo manualmente.
Voy a tratar de generar por cada artista un slug comun (uso el alfabeto ascii, convierto a minúscula y reemplazo espacios por guiones bajos). Si existe en la base de datos utilizo ese. Sino le doy la posibilidad al usuario de que lo introduzca manualmente.
End of explanation
"""


Cancion = collections.namedtuple('Cancion', ('artista', 'slug', 'titulo', 'contenido'))

# Selecciono la version de acordes mas votada de cada cancion de un conjunto de artistas
query = """ 
select a.slug, c.slug, c.titulo, v.contenido
from version as v
join 
	(select
	     id_cancion, max(puntaje) as max_puntaje
            from version
	 where formato="R"
	 group by id_cancion) as vj
	on v.id_cancion=vj.id_cancion and v.puntaje=vj.max_puntaje
join cancion as c on v.id_cancion=c.rowid
join artista as a on c.slug_artista=a.slug
where formato="R" and a.slug in (%s)""" % ','.join('?'*len(slugs))
canciones = [Cancion(*row) for row in conn.execute(query, tuple(slugs))]
print(len(canciones), 'canciones a analizar')

print(next(filter(lambda c: c.slug=='flaca', canciones)).contenido)

print(random.choice(canciones).contenido)

"""
Explanation: Una vez que tengo los slugs de los artistas a utilizar obtengo sus canciones y almaceno sus letras y acordes en una estructura de datos (en mi caso voy a usar una simple namedtuple).
End of explanation
"""


