/*

                                   _JNJ`                        
                               .JNMH`                           
                              JMMF`       `;.                   
                            .NMM)          `MN.                 
                            MMM)            (MML                
                           (MMM`             MMML               
                     M  I  D  N  I  G  H  T    C  o  D  E       
                           (NMMF             MHNH               
                            NMML            .MMM                
                             NMML          .NMH                 
                              4MMNL       .#F                   
                               `4HNNL_   `                      
                                   `"""`                        

                          Copyright (C) 2004-2007
       "Ian (Larry) Latter" <ian dot latter at midnightcode dot org>

    Midnight Code is a registered trademark of Ian Latter.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, and mirrored at the Midnight Code web
    site; as at version 2 of the License only.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
  
    You should have received a copy of the GNU General Public License
    (version 2) along with this program; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA, or see http://midnightcode.org/gplv2.txt

*/

/* midnightcode-webint.c :: Midnight Code web interface library		*/


#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <arpa/inet.h>

#include "preferences.h"
#include "midnightcode-parse.h"
#include "midnightcode-webint.h"



char midnightcode_webint_document_head[9][200] = {
  "<html>",
  "<head>",
  "  <meta http-equiv=\"Content-Type\""
  " content=\"text/html; charset=iso-8859-1\">",
  "  <meta http-equiv=\"Content-Language\" content=\"en\">",
  "  <meta name=\"Author\" content=\"Midnight Code\">",
  "  <link rel=\"stylesheet\" type=\"text/css\"" \
  " href=\"/static/style.css\" media=\"screen\">",
  "  <title>%s</title>",
  "</head>",
  "<body>"
};

char midnightcode_webint_document_tail[2][200] = {
  "</body>",
  "</html>"
};

char midnightcode_webint_form_head[1][200] = {
  "<form method=\"post\" name=\"myform\">"
};

char midnightcode_webint_form_tail[1][200] = {
  "</form>"
};

char midnightcode_webint_layout_head[29][200] = {
  "<center>",
  "<table border=\"0\" width=\"800\" cellpadding=\"0\" cellspacing=\"0\">",
  "<tr>",
  "  <td width=\"800\" height=\"5\">",
  "    <img src=\"/static/pixel.png\" width=\"1\" height=\"1\" border=\"0\">",
  "  </td>",
  "</tr>",
  "<tr>",
  "  <td width=\"800\" height=\"21\" background=\"/static/navtop.png\"" \
  " align=\"right\" valign=\"bottom\">",
  "    <table width=\"303\" height=\"20\" cellspacing=\"0\"" \
  " cellpadding=\"0\" border=\"0\">",
  "    <tr>",
  "      <td valign=\"middle\" background=\"/static/navbut.png\""\
  " width=\"101\" height=\"20\" class=\"toptxtoff\"><a" \
  " href=\"/gplv2.txt\" class=\"toptxtoff\">GPL</a></td>",
  "      <td valign=\"middle\" background=\"/static/navbut.png\"" \
  " width=\"101\" height=\"20\" class=\"toptxtoff\"><a" \
  " href=\"/about/\" class=\"toptxtoff\">About</a></td>",
  "      <td valign=\"middle\" background=\"/static/navbut.png\"" \
  " width=\"101\" height=\"20\" class=\"toptxton\"><a" \
  " href=\"/\" class=\"toptxton\">Home</a></td>",
  "    </tr>",
  "    </table>",
  "  </td>",
  "</tr>",
  "<tr>",
  "  <td width=\"800\" height=\"94\" background=\"/static/see-the-code.png\">",
  "    <img src=\"/static/pixel.png\" width=\"1\" height=\"1\" border=\"0\">",
  "  </td>",
  "</tr>",
  "<tr>",
  "  <td width=\"800\" valign=\"top\">",
  "    <table width=\"800\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">",
  "    <tr>",
  "      <td width=\"150\" valign=\"top\">",
  "        <table width=\"150\" cellspacing=\"0\"" \
  " cellpadding=\"0\" border=\"0\">"
};

char midnightcode_webint_layout_head_sub[10][200] = {
  "        <tr>",
  "          <td width=\"150\" colspan=\"2\">",
  "            <img src=\"/static/pixel.png\" width=\"1\"" \
  " height=\"150\" border=\"0\">",
  "          </td>",
  "        </tr>",
  "        </table>",
  "      </td>",
  "      <td width=\"20\"><img src=\"/static/pixel.png\" width=\"1\"" \
  " height=\"1\" border=\"0\"></td>",
  "      <td width=\"630\" valign=\"top\">",
  "        <br>"
};

