#include <stdio.h>
#include <string.h>

char *runkey; // key iterator
int debug = 0;

/* to_mvc:
 * transfers characters from ASCII table to "My Vigener Characters" table
 */
int to_mvc(char ch)
{
  if(ch >= 'A' && ch <= 'Z')
    return ch - 'A' + 1;
  if(ch >= 'a' && ch <= 'z')
    return ch - 'a' + 27;
  if(ch >= '0' && ch <= '9')
    return ch - '0' + 53;

  return 0;
}

/* from_mvc:
 * transfers characters from "My Vigener Characters" table to ASCII table
 */
char from_mvc(int ch)
{
  if(ch >= 1 && ch <= 26)
    return ch + 'A' - 1;
  if(ch >= 27 && ch <= 52)
    return ch + 'a' - 27;
  if(ch >= 53 && ch <= 62)
    return ch + '0' - 53;
  return 0;
}

/* mvc_round:
 * sets MVC character to valid range
 */
int mvc_round(int ch)
{
  ch--;
  while(ch < 0) ch += 62;
  while(ch > 62) ch -= 62;
  return ch + 1;
}

#define encode_real(n, z) ((n) - (z) + 1)
#define decode_real(s, z) ((s) + (z) - 1)

char encode(char n)
{
  int mvc_n; /* not encoded char */
  int mvc_s; /* encoded char */

  mvc_n = to_mvc(n);
  if(!mvc_n) return n;

  mvc_s = mvc_round(encode_real(mvc_n, *runkey));
  if(debug)
    fprintf(stderr, "key %d\t%d ('%c') -> %d (round %d)\tchar: %d '%c'\n", *runkey, mvc_n, n, mvc_n - (*runkey) + 1, mvc_s, from_mvc(mvc_s), from_mvc(mvc_s));
  runkey++; return from_mvc(mvc_s);
}

char decode(char s)
{
  int mvc_n; /* not encoded char */
  int mvc_s; /* encoded char */

  mvc_s = to_mvc(s);
  if(!mvc_s) return s;

  mvc_n = mvc_round(decode_real(mvc_s, *runkey));
  if(debug)
    fprintf(stderr, "key %d\t%d ('%c') -> %d (round %d)\tchar: %d '%c'\n", *runkey, mvc_s, s, mvc_s + (*runkey) - 1, mvc_n, from_mvc(mvc_n), from_mvc(mvc_n));
  runkey++; return from_mvc(mvc_n);
}

int translate_key(char *key)
{
  int i;
  int len = strlen(key);
  for(i = 0; i < len; i++)
    if(!(key[i] = to_mvc(key[i])))
      return i+1;
  return 0;
}

int usage_help()
{
  fprintf(stderr, "Usage: vigener [-d] [-k key] [infile] [> outfile]\n");
  fprintf(stderr, "Options:\n  -x     Switch to decoding mode\n  -k key");
  fprintf(stderr, " Allows you to set your key\n\t(Can contain only ");
  fprintf(stderr, "letters and numbers)\n -d     Enable debug mode\n\n");
  return 1;
}

int main(int argc, char *argv[])
{
  FILE *f;
  int i;
  int decoding = 0;
  char default_key[16] = "1234ViGeNeR5678";
  char *key = default_key;
  char *file = NULL;
  int ch;
  int len;

  fprintf(stderr, "Vigener square coding program\n(C) Tomi Belan 2005\n");

  for(i = 1; i < argc; i++) {
    if(strcmp(argv[i], "-x") == 0)
      decoding = 1;
    if(strcmp(argv[i], "-d") == 0)
      debug = 1;
    else if(strcmp(argv[i], "-k") == 0)
      key = argv[++i];
    else if(!file)
      file = argv[i];
    else
      return usage_help();
  }

  len = strlen(key);
  if(!!(i = translate_key(key))) {
    fprintf(stderr, "Error: key can contain only letters and numbers (char %d)\n", i);
    return 2;
  }

  if(file) {
    if((f = fopen(file, "r")) == NULL) {
      fprintf(stderr, "Error: can't open input file '%s'\n", file);
      return 3;
    }
  }
  else f = stdin;

  fprintf(stderr, decoding ? "Decoding message...\n" : "Encoding message...\n");

  for(runkey = key; (ch = fgetc(f)) != EOF; !*runkey ? runkey = key : 0)
    putchar(decoding ? decode(ch) : encode(ch));

  return 0;
}


