#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-

import random, sys, os

# define a quantidade maxima de questoes/respostas: 702 por enquanto.

letras_1 = ['A','B','C','D','E','F','G','H','I','J', 'K','L', 'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']

letras_2 = [x+y for x in letras_1 for y in letras_1]

letras = letras_1 + letras_2

identificadores = ['.-' , ',+' , ':-' , '=+', ';.', '...',  ';;;', '+++', '~~~', '***']

def lequestoes(arquivos):
    """ funcao que le os arquivos e cria uma lista com todas as perguntas, que sao dicionarios"""
    print 'crialista', arquivos
    listao = []
    respostas = []
    d = dict()

    # estados possiveis: fora de alguma questao 
    #                    dentro de uma questao - Q - pergunta
    #                    dentro de uma questao - A - respostas
    # quando esta fora de uma questao e encontra um Q, deve entrar em modo questao, adicionar a pergunta ao
    # dicionario
    # quando esta em modo questao e encontra um A, deve entrar em modo respostas, adicionar a resposta ao
    # dicionario
    # quando esta em modo respostas e encontra um A, adiciona a resposta ao dicionario
    # quando esta em modo respostas e encontra um Q, deve entrar em modo questao, adicionar o dicionario
    # ao listao de perguntas, zerar o dicionario e as respostas
    # quando esta em qualquer modo e encontra uma linha em branco, passa a proxima linha
    # quando esta em modo questao e encontra um Q, significa erro no arquivo: retorna ERRO. 
    
    for a in arquivos:
        arq = open(a)
        lista = []
        todaslinhas = arq.readlines()
        respostas = []
        estado = 'OUT'
        for linha in todaslinhas:
            if linha.startswith('Q:') and estado == 'OUT': # nova questao
                d = dict()
                estado = 'Q' # entra em modo questao
                linha = linha.lstrip(' ')
                d["q"] = linha[3:]
                d["t"] = linha[0]
            elif linha.startswith('Q') and estado == 'Q': # outra linha com Q -> erro
                print "Arquivo %s de questoes com erro linha %d " % (a, todaslinhas.index(linha))
                sys.exit(-1)
            if linha.startswith('A') and (estado == 'Q' or estado == 'A'):
                estado = 'A'  # entra em modo resposta
                linha = linha.lstrip(' ')
                if len(linha) > 4:
                    respostas.append(linha[3:])
                    d["a"] = respostas
                else:
                    print "linha len < 4"
            if linha.startswith('Q') and estado == 'A': # nova questao
                    listao.append(d)
                    respostas = []
                    d = dict()
                    estado = 'Q'
                    linha = linha.lstrip(' ')
                    d["q"] = linha[3:]
                    d["t"] = linha[0]
            if linha.startswith('\n'): # linha em branco separando questao
                if estado == 'A' and len(d):
                    listao.append(d)
                    respostas = []
                    d = dict()
                estado = 'OUT'
                pass
            # fim do loop
        if estado == 'A' and len(d): # terminaram as linhas e o dicionario contem dados
            listao.append(d)
            estado = 'OUT'
            d = {}
            respostas = []
        arq.close()

    return listao

def criasequencia(listao):
    """ cria uma sequencia (lista) de tuplas (q,a) a partir do listao geral de questoes """
    sequencia = [] # todas as possibilidades de perguntas (tuplas do tipo (Q,A))
    for q in listao:
        perg = q['q']
        resp = random.choice(q['a'])
        sequencia.append((perg,resp))
        if q['t'] != 'QNI':
            pass
    return sequencia
         
def criaprovas(sequencia, numprovas,questaoporprova):
    """ cada prova eh gerada aleatoriamente a partir da lista de tuplas com todas as questoes.
    recebe como argumentos: uma lista de tuplas (q,a), o num de provas a serem geradas e 
    quantas questoes cada prova deve ter.
    retorna as provas geradas e os gabaritos; as provas sao listas de tuplas (q,a) e os gabaritos sao listas de tuplas (num questao, letra resposta)
    """
    provas = []
    gabaritos = []
    for np in range(numprovas):
        prova = random.sample(sequencia,questaoporprova)
        provas.append(prova)
        perguntas = []
        respostas = []
        embaralha = range(len(prova))
        random.shuffle(embaralha)
        gabarito = []
        gaba_str = ''
        for i in range(len(prova)):
            gabarito.append((i+1,letras[embaralha[i]]))
        gabaritos.append(gabarito)
    return provas, gabaritos
            

