#Cargamos librerias necesarias
import sqlite3
import json
from datetime import datetime
import time
#De todos los meses disponibles en los datos del torrent de de reddit elijo marzo de  2015
timeframe = '2015-03'
sql_transaction = []
start_row = 0
cleanup = 1000000
#vamos a almacenar los datos en un una BBDD sqlLite
connection = sqlite3.connect('{}.db'.format(timeframe))
c = connection.cursor()
#Nos creamos una función para crear la tabla donde guardamos los campos que nos interesan del #JSON. En este caso son:
def create_table():
    c.execute("CREATE TABLE IF NOT EXISTS parent_reply(parent_id TEXT PRIMARY KEY, comment_id TEXT UNIQUE, parent TEXT, comment TEXT, subreddit TEXT, unix INT, score INT)")
#Función para formatear los datos que vamos leyendo
def format_data(data):
    data = data.replace('\n',' newlinechar ').replace('\r',' newlinechar ').replace('"',"'")
    return data
# Esta función se utiliza para crear sentencias de inserción y confirmarlas en grupos
# en lugar de hacer que inserte uno a uno
def transaction_bldr(sql):
    global sql_transaction
    sql_transaction.append(sql)
    if len(sql_transaction) > 1000:
        c.execute('BEGIN TRANSACTION')
        for s in sql_transaction:
            try:
                c.execute(s)
            except:
                pass
        connection.commit()
        sql_transaction = []
#función que actualiza el comentarios en nuestra BBDD sqlLite
def sql_insert_replace_comment(commentid,parentid,parent,comment,subreddit,time,score):
    try:
        sql = """UPDATE parent_reply SET parent_id = ?, comment_id = ?, parent = ?, comment = ?, subreddit = ?, unix = ?, score = ? WHERE parent_id =?;""".format(parentid, commentid, parent, comment, subreddit, int(time), score, parentid)
        transaction_bldr(sql)
    except Exception as e:
        print('s0 insertion',str(e))
#Funcion que guarda en BBDD un comentario que tiene padre
def sql_insert_has_parent(commentid,parentid,parent,comment,subreddit,time,score):
    try:
        sql = """INSERT INTO parent_reply (parent_id, comment_id, parent, comment, subreddit, unix, score) VALUES ("{}","{}","{}","{}","{}",{},{});""".format(parentid, commentid, parent, comment, subreddit, int(time), score)
        transaction_bldr(sql)
    except Exception as e:
        print('s0 insertion',str(e))
        
#Funcion que guarda en BBDD un comentario que no tiene padre
def sql_insert_no_parent(commentid,parentid,comment,subreddit,time,score):
    try:
        sql = """INSERT INTO parent_reply (parent_id, comment_id, comment, subreddit, unix, score) VALUES ("{}","{}","{}","{}",{},{});""".format(parentid, commentid, comment, subreddit, int(time), score)
        transaction_bldr(sql)
    except Exception as e:
        print('s0 insertion',str(e))
#Solo guardamos los comentarios cuyo tamaño sea válido para el entrenamiento
def acceptable(data):
    if len(data.split(' ')) > 1000 or len(data) < 1:
        return False
    elif len(data) > 32000:
        return False
    elif data == '[deleted]':
        return False
    elif data == '[removed]':
        return False
    else:
        return True
#Función que encuentra el padre de un comentario dado
def find_parent(pid):
    try:
        sql = "SELECT comment FROM parent_reply WHERE comment_id = '{}' LIMIT 1".format(pid)
        c.execute(sql)
        result = c.fetchone()
        if result != None:
            return result[0]
        else: return False
    except Exception as e:
        #print(str(e))
        return False
#Función que nos da la puntuación de un comentario dado
def find_existing_score(pid):
    try:
        sql = "SELECT score FROM parent_reply WHERE parent_id = '{}' LIMIT 1".format(pid)
        c.execute(sql)
        result = c.fetchone()
        if result != None:
            return result[0]
        else: return False
    except Exception as e:
        #print(str(e))
        return False
    
if __name__ == '__main__':
    create_table() #Empezamos creando la tabla sobre la que almacenar los datos
    row_counter = 0 #Contador para ver en que parte del archivo estamos.Va contando las filas
    paired_rows = 0 #Contador que nos dice las filas que están emparejas.Pregunta con respuesta
    
#Abrimos la ubicación del archivo que nos iteresa y vamos lyendo filas
     with open('D:/reddit/RC_{}'.format(timeframe), buffering=1000) as f:
        for row in f:
            #print(row)
            #time.sleep(555)
            row_counter += 1
            #vamos obtiendo los datos quqe nos interesan de cada fila
            if row_counter > start_row:
                try:
                    row = json.loads(row)
                    parent_id = row['parent_id'].split('_')[1]
                    body = format_data(row['body'])
                    created_utc = row['created_utc']
                    score = row['score']
                    comment_id = row['id']
                    subreddit = row['subreddit']
    
                    #Todos los comentarios inicialmente no tendrán un padre. 
                    #Sin embargo, a medida que avanzamos en el documento, encontraremos 
                    #comentarios que tienen padres que tenemos en nuestra base de datos. 
                    #Cuando esto sucede, queremos agregar este comentario al padre existente. 
                    parent_data = find_parent(parent_id)
                    
                    existing_comment_score = find_existing_score(parent_id)
                    
                    #Si existe un comentario asociado al padre con mejor puntuación reemplazamos
                    #el comentario existente.
                    #En el caso que el comentario no tenga padre se inserta
                    if existing_comment_score:
                        if score > existing_comment_score:
                            if acceptable(body):#validamos el tamaño
                                sql_insert_replace_comment(comment_id,parent_id,parent_data,body,subreddit,created_utc,score)
                                
                    else:
                        if acceptable(body):
                            if parent_data:
                                if score >= 2:#solo tratamos comentarios con más de dos votos
                                    sql_insert_has_parent(comment_id,parent_id,parent_data,body,subreddit,created_utc,score)
                                    paired_rows += 1
                            else:
                                sql_insert_no_parent(comment_id,parent_id,body,subreddit,created_utc,score)
                except Exception as e:
                    print(str(e))
                    
            #Muestro por pantalla cada 100000 filas                
            if row_counter % 100000 == 0:
                print('Total Rows Read: {}, Paired Rows: {}, Time: {}'.format(row_counter, paired_rows, str(datetime.now())))
            
            #Finalmente borrmos los comentarios que no tengan padre cada 100000 lineas #procesadas
            if row_counter > start_row:
                if row_counter % cleanup == 0:
                    print("Cleanin up!")
                    sql = "DELETE FROM parent_reply WHERE parent IS NULL"
                    c.execute(sql)
                    connection.commit()
                    c.execute("VACUUM")
                    connection.commit()