/* Discursomático - Una herramienta auxiliar en la composición de
   discursos para políticos, managers y otros tipos de "líder".

   Copyright (C) 2006 Cesar Rincon.

   Este programa es Software Libre: usted puede redistribuirlo y/o
   modificarlo bajo los términos de la Licencia Pública General GNU
   (GNU General Public License, ó "GPL"), versión 2.0, como la publica
   la Free Software Foundation de Massachusetts, Estados Unidos.

   ESTE PROGRAMA SE DISTRIBUYE SIN GARANTÍA, ni siquiera una garantía
   implícita de funcionalidad o aptitud para ser comercializado.  Vea
   la GPL para más detalles.

   Puede obtener una copia de la GPL en la página web de este
   programa.  Alternativamente, escriba al autor.  Alternativamente,
   escriba a la Free Software Foundation, 59 Temple Place, Suite 330,
   Boston, MA 02111-1307 USA; recuerde solicitar la versión "2.0"
   explícitamente.

   La página web de este programa es: http://mengambrea.org/dm/
   Refiérase a ella para actualizaciones e información adicional.

   Para ponerse en contacto con el autor de este software, envíe
   correo electrónico dirigido a <cesar@mengambrea.org>; o correo
   convencional dirigido a Enlaces Tecnológicos, attn. Cesar Rincon,
   Av. Patria 1347-14, Mirador del Sol, 45054 Zapopan, Jalisco,
   MEXICO. */



/* Este programa es C ANSI, muy básico.  No tiene ningún prerrequisito
   más que la biblioteca estándar de C.  Debería compilar en cualquier
   compilador moderno y correr en cualquier plataforma.  Si detecta
   algún problema en un ambiente particular, por favor repórtelo al
   autor para que sea corregido.

   Como un ejemplo, para compilar con GCC, utilice una línea de
   comando similar a esta:

     gcc -W -Wall -ansi -O3 -o dm.cgi dm.c

   Y luego instale "dm.cgi" de forma que su servidor HTTP pueda
   ejecutarlo como un programa CGI.

   Recuerde modificar los "macros de configuración", abajo.  Y
   recuerde proveer una hoja de estilo CSS (piratéese la que hizo el
   autor para su sitio web, si lo desea). */



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>


/* MACROS DE CONFIGURACIÓN */

/* Actualice la versión si cambia algo. Si va a instalar esto en su
   propio servidor, y quiere dejar una liga a la página de
   Discursomático, use el URL absoluto:
   http://mengambrea.org/dm/ */
#define VERSION "<a href=\"/dm/\" target=\"_top\">Discursomático</a> 1.0.2"

/* Esto debería ser el URL vacío, "". Sin embargo, temo que algún
   browser chaqueto ignore el estándar y haga algo raro; de forma que
   estoy poniendo aquí el nombre con el que se ve el CGI en mi
   webserver. */
#define HANDLER_URL "dm.cgi"

#define SUPPORT_URL "mailto:cesar@mengambrea.org"

#define STYLESHEET_URL "/dm/discursomatic.css"

/* FIN DE MACROS DE CONFIGURACIÓN */


static const char* A[] = {
  "Queridos compañeros,",
  "La práctica de la vida cotidiana prueba que",
  "Las experiencias ricas y diversas muestran que",
  "El afán de organización, pero sobre todo",
  "Los superiores principios ideológicos condicionan que",
  "Es obvio señalar que",
  "Compañeros,",
  "Estimados amigos,",

  /* Las siguientes frases quedan mal como inicio del primer párrafo.
     Las 8 frases anteriores sí quedan bien, NA_INIT se define abajo
     como ese número. Si agrega más, muévale ahí. */

  "Por otra parte, y dados los condicionamientos actuales",
  "Asimismo,",
  "Sin embargo, no hemos de olvidar que",
  "De igual manera,",
  "No es indispensable argumentar el peso y la significación de estos "
  /* cont */ "problemas ya que",
  "Incluso, bien pudieramos atrevernos a sugerir que",
  "Pero pecaríamos de insinceros si soslayásemos que",
  "Por último, y como definitivo elemento esclarecedor, cabe añadir que",
};

