#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "ezxml.h"
#include "api_key.h" /* NOT PUBLIC */

#ifndef TRUE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif

static char PROGNAME[128] = { 'b', 'm', 'n', 'a', '\0' };

#define TAGFILE "/work/www.gtoal.com/flickr/tags.csv"

void
gettags (char *s)
{
  char *command = malloc (strlen (s) + 128);
  char *sep;
  //fprintf(stdout, "Looking for '%s'<BR>\n", s);
  if (*s == '\0') {
    return;
  }
  s = strdup(s);
  sprintf (command, "/bin/cat %s", TAGFILE);
  for (;;)
    {
      if ((s == NULL) || (*s == '\0'))
	break;
      sep = strchr (s, ' ');
      if (sep != NULL)
	*sep++ = '\0';
      sprintf (command + strlen (command), "|grep -i '%s'", s);
      s = sep;
    }
  //fprintf(stdout, "Executing '%s'<BR>\n", command);
  fprintf(stdout, "<H2>BMNA tag list</H2><HR>\n");
  fflush (stdout);
  fflush (stderr);
  system (command);
  fflush (stdout);
  fflush (stderr);
}

int
htoi (int c)
{
  if (('0' <= c) && (c <= '9'))
    return c - '0';
  if (('A' <= c) && (c <= 'F'))
    return c - 'A' + 10;
  if (('a' <= c) && (c <= 'f'))
    return c - 'a' + 10;
  return 0;
}

char *replace(char *in, int from, int to)
{
    char *out = strdup(in), *s = out;
    for (;;) {
	int c = *in++;
        if (c == from) c = to;
        *out++ = c;
        if (c == '\0') break;
    }
    return s;
}

char *
cleanup (char *args)
{
  // clean up arguments.  Allow for names like "4-spotted prepona" ...
  // returns string with spaces between tags
  char *result, *s = malloc (strlen (args) + 1);
  result = s;
  for (;;)
    {
      int c = *args++;
      if (c == '\0')
	break;
      if (c == '%')
	{
	  int c1 = *args++;
	  if (c1 == '\0')
	    break;
	  int c2 = *args++;
	  if (c2 == '\0')
	    break;
	  c = (htoi (c1) << 4) | htoi (c2);
	}
      if ((('a' <= c) && (c <= 'z'))
	  || (('A' <= c) && (c <= 'Z'))
	  || c == '+' || c == ' ' || c == '-' || (('0' <= c) && (c <= '9')))
	{
	  if (c == '+')
	    {
	      if ((s != result) && (s[-1] != ' '))
		*s++ = ' ';
	    }
	  else
	    {
	      *s++ = c;
	    }
	}
      else
	{
	  if ((s != result) && (s[-1] != ' '))
	    *s++ = ' ';
	}
    }
  *s = '\0';
  while (*result == ' ') result += 1;
  for (;;) {
      int l = strlen(result);
      if ((l > 0) && (result[l-1] == ' ')) result[l-1] = '\0'; else break;
  }
  return result; // DON'T FREE IT!
}

FILE *
my_popen (char *command, char *opts)
{
  FILE *f, *log;
  log = fopen ("/tmp/bmna.log", "a");
  fprintf (log, "%s\n", command);
  fclose (log);
  f = popen (command, opts);
  return f;
}

void
myexit_ (int rc, int lineno, char *file)
{
  fflush (stdout);
  fflush (stderr);
  if (rc != 0)
    fprintf (stderr, "Exiting %s:%d, Reason %d\n", file, lineno, rc);
  fflush (stderr);
  exit (rc);
}

#define myexit(rc) myexit_(rc, __LINE__, __FILE__)

FILE *
flickr_photos_search_tags (char *ctags)
{
    char *command = malloc(strlen(ctags)+256);
    sprintf(command, 
      "wget -q -O - 'http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=%s&group_id=38155409@N00&tags=%s&sort=interestingness-desc'",
	    API_KEY, replace(ctags, ' ', ','));
  return my_popen(command, "r");
}