char midnightcode_webint_layout_tail[23][200] = {
  "        <br><br>",
  "      </td>",
  "    </tr>",
  "    </table>",
  "  </td>",
  "</tr>",
  "<tr>",
  "  <td width=\"800\" height=\"7\" background=\"/static/foot.png\">",
  "    <img src=\"/static/pixel.png\" width=\"1\" height=\"1\" border=\"0\">",
  "  </td>",
  "</tr>",
  "<tr>",
  "  <td width=\"800\" height=\"30\">",
  "    <table width=\"800\" height=\"30\" cellspacing=\"0\"" \
  " cellpadding=\"0\" border=\"0\">",
  "    <tr>",
  "      <td width=\"300\" height=\"30\" align=\"left\"" \
  " class=\"foot\">&copy; 2004-2007 Ian Latter, All rights reserved.<br>" \
  " Midnight Code is a registered trademark of Ian Latter</td>",
  "      <td width=\"200\" height=\"30\" align=\"center\"" \
  " class=\"foot\"> &nbsp; </td>",
  "      <td width=\"300\" height=\"30\" align=\"right\"" \
  " class=\"foot\">All Midnight Code source code is distributed under<br>" \
  " version 2 of the Gnu General Public License (GPL).</td>",
  "    </tr>",
  "    </table>",
  "  </td>",
  "</tr>",
  "</table>"
};

char midnightcode_webint_menu_item[4][200] = {
  "        <tr>",
  "          <td width=\"145\" height=\"23\" class=\"subtxt%s\">" \
  "&nbsp;&nbsp;" \
  "<img src=\"/static/%s.png\" width=\"9\" height=\"9\" border=\"0\">" \
  "&nbsp;&nbsp;" \
  "<a href=\"%s\" class=\"subtxt%s\">%s</a></td>",
  "          <td width=\"5\" height=\"23\" class=\"subind%s\">" \
  "<img src=\"/static/pixel.png\" width=\"1\" height=\"1\" border=\"0\"></td>",
  "        </tr>"
};

char midnightcode_webint_menu_separator[3][200] = {
  "        <tr>",
  "          <td width=\"150\" height=\"1\" colspan=\"2\" class=\"subsep\">" \
  "<img src=\"/static/pixel.png\" width=\"1\" height=\"1\" border=\"0\"></td>",
  "        </tr>"
};

char midnightcode_webint_content_head[7][200] = {
  "        <table border=\"0\" width=\"600\" cellpadding=\"0\"" \
  " cellspacing=\"0\">",
  "        <tr>",
  "          <td align=\"right\" valign=\"top\" class=\"ttl\"" \
  " width=\"600\" colspan=\"2\">%s</td>",
  "        </tr>",
  "        <tr>",
  "          <td align=\"left\" valign=\"top\" class=\"subttl\"" \
  " colspan=\"2\">%s</td>",
  "        </tr>"
};

char midnightcode_webint_content_item[9][200] = {
  "        <tr>",
  "          <td align=\"left\" valign=\"top\" class=\"lbl\"" \
  " colspan=\"2\"><br>%s%s</td>",
  "        </tr>",
  "        <tr>",
  "          <td class=\"txt\" width=\"20\"><img src=\"/static/pixel.png\"" \
  " width=\"20\" height=\"1\" border=\"0\"></td>",
  "          <td align=\"left\" valign=\"top\" class=\"txt\" width=\"580\">",
  "%s",
  "          </td>",
  "        </tr>"
};

char midnightcode_webint_content_tail[1][200] = {
  "        </table>"
};