def crialatex(sequencia, numprovas,questaoporprova):
    """ cria um arquivo .tex para cada prova e tb o arquivo gabarito para as provas
    recebe como argumentos: uma lista de tuplas (q,a), o num de provas a serem geradas e 
    quantas questoes cada prova tera.
    cada prova eh gerada aleatoriamente a partir da lista de tuplas com todas as questoes.
    retorna as provas geradas.
    """
    preambulo1 = """
\documentclass[10pt,brazil,a4paper]{article}
\usepackage[latin1]{inputenc}
\usepackage[portuguese]{babel}
%\usepackage{graphicx}
%\usepackage{multicol}
%\usepackage{shadow}
%\usepackage{pifont}
%\usepackage{listings}
%\usepackage{fancyvrb}

%\usepackage{boxedminipage}
%\usepackage{theorem}
\usepackage{verbatim}
\usepackage{tabularx}
%\usepackage{moreverb}
\usepackage{times}
%\usepackage{relsize}
\usepackage{pst-barcode}

\setlength{\\textwidth}{180mm}
\setlength{\\oddsidemargin}{-0.5in}
\setlength{\\evensidemargin}{0in}
\setlength{\\columnsep}{8mm}
\setlength{\\topmargin}{-28mm}
\setlength{\\textheight}{265mm}
\setlength{\\itemsep}{0in}
\\begin{document}
\\pagestyle{empty}
%\lstset{language=python}

                """
    preambulo2= """

\\textbf{Curso:}\\rule{11cm}{0.1pt}\hspace{0.5cm}\\textbf{Turma:}\\rule{3cm}{0.1pt}

\\textbf{Nome:}\\rule{11cm}{0.1pt} \hspace{0.5cm}\\textbf{nota:} \\rule{3cm}{0.1pt}

{\scriptsize 

\\textbf{Instruções:}
\\begin{verbatim}
   1. Proibida a consulta de livros ou anotações     2. Permitido o uso de calculadoras eletrônicas
   3. Somente serão consideradas as respostas da Parte 1 na região "Gabarito" desta página
\end{verbatim}
}


\\begin{tabularx}{\linewidth}{X|X}
\\textbf{Parte 1 -- Questões} """

    preambulo3 =  """

 & \\textbf{Respostas} \\\\ \hline \hline
%& \\\\

                """
                
    finaltabela = """
\end{tabularx}

%\\vspace{0.3cm}

\\textbf{Parte 1 -- Gabarito:}
                  """
    fimdocumento = """
    \end{document}
    """
    
    gabatabela = """

\\begin{tabular}[t]{|b{10mm}|b{10mm}|b{10mm}|b{10mm}|b{10mm}|b{10mm}|b{10mm}|b{10mm}|b{10mm}|b{10mm}|} \\\\ \hline
    """

    titulo = "\\textbf{\\centering \\large %s}" % tituloprova
    provas = []
    arqgaba = open('prova_'+'gb.tex','w')
    arqgaba.write(preambulo1.decode('utf-8').encode("latin1"))
    titulogaba = "%s \\textbf{\\large GABARITO}" % titulo
    arqgaba.write(titulogaba.decode('utf-8').encode('latin1'))
    
    for np in range(numprovas):
        prova = random.sample(sequencia,questaoporprova)
        arqprova = open('prova_'+str(np)+'.tex','w')
        arqprova.write(preambulo1.decode('utf-8').encode("latin1"))
        arqprova.write(titulo.decode('utf-8').encode("latin1"))
        arqprova.write(preambulo2.decode('utf-8').encode("latin1"))
        arqprova.write("%s" % (identificadores[np]))
        arqprova.write(preambulo3.decode('utf-8').encode("latin1"))
        #arqprova.write(initabela)
        
       
        provas.append(prova)
        perguntas = []
        respostas = []
        embaralha = range(len(prova))
        random.shuffle(embaralha)
        gabarito = []
        gaba_str = ''
        for i in range(len(prova)):
            arqprova.write("%d) %s & \n".encode('latin1') % (i+1, prova[embaralha[i]][0]))
            gabarito.append((i+1,letras[embaralha[i]]))
            gaba_str += letras[embaralha[i]]
            arqprova.write("%s) %s \\\\ \n".encode("latin1") % (letras[i],prova[i][1]))
        
        arqprova.write(finaltabela)
        #arqprova.write("%s" % (identificadores[np]))
        arqprova.write("\\hspace{1cm}\\begin{pspicture}(1,1in)\n")
        # a linha abaixo gera o codigo de barras do identificador (duplicado) da prova, 
        # inclui o texto no codigo de barras
        #arqprova.write("\\psbarcode[scalex=0.9,scaley=0.3]{%s%s}{includetext}{code39}\n" % (np,np))
        # gera codigo de barras usando a string do gabarito, nao inclui o texto no codigo de barras.
        arqprova.write("\\psbarcode[scalex=0.9,scaley=0.3]{%s}{}{code39}\n" % (gaba_str))
        arqprova.write("\\end{pspicture}\n")
        arqprova.write(gabatabela.encode('latin1'))
        for l in range(len(prova)):
            arqprova.write("{\\raggedright \\raisebox{0.8ex}[2.5ex][0.75ex]{%d}} ".encode("latin1") % (l+1))
            if l > 0 and (l+1) % 10 == 0:
                arqprova.write("\\\\ \hline \n")
            else:
                arqprova.write("&")
        arqprova.write("\\end{tabular}")

        arqprova.write(fimdocumento)

        arqgaba.write("\n\n\n PROVA")
        arqgaba.write("%s" % (identificadores[np]))
        arqgaba.write("\\hspace{1cm}\\begin{pspicture}(1,1in)\n")
        # a linha abaixo gera o codigo de barras do identificador (duplicado) da prova, 
        # inclui o texto no codigo de barras
        #arqprova.write("\\psbarcode[scalex=0.9,scaley=0.3]{%s%s}{includetext}{code39}\n" % (np,np))
        # gera codigo de barras usando a string do gabarito, nao inclui o texto no codigo de barras.
        arqgaba.write("\\psbarcode[scalex=0.9,scaley=0.3]{%s}{}{code39}\n" % (gaba_str))
        arqgaba.write("\\end{pspicture}\n")
        arqgaba.write(gabatabela.encode('latin1'))
        for l in range(len(prova)):
            arqgaba.write("{\\raggedright \\raisebox{0.8ex}[2.5ex][0.75ex]{%d}} %s ".encode("latin1") % (gabarito[l]))
            if l > 0 and (l+1) % 10 == 0:
                arqgaba.write("\\\\ \hline \n")
            else:
                arqgaba.write("&")
        arqgaba.write("\\end{tabular}")
        
        arqprova.close()
    
    arqgaba.write(fimdocumento)
    arqgaba.close()
    return provas
            

tituloprova = "Avaliação Bimestral"

def main():
    if len(sys.argv) > 1:
        arquivos = sys.argv[3:]
        numprovas = int(sys.argv[1])
        questaoporprova = int(sys.argv[2])
        print arquivos

    else:
        numprovas = int(raw_input("entre o numero de provas: "))
        questaoporprova = int(raw_input("entre o numero de questoes por prova: "))
        entrada = raw_input("entre os nomes dos arquivos, separados por espaco: ")
        entrada.rstrip('\n')
        arquivos = entrada.split(' ')
    global tituloprova
    tituloprova= raw_input("Digite o titulo da prova: ")
    lista = lequestoes(arquivos)
    sequencia = criasequencia(lista)
    provas = crialatex(sequencia, numprovas, questaoporprova)

if __name__ == '__main__':
    main()
     
