#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <vga.h>

#define BIT(x) (1 << (x))
/* field width of the first field for the print_modeinfo function */
#define FW 27

char usage[] = "usage: %s [-options] [modename]
Options are:

-a, --all
     Print mode information for all available video modes.
-v, --available
     Print the names of all available video modes.

modename
     Print mode information for 'modename'.
";

/* returns bits per pixel */
int colorbits(colors)
     int colors;   /* number of colors mode has */
{
   switch (colors) {
      case 2: 		return 1;
      case 16:		return 4;
      case 256:		return 8;
      case 32768:	return 15;
      case 65536:	return 16;
      case 256 * 65536: return 24;
   } 
}

/* print modeinfo, returns 0 if successful, 1 if mode not found */
int
print_modeinfo(mode)
     int mode;
{
  vga_modeinfo *info;
  
  if (! vga_hasmode(mode)) 
    return 1;
  info = vga_getmodeinfo(mode);
  if (info == NULL)
    return 1;
  
  printf("Info for mode %s\n", mode == 0 ? "TEXT" : vga_getmodename(mode));
  printf("--------------------------------------\n");
  printf("%-*s - %d\n", FW, "width", info->width);
  printf("%-*s - %d\n", FW, "height", info->height);
  printf("%-*s - %d\n", FW, "bytesperpixel", info->bytesperpixel);
  printf("%-*s - %d\n", FW, "bitsperpixel", colorbits(info->colors));
  printf("%-*s - %d\n", FW, "linewidth", info->linewidth);
  printf("%-*s - %d\n", FW, "colors", info->colors);
  printf("%-*s - %d\n", FW, "maxlogicalwidth", info->maxlogicalwidth);
  printf("%-*s - %d\n", FW, "startaddressrange", info->startaddressrange); 
  printf("%-*s - %d\n", FW, "maxpixels", info->maxpixels);
  printf("haveblit\n");
  printf("%-*s - %s\n", FW, "  Bitblit", 
         (info->haveblit & BIT(0)) ? "yes" : "no");
  printf("%-*s - %s\n", FW, "  Fillblit",  
         (info->haveblit & BIT(1)) ? "yes" : "no");
  printf("%-*s - %s\n", FW, "  Imageblit", 
         (info->haveblit & BIT(2)) ? "yes" : "no");
  printf("flags\n");
  printf("%-*s - %s\n", FW, "  setreadpage/setwritpage",
         (info->flags & BIT(0)) ? "available" : "not available");
  printf("%-*s - %s\n", FW, "  interlaced mode", 
         (info->flags & BIT(1)) ? "yes" : "no");
  printf("%-*s - %s\n", FW, "  mode-X", 
         (info->flags & BIT(2)) ? "yes" : "no");
  printf("%-*s - %s\n", FW, "  Dynamically loaded",
         (info->flags & BIT(3)) ? "yes" : "no");
  printf("%-*s - %s\n", FW, "  linear addressing",
         (info->flags & BIT(4)) ? "available" : "not available");
  printf("%-*s - %s\n", FW, "  linear addressing",
         (info->flags & BIT(5)) ? "enabled" : "not enabled");
  if (info->flags & BIT(6)) {   /* extra-mode-info-available flag */
     printf("%-*s - %d\n", FW, "chiptype", info->chiptype);
     printf("%-*s - %d\n", FW, "memory", info->memory);
     printf("%-*s - %d\n", FW, "linewidth_unit", info->linewidth_unit);
     printf("%-*s - %d\n", FW, "aperture_size", info->aperture_size);
  }
  printf("\n");

  return 0;
}

void print_available_modes()
{
  int mode, w = 0;

  vga_disabledriverreport();
  printf("Available video modes are:\n\n");
  printf("%-15s", "TEXT");  /* vga_getmodename doesn't work for mode 0 */
  w++;
  for (mode = 1; mode <= GLASTMODE; mode++) {
     if (vga_hasmode(mode)) {
        printf("%-15s", vga_getmodename(mode));
        if (++w == 4) {
           w = 0;
           printf("\n");
        }
     }  
  }
  printf("\n");
}  
     
int main(argc, argv)
     int argc;
     char **argv;
{
   int mode, opt, opt_index;
   char modename[15];
   struct option opts[] = {
     {"all", 0, NULL, 'a'},       /* display modeinfo for all available modes */
     {"available", 0, NULL, 'v'}, /* display the names of all available modes */
     {0, 0, 0, 0}
   };

   if (argc == 1) {
      fprintf(stderr, usage, argv[0]);
      exit(1);
   }
   
   while ((opt = getopt_long(argc, argv, "av", opts, &opt_index)) != EOF) {
      switch (opt) {
      case 'a':  /* print mode info for all available modes */
         for (mode = 0; mode <= GLASTMODE; mode++) {
           print_modeinfo(mode);
         }
         exit(0);
      case 'v':    /* print names of available modes */
         print_available_modes();
         exit(0);
      case '?':
         fprintf(stderr, usage, argv[0]);
         exit(1);
      }  /* switch */
   }  /* while */


   if (argc > 1) {   /* print mode info for a single mode */
      if (strcmp(argv[1], "TEXT") == 0)   /* handle TEXT mode */
         mode = 0;
      else { 
         if (argv[1][0] != 'G') 
            sprintf(modename, "G%s", argv[1]);
         else
            strcpy(modename, argv[1]);
         mode = vga_getmodenumber(modename);
      }
      if (print_modeinfo(mode) != 0) {
         printf("\n%s: Mode %s not available.\n", argv[0], argv[1]);
         printf("%s: Use '%s --available' to see which modes are available.\n\n",
                argv[0], argv[0]); 
         exit(1);
      }
      exit(0);
   }
}