int
midnightcode_webint_membrane(int direction,
                     char ** buffer, int * buffer_size,
                     struct midnightcode_webint_message_t ** message_p) {
  struct midnightcode_webint_message_t * message;
  char * buffer_ptr;
  char query[5];
  char type[5];
  char message_size[9];
  int * int_ptr;
  int ret_i;


  ret_i = 0;

  if(message_p == NULL)
    return -1;
  if(buffer == NULL)
    return -1;
  if(buffer_size == NULL)
    return -1;

  memset(query, 0, sizeof(query));
  memset(type, 0, sizeof(type));
  memset(message_size, 0, sizeof(message_size));

  /*

      +---+---+---+---+---+---+---+---+
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
      +---+---+---+---+---+---+---+---+
      |     Query     | Type (Unused) |
      +---+---+---+---+---+---+---+---+
      |          Message Size         |
      +---+---+---+---+---+---+---+---+
      | Message ... 
      +---+---+---+---+---+---+---+---+

  */

  switch(direction) {

    case MIDNIGHTCODE_WEBINT_MEMBRANE_ENCODE:
      message = *message_p;
      if(message == NULL)
        return -1;
      if(message->buffer_size < 0)
        return -1;
      *buffer_size = (MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE +
        message->buffer_size);
      *buffer = malloc(*buffer_size);
      if(*buffer == NULL)
        return -1;
      memset(*buffer, 0, *buffer_size);
      buffer_ptr = *buffer;
      if(midnightcode_parse_vartostr(buffer_ptr, &(message->query), 4, 0,
        MIDNIGHTCODE_PARSE_TYPE_INT))
        ret_i = -1;
      buffer_ptr = *buffer + 4;
      if(midnightcode_parse_vartostr(buffer_ptr, &(message->type), 4, 0,
        MIDNIGHTCODE_PARSE_TYPE_INT))
        ret_i = -1;
      buffer_ptr = *buffer + 8;
      if(midnightcode_parse_vartostr(buffer_ptr, &(message->buffer_size), 8, 0,
        MIDNIGHTCODE_PARSE_TYPE_INT))
        ret_i = -1;
      if(ret_i < 0) {
        free(*buffer);
        *buffer = NULL;
        return -1;
      }
      if(message->buffer_size > 0) {
        buffer_ptr = *buffer + MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE;
        memcpy(buffer_ptr, message->buffer, message->buffer_size);
      }
      break;

    case MIDNIGHTCODE_WEBINT_MEMBRANE_DECODE:
      if(buffer == NULL)
        return -1;
      if(*buffer_size < MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE)
        return -1;
      message = malloc(MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE);
      if(message == NULL)
        return -1;
      memset(message, 0, MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE);
      *message_p = message;
      buffer_ptr = *buffer;
      memcpy(query, buffer_ptr, 4);
      buffer_ptr += 4;
      memcpy(type, buffer_ptr, 4);
      buffer_ptr += 4;
      memcpy(message_size, buffer_ptr, 8);
      int_ptr = &message->query;
      if(midnightcode_parse_strtovar(int_ptr, query,
          0, 0, MIDNIGHTCODE_PARSE_TYPE_INT))
        ret_i = -1;
      if(midnightcode_parse_strtovar(&(message->type), type,
          0, 0, MIDNIGHTCODE_PARSE_TYPE_INT))
        ret_i = -1;
      if(midnightcode_parse_strtovar(&(message->buffer_size), message_size,
          0, 0, MIDNIGHTCODE_PARSE_TYPE_INT))
        ret_i = -1;
      if(message->buffer_size < 0 ||
        *buffer_size != (MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE +
        message->buffer_size))
        ret_i = -1;
      if(ret_i < 0) {
        free(message);
        *message_p = NULL;
        return -1;
      }
      if(message->buffer_size > 0) {
        message->buffer = malloc(message->buffer_size);
        if(message->buffer == NULL) {
          free(message);
          *message_p = NULL;
          return -1;
        }
        buffer_ptr = *buffer + MIDNIGHTCODE_WEBINT_MESSAGE_MINSIZE;
        memcpy(message->buffer, buffer_ptr, message->buffer_size);
      }
      break;

    default:
      return -1;
      break;
  }


  return ret_i;
}