FILE *
flickr_tags (const char *photoid)
{
  static char command[1024];
  sprintf (command,
	   "wget -q -O - 'http://api.flickr.com/services/rest/?method=flickr.tags.getListPhoto&api_key=%s&photo_id=%s'",
	   API_KEY, photoid);
  return my_popen (command, "r");
}

static int nextfreekey = 0;
static char *canonkey[1024];
static char *fullkey[1024];
static int count[1024];

#define SWAP(l,r) {char *tmp; int itmp; tmp = canonkey[l]; canonkey[l] = canonkey[r]; canonkey[r] = tmp; \
                                        tmp = fullkey[l]; fullkey[l] = fullkey[r]; fullkey[r] = tmp; \
                                        itmp = count[l]; count[l] = count[r]; count[r] = itmp;}

void
sort_tags_by_alpha (int l, int u)
{
  for (;;)
    {
      int l1, u1, pivot;
      if (l + 1 == u)
	{
	  if (strcmp (canonkey[l], canonkey[u]) > 0)
	    SWAP (l, u);
	  return;
	}
      if (l >= u)
	return;
      l1 = l;
      u1 = u;
      pivot = (l + u) / 2;
      for (;;)
	{
	  while (strcmp (canonkey[l], canonkey[pivot]) < 0)
	    l += 1;
	  while (strcmp (canonkey[pivot], canonkey[u]) < 0)
	    u -= 1;
	  if (l >= u)
	    break;
	  SWAP (l, u);
	  l++;
	  u--;
	}
      sort_tags_by_alpha (l1, l);
      l = u;
      u = u1;
    }
}

void
sort_tags_by_count (int l, int u)
{
  for (;;)
    {
      int l1, u1, pivot;
      if (l + 1 == u)
	{
	  if (count[l] > count[u])
	    SWAP (l, u);
	  return;
	}
      if (l >= u)
	return;
      l1 = l;
      u1 = u;
      pivot = (l + u) / 2;
      for (;;)
	{
	  while ((count[l] < count[pivot])
		 || ((count[l] == count[pivot])
		     && (strcmp (canonkey[l], canonkey[pivot]) < 0)))
	    l += 1;
	  while ((count[pivot] < count[u])
		 || ((count[pivot] == count[u])
		     && (strcmp (canonkey[pivot], canonkey[u]) < 0)))
	    u -= 1;
	  if (l >= u)
	    break;
	  SWAP (l, u);
	  l++;
	  u--;
	}
      sort_tags_by_count (l1, l);
      l = u;
      u = u1;
    }
}

void
bmna_count_tag (const char *canon, const char *fullname)	// POOR IMPLEMENTATION for now.  Quick & Dirty to get something working.
{
  int i;

  if (strcmp (canon, "bmna") == 0)
    return;
  if (strchr (canon, 0251 /* (c) */ ) != NULL)
    return;

  canonkey[nextfreekey] = strdup (canon);
  fullkey[nextfreekey] = strdup (fullname);

  for (i = 0; i <= nextfreekey; i++)
    {
      if (strcmp (canon, canonkey[i]) == 0)
	break;
    }
  if (i == nextfreekey)
    nextfreekey++;
  count[i] += 1;

}

void
print_tag_cloud (void)
{
  int i;
  fprintf (stdout, "<HR><BR><H2>Tag Cloud of associated concepts</H2>\n");
  for (i = 0; i < nextfreekey; i++)
    {
      if (count[i] > 0)
	fprintf (stdout,
		 "<font size=\"%d\"><a href=\"http://www.flickr.com/groups/butterfliesnorthamerica/pool/tags/%s\">%s</a></font>&nbsp; ",
		 count[i], canonkey[i], fullkey[i]);
    }
  fprintf (stdout, "<BR>\n");
}