static const char* B[] = {
  "la realización de las premisas del programa",
  "la complejidad de los estudios de los dirigentes",
  "el aumento constante, en cantidad y en extensión, de nuestra actividad",
  "la estructura actual de la organización",
  "el nuevo modelo de actividad de la organización",
  "el desarrollo continuo de distintas formas de actividad",
  "nuestra actividad de información y propaganda",
  "el reforzamiento y desarrollo de las estructuras",
  "la consulta con los numerosos militantes",
  "el inicio de la acción general de formación de las actitudes",
  "un relanzamiento específico de todos los sectores implicados",
  "la superación de experiencias periclitadas",
  "una aplicación indiscriminada de los factores confluyentes",
  "el proceso consensuado de unas y otras aplicaciones concurrentes",
  "el proceso acordado de unas y otras aplicaciones concurrentes",
  "la sinergia de nuestra unidad de trabajo"
};

static const char* C[] = {
  "nos obliga a un exhaustivo análisis",
  "cumple un rol esencial en la formación",
  "exige la precisión y la determinación",
  "ayuda a la preparación y a la realización",
  "garantiza la participación de un grupo importante en la formación",
  "cumple deberes importantes en la determinación",
  "facilita la creación",
  "obstaculiza la apreciación de la importancia",
  "ofrece un ensayo interesante de verificación",
  "implica el proceso de reestructuración y modernización",
  "habrá de significar un auténtico y eficaz punto de partida",
  "permite en todo caso explicitar las razones fundamentales",
  "asegura, en todo caso, un proceso muy sensible de inversión",
  "deriva de una indirecta incidencia superadora"
};

static const char* D[] = {
  "de las condiciones financieras y administrativas existentes.",
  "de las directivas de desarrollo para el futuro.",
  "del sistema de participación general.",
  "de las actitudes de los miembros hacia sus deberes ineludibles.",
  "de las nuevas proposiciones.",
  "de las direcciones educativas en el sentido del progreso.",
  "del sistema de formación de cuadros que corresponda a las necesidades.",
  "de las condiciones de las actividades apropiadas.",
  "del modelo de desarrollo.",
  "de las formas de acción.",
  "de las básicas premisas adoptadas.",
  "de toda una casuística de amplio espectro.",
  "de los elementos generadores.",
  "de toda una serie de criterios ideologicamente sistematizados en un "
  /* cont */ "frente común de actuación regeneradora."
};

#define NA_INIT 8
#define NA (sizeof(A)/sizeof(A[0]))
#define NB (sizeof(B)/sizeof(B[0]))
#define NC (sizeof(C)/sizeof(C[0]))
#define ND (sizeof(D)/sizeof(D[0]))

static char* concat4(const char* a, const char* b,
                     const char* c, const char* d) {
  char* r;
  size_t na, nb, nc, nd;

  na = strlen(a);
  nb = strlen(b);
  nc = strlen(c);
  nd = strlen(d);

  r = malloc(na + 1 + nb + 1 + nc + 1 + nd + 1);
  if(NULL != r) {
    memcpy(r, a, na);
    r[na] = ' ';
    memcpy(r + na + 1, b, nb);
    r[na + 1 + nb] = ' ';
    memcpy(r + na + 1 + nb + 1, c, nc);
    r[na + 1 + nb + 1 + nc] = ' ';
    memcpy(r + na + 1 + nb + 1 + nc + 1, d, nd);
    r[na + 1 + nb + 1 + nc + 1 + nd] = '\0';
  }

  return r;
}

static size_t count_words(const char* s) {
  size_t n = 1;
  while('\0' != s[0]) {
    if(' ' == s[0])
      ++n;
    ++s;
  }

  return n;
}

