
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/param.h>

#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <paper.h>


/* needed for GNU/Hurd */
#ifndef MAXPATHLEN
#define MAXPATHLEN 4096
#endif

static void usage(const char* name)
{
    fprintf(stderr,
	"usage: %s [ [ -p ] papername | -d | -a ] [ -z ] [ -n | -N ] [ -s | -w | -h ] [ -c | -m | -i ]\n",
	    name);
    exit(1);
}

#define OPT_NAME	1
#define OPT_UPPERNAME	2
#define OPT_WIDTH	4
#define OPT_HEIGHT      8
#define OPT_CM         16
#define OPT_MM         32
#define OPT_INCH       64
#define OPT_CONTINUE  128

#define OPT_UNIT      (OPT_CM | OPT_MM | OPT_INCH)

#define INCHxCM 2.54

static void printinfo(const struct paper* paper, int options)
{
    int pr = 0;

    if ((options & ~(OPT_CONTINUE)) == 0) {
	options = OPT_NAME;
    }

    if (options & OPT_NAME) {
	printf("%s", papername(paper));
	pr = 1;
    } else if (options & OPT_UPPERNAME) {
	if (islower(*papername(paper))) {
	    printf("%c%s", toupper(*papername(paper)), papername(paper) + 1);
	} else {
	    printf("%s", papername(paper));
	}
	pr = 1;
    }

    if (options & OPT_WIDTH) {
	if (pr) putchar(' ');
        if (options & OPT_CM)
          printf("%g cm", paperpswidth(paper) / 72.0 * INCHxCM );
	else if (options & OPT_MM)
          printf("%g mm", paperpswidth(paper) / 72.0 * 10 * INCHxCM );
	else if (options & OPT_INCH)
          printf("%g\"", paperpswidth(paper) / 72.0 );
	else
          printf("%g", paperpswidth(paper) );
	pr = 1;
    }
    if (options & OPT_HEIGHT) {
	if (pr) putchar(' ');
        if (options & OPT_CM)
          printf("%g cm", paperpsheight(paper) / 72.0 * INCHxCM );
	else if (options & OPT_MM)
          printf("%g mm", paperpsheight(paper) / 72.0 * 10 * INCHxCM );
	else if (options & OPT_INCH)
          printf("%g\"", paperpsheight(paper) / 72.0 );
	else
          printf("%g", paperpsheight(paper) );
	pr = 1;
    }

    putchar('\n');
}

int main(int argc, char** argv)
{
    int c;

    int all = 0;
    const char* paper = 0;
    unsigned options = 0;

    const char* progname;

    progname = strrchr(*argv, '/');
    if (progname) {
	++progname;
    } else {
	progname = *argv;
    }

    while ((c = getopt(argc, argv, "adznNswhcmip:")) != EOF) {
	switch (c) {
	    case 'a':
		if (paper || all) {
		    usage(progname);
		}
		all = 1;
		break;

	    case 'd':
		if (paper || all) {
		    usage(progname);
		}
		paper = defaultpapername();
		break;

	    case 'p':
		if (paper || all) {
		    usage(progname);
		}
		paper = optarg;
		break;

	    case 'z':
		options |= OPT_CONTINUE;
		break;

	    case 'n':
		if (options & OPT_UPPERNAME) usage(progname);
		options |= OPT_NAME;
		break;

	    case 'N':
		if (options & OPT_NAME) usage(progname);
		options |= OPT_UPPERNAME;
		break;

	    case 's':
		options |= OPT_WIDTH | OPT_HEIGHT;
		break;

	    case 'w':
		options |= OPT_WIDTH;
		break;

	    case 'h':
		options |= OPT_HEIGHT;
		break;

	    case 'c':
	        if (options & OPT_UNIT) usage(progname);
		options |= OPT_CM;
		break;

	    case 'm':
	        if (options & OPT_UNIT) usage(progname);
		options |= OPT_MM;
		break;

	    case 'i':
	        if (options & OPT_UNIT) usage(progname);
		options |= OPT_INCH;
		break;

	    default:
		usage(progname);
	}
    }

    if (optind < argc - 1 || (paper && optind != argc)) {
	usage(progname);
    } else if (optind != argc) {
	paper = argv[optind];
    }

    paperinit();

    if (all) {
 	const struct paper* papers;

	for (papers = paperfirst(); papers; papers = papernext(papers)) {
	    printinfo(papers, options);
	}
    } else {
        const struct paper* syspaper;

        if (!paper) paper = systempapername();
        if (!paper) paper = defaultpapername();
	if (!paper) {
	    char errmsg[2 * MAXPATHLEN + 64];

	    sprintf(errmsg, "%s: cannot get paper size from %s",
		progname, systempapersizefile());

	    if (errno) {
		perror(errmsg);
	    } else {
	        fputs(errmsg, stderr);
	    }

	    paperdone();

	    exit(3);
	}

        syspaper = paperinfo(paper);

        if (syspaper) {
            printinfo(syspaper, options);
        } else {
	    fprintf(stderr, "%s: unknown paper `%s'\n", progname, paper);
	    if (options & OPT_CONTINUE) {
		puts(paper);
	    }

	    paperdone();

	    exit(2);
        }
    }

    paperdone();

    return 0;
}