int
midnightcode_webint_buffer(char ** buffer,
                     char * title,
                     struct midnightcode_webint_menu_t * menu_items,
                     struct midnightcode_webint_page_t * page_items,
                     struct midnightcode_webint_content_t * content_items,
                     int padding, int sections) {
  struct midnightcode_webint_menu_t * menu_item;
  struct midnightcode_webint_content_t * content_item;
  int itemn;
  int element;
  char * buffer_p;
  char * line_p;
  char * value_p;
  char pad[81];
  char empty[2];
  int buffer_size;
  int line_size;
  int buffer_offset;


  buffer_size = 131072;
  buffer_offset = 0;
  buffer_p = malloc(buffer_size);
  if(buffer_p == NULL)
    return -1;
  memset(buffer_p, 0, buffer_size);

  line_size = 512;
  line_p = malloc(line_size);
  if(line_p == NULL) {
    free(buffer_p);
    return -1;
  }
  memset(line_p, 0, line_size);

  memset(pad, 0, 81);
  if(padding < 0 || padding > 50) {
    padding = 2;
  }
  memset(pad, ' ', padding);
  *buffer = buffer_p;

  memset(empty, 0, 2);

  if(sections < MIDNIGHTCODE_WEBINT_LAYOUT_NONE ||
     sections > MIDNIGHTCODE_WEBINT_LAYOUT_ALL) {
    sections = MIDNIGHTCODE_WEBINT_LAYOUT_ALL;
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_DOCUMENT_HEAD) {
    for(element=0; element<9; element++) {
      if(title) {
        memset(line_p, 0, line_size);
        snprintf(line_p, line_size,
          "%s%s\n", pad, midnightcode_webint_document_head[element]);
        snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
          line_p, title);
      } else {
        snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
          "%s%s\n", pad, midnightcode_webint_document_head[element]);
      }
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_FORM_HEAD) {
    for(element=0; element<1; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_form_head[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_HEAD) {
    for(element=0; element<29; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_layout_head[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_MENU && menu_items != NULL) {
    for(menu_item = menu_items, itemn = 0;
      menu_item[itemn].url_s != NULL && menu_item[itemn].descript_s != NULL;
      itemn++) {
      for(element=0; element<4; element++) {
        memset(line_p, 0, line_size);
        snprintf(line_p, line_size,
          "%s%s\n", pad, midnightcode_webint_menu_item[element]);
        if(menu_item[itemn].active) {
          snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
            line_p, "on", "arrow",
            menu_item[itemn].url_s, "on", menu_item[itemn].descript_s);
        } else {
          snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
            line_p, "off", "pixel",
            menu_item[itemn].url_s, "off", menu_item[itemn].descript_s);
        }
        buffer_offset = strlen(buffer_p);
      }
      for(element=0; element<3; element++) {
        snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
          "%s%s\n", pad, midnightcode_webint_menu_separator[element]);
        buffer_offset = strlen(buffer_p);
      }
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_HEAD) {
    for(element=0; element<10; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_layout_head_sub[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_CONTENT && content_items != NULL) {
    for(element=0; element<7; element++) {
      memset(line_p, 0, line_size);
      snprintf(line_p, line_size,
        "%s%s\n", pad, midnightcode_webint_content_head[element]);
      switch(element) {

        case 2:
          value_p = empty;
          if(page_items != NULL) {
            if(page_items[0].label_s != NULL)
              value_p = page_items[0].label_s;
          }
          snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
            line_p, value_p);
          break;

        case 5:
          value_p = empty;
          if(page_items != NULL) {
            if(page_items[0].title_s != NULL)
              value_p = page_items[0].title_s;
          }
          snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
            line_p, value_p);
          break;

        default:
          snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
            "%s", line_p);
          break;
      }
      buffer_offset = strlen(buffer_p);
    }
    for(content_item = content_items, itemn = 0;
      content_item[itemn].label_s != NULL &&
      content_item[itemn].content_s != NULL; itemn++) {
      for(element=0; element<9; element++) {
        memset(line_p, 0, line_size);
        snprintf(line_p, line_size,
          "%s%s\n", pad, midnightcode_webint_content_item[element]);
        switch(element) {

          case 1:
            value_p = empty;
            if(content_item[itemn].label_s != NULL)
              value_p = content_item[itemn].label_s;
            if(strlen(value_p)) {
              snprintf((buffer_p + buffer_offset),
                (buffer_size - buffer_offset), line_p, value_p, ":");
            } else {
              snprintf((buffer_p + buffer_offset),
                (buffer_size - buffer_offset), line_p, value_p, "");
            }
            break;

          case 6:
            value_p = empty;
            if(content_item[itemn].content_s != NULL)
              value_p = content_item[itemn].content_s;
            snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
              line_p, value_p);
            break;

          default:
            snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
              "%s", line_p);
            break;

        }
        buffer_offset = strlen(buffer_p);
      }
    }
    for(element=0; element<1; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_content_tail[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_TAIL) {
    for(element=0; element<23; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_layout_tail[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_FORM_TAIL) {
    for(element=0; element<1; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_form_tail[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(sections & MIDNIGHTCODE_WEBINT_LAYOUT_DOCUMENT_TAIL) {
    for(element=0; element<2; element++) {
      snprintf((buffer_p + buffer_offset), (buffer_size - buffer_offset),
        "%s%s\n", pad, midnightcode_webint_document_tail[element]);
      buffer_offset = strlen(buffer_p);
    }
  }

  if(line_p != NULL)
    free(line_p);

  if(buffer_offset < buffer_size) {
    buffer_p = realloc(buffer_p, buffer_offset + 1);
  }
  if(buffer_p == NULL) {
    *buffer = NULL;
    return -1;
  }
  *buffer = buffer_p;


  return buffer_offset;
}



void
midnightcode_webint(char * title,
                     struct midnightcode_webint_menu_t * menu_items,
                     struct midnightcode_webint_page_t * page_items,
                     struct midnightcode_webint_content_t * content_items,
                     int padding, int sections) {
  char *buffer;
  int buffer_size;


  buffer_size = midnightcode_webint_buffer(&buffer,
    title, menu_items, page_items, content_items, padding, sections);
  if(buffer == NULL)
    return;
  if(buffer_size <= 0) {
    if(buffer)
      free(buffer);
    return;
  }

  fprintf(stdout, "%s", buffer);
  fflush(stdout);
  free(buffer);


  return;
}