static int print_discurso(const size_t words) {
  char* frase;
  size_t n, p, t;
  int r, init, first, close_p;

  srand((unsigned int) time(NULL));
  r = 0;
  p = 0;
  t = 0;
  init = first = 1;
  close_p = 0;

  fputs("<div class=\"discurso\">\r\n\r\n", stdout);

  while(0 == r) {
    frase = concat4(A[rand() % (init ? NA_INIT : NA)],
                    B[rand() % NB],
                    C[rand() % NC],
                    D[rand() % ND]);
    init = 0;
    if(NULL != frase) {
      n = count_words(frase);
      if(0 == t || t + n < words) {
        if(!first)
          putchar(' ');
        else {
          fputs("<p>", stdout);
          first = 0;
          close_p = 1;
        }

        fputs(frase, stdout);
        free(frase);

        t += n;
        ++p;

        if(p > 1 && 0 == rand() % 2) {
          fputs("</p>\r\n\r\n", stdout);
          p = 0;
          first = 1;
          close_p = 0;
        }
      }
      else {
        free(frase);
        break;
      }
    }
    else
      r = -1;
  }

  if(close_p)
    fputs("</p>\r\n\r\n", stdout);

  fputs("</div>\r\n", stdout);

  return r < 0 ? r : (int) t;
}

static int parse_cgi_params(size_t* words_ret) {
  const char* method;
  const char* query_string;
  const char* p;
  size_t query_string_len;

  method = getenv("REQUEST_METHOD");
  if(NULL == method ||
     'G' != method[0] ||
     'E' != method[1] ||
     'T' != method[2] ||
     '\0' != method[3]) {
    return -1;
  }

  query_string = getenv("QUERY_STRING");
  /* QUERY_STRING: palabras=nnnn */
  if(NULL == query_string || '\0' == query_string[0]) {
    *words_ret = 0;
    return 0;
  }

  query_string_len = strlen(query_string);
  if(query_string_len < 10 || query_string_len > 13)
    return -1;

  if(0 != memcmp("palabras=", query_string, 9))
    return -1;

  query_string += 9;
  p = query_string;
  while('\0' != p[0]) {
    if(!isdigit(p[0]))
      return -1;
    ++p;
  }

  if(p == query_string)
    return -1;

  *words_ret = (size_t) atoi(query_string);

  return 0;
}

static void start_html(const char* title) {
  printf("Content-Type: text/html; charset=ISO-8859-1\r\n"
         "\r\n"
         "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
         " \"http://www.w3.org/TR/html4/loose.dtd\">\r\n"
         "<html lang=\"es\">\r\n"
         "<head>\r\n"
         "<title>%s</title>\r\n"
         "<link type=\"text/css\" href=\"" STYLESHEET_URL
         "\" rel=\"stylesheet\">\r\n"
         "</head>\r\n"
         "<body>\r\n"
         "<div id=\"contents\">\r\n\r\n",
         title);
}

static void end_html(void) {
  fputs("</div>\r\n"
        "</body>\r\n"
        "</html>\r\n",
        stdout);
}

static void print_form(const char* id, size_t words) {
  printf("<div class=\"forma\">\r\n"
         "<form action=\"" HANDLER_URL "\" method=\"GET\">\r\n"
         "<label for=\"%s\">palabras:</label>\r\n"
         "<input type=\"text\" name=\"palabras\" id=\"%s\" value=\"%d\" "
         "size=\"5\">\r\n"
         "<input type=\"submit\" value=\"Generar otro discurso\">\r\n"
         "</form>\r\n"
         "</div>\r\n\r\n",
         id, id, words);
 }

int main() {
  int r;
  size_t words;

  start_html("Discursomático");

  r = parse_cgi_params(&words);
  if(0 == r) {
    fputs("<h1>" VERSION " - Discurso generado automáticamente</h1>\r\n\r\n",
          stdout);
    print_form("p1", words < 100 ? 100 : words);
    r = print_discurso(words);
  }

  if(r >= 0) {
    printf("<hr>\r\n"
           "<div class=\"palabras\">(%d palabras)</div>\r\n\r\n", r);
    print_form("p2", words < 100 ? 100 : words);
  }
  else {
    printf("<div class=\"error\">\r\n"
           "<p>Ocurrió un error al procesar su petición.\r\n"
           "De verdad, qué pena.</p>\r\n"
           "<p>Si le nace, puede reportar esto al \r\n"
           "<a href=\"" SUPPORT_URL "\">\"administrador\"</a>.\r\n"
           "O puede <a href=\"" HANDLER_URL "\">probar de nuevo</a>.</p>\r\n"
           "</div>\r\n\r\n");
  }

  end_html();

  return r;
}