void
html_display_photo (ezxml_t photo)
{
  FILE *xml_file;
  ezxml_t xml, xphoto, tags, tag;
  fprintf (stdout, "<A HREF=\"http://www.flickr.com/photos/%s/%s\">",
	   ezxml_attr (photo, "owner"), ezxml_attr (photo, "id"));
  fprintf (stdout, "<IMG BORDER=0 SRC=");
  fprintf (stdout, "\"http://farm%s.static.flickr.com/%s/%s_%s_t.jpg\"",
	   ezxml_attr (photo, "farm"),
	   ezxml_attr (photo, "server"),
	   ezxml_attr (photo, "id"), ezxml_attr (photo, "secret"));
  fprintf (stdout, " alt=\"%s\"", ezxml_attr (photo, "title"));
  fprintf (stdout, ">");
  fprintf (stdout, "</A>\n");
  xml_file = flickr_tags (ezxml_attr (photo, "id"));
  if (xml_file == NULL)
    {
      fprintf (stderr, "Tag search failed\n");
      myexit (EXIT_FAILURE);
    }

  xml = ezxml_parse_fp (xml_file);
  xphoto = ezxml_child (xml, "photo");
  tags = ezxml_child (xphoto, "tags");

  for (tag = ezxml_child (tags, "tag"); tag != NULL; tag = tag->next)
    {
      // fprintf(stdout, "%s:%s<br>\n", tag->txt, ezxml_attr(tag, "raw"));
      bmna_count_tag (tag->txt, ezxml_attr (tag, "raw"));
    }
  ezxml_free (tags);
}

int
main (int argc, char **argv)
{
  FILE *xml_file;
  ezxml_t xml;
  ezxml_t photo;
  char *args;
  char *progname;

  progname = strrchr(argv[0], '/');
  if (progname != NULL) strcpy(PROGNAME, progname+1);

  fprintf (stdout, "Content-Type: text/html\n\n");
  fprintf (stdout,
	   "<html>\n<head><title>BMNA tagger</title></head>\n<body>\n");

  args = getenv ("QUERY_STRING");
  fprintf (stdout, "<form action=\"/cgi-bin/%s\">\n", PROGNAME);
  fprintf (stdout, "Search For A Butterfly: \n");
  fprintf (stdout, "<input type=\"text\" name=\"name\"");
  if ((args != NULL) && (*args != '\0'))
    {
      if (strncmp (args, "name=", 5) != 0)
	{
	  fprintf (stdout,
		   "The only valid argument to this form is \"name=\"\n");
	  args = strdup ("name=");
	}
      args += 5;
      args = cleanup (args);
      fprintf (stdout, " value=\" %s \"", args);
    }
  fprintf (stdout, "></form>\n");

  gettags (args);
  if ((args != NULL) && (*args != '\0'))
    {
      char *tags = malloc (strlen (args) + 128);
      sprintf (tags, "bmna,%s", replace(args, ' ', ','));
      xml_file = flickr_photos_search_tags (tags);

      if (xml_file == NULL)
	{
	  fprintf (stderr, "Search failed\n");
	  myexit (EXIT_FAILURE);
	}

      fprintf(stdout, "<H2>Photos for ID help</H2>\n");
      xml = ezxml_parse_fp (xml_file);

      for (photo = ezxml_child (ezxml_child (xml, "photos"), "photo");
	   photo != NULL; photo = photo->next)
	{
	  html_display_photo (photo);
	}
      ezxml_free (xml);

      sort_tags_by_count (0, nextfreekey - 1);
      {
	int i, q1 = (nextfreekey - 1) / 4, q2 = (nextfreekey - 1) / 2, q3 =
	  ((nextfreekey - 1) * 3) / 4;
	for (i = 0; i < q1; i++)
	  count[i] = 0;
	for (i = q1; i < q2; i++)
	  count[i] = 1;
	for (i = q2; i < q3; i++)
	  count[i] = 2;
	for (i = q3; i < nextfreekey; i++)
	  count[i] = 4;
      }
      sort_tags_by_alpha (0, nextfreekey - 1);
      print_tag_cloud ();
    }

  fprintf (stdout, "</body>\n</html>\n");
  myexit (EXIT_SUCCESS);
  return (0);
}