/* AlphaTone
 * 
 * Converts a small PPM file to a PostScript file.
 * All pixels are replaced with a character of
 * varying weights. Replacement string should
 * be specified on the command line.
 *
 * Output is to STDOUT.
 *
 * bkg2
 * 10/11/00
 */

#include <stdio.h>
#include "Image.h"

#define 	MAX_JITTER	8

enum METHOD {
 GREYVAL,
 COLORVAL,
 JITTER
};

METHOD 		method_;
char 		*filename_;
char 		*phrase_;
int		plength_;
Image 		image_;
FILE		*ps_;

int		char_height_;
int		font_scale_;

void
print_help(void)
{
    printf("  param 1: PPM filename\n");
    printf("  param 2: phrase\n");
    printf("[param 3]: method: {greyval, colorval, jitter}\n");
    printf("[param 4]: output filename\n");
}

void
parse_commandline(int argc, char *argv[]) 
{
    if (argc < 3) {
	print_help();
	exit(-1);
    }
    if (argc >= 3) {
	filename_ = argv[1];
	phrase_ = argv[2];
	plength_ = strlen(phrase_);
	ps_ = stdout;
    }
    if (argc >= 4) {
	if (strcasecmp(argv[3], "greyval") == 0) {
	    method_ = GREYVAL;
	}
	else if (strcasecmp(argv[3], "colorval") == 0) {
	    method_ = COLORVAL;
	}
	else if (strcasecmp(argv[3], "jitter") == 0) {
	    method_ = JITTER;
	}
	else {
	    print_help();
	    exit(-1);
	}
    }
    if (argc >= 5) {
	ps_ = fopen(argv[4], "w");
	if (ps_ == NULL) {
	    perror("fopen (using stdout)");
	    ps_ = stdout;
	}
    }

    fprintf(stderr, "Using method %d\n", method_);
}

void
print_ps_header(void)
{
    font_scale_ = (int)((double)(72 * 11) / (double)image_.rows_);
    font_scale_ *= 3;
    char_height_ = font_scale_;
    
    fprintf(ps_, "\%%!PS-Adobe-2.0\n");
    fprintf(ps_, "%%%%BoundingBox: 0 0 2592 2592\n");
    fprintf(ps_, "%%<</PageSize [2592 2592]>> setpagedevice  %% 36in x 36in\n");
    fprintf(ps_, "%%0.2361 dup scale       %% for 8.5 x 11\n");
    fprintf(ps_, "<</PageSize [612 792]>> setpagedevice  %% 8.5in x 11in\n");
    fprintf(ps_, "1.33 1.0 scale  %% correct aspect ratio\n");
    fprintf(ps_, "0 0 moveto\n");
    fprintf(ps_, "/Courier findfont %d scalefont setfont\n", font_scale_);
    fprintf(ps_, "/charwidth (W) stringwidth pop def\n");
    fprintf(ps_, "/charheight %d def\n", char_height_);
    
    fprintf(ps_, "%%% ===== END HEADER ===== %%%\n\n");
}

void
print_ps_footer(void)
{

    fprintf(ps_, "%%% ===== BEGIN FOOTER ===== %%%\n\n");
    fprintf(ps_, "showpage\n");
}

void
alpha_tone(void)
{
    /* Need to get code for HSV conversion */

    int j;
    int c;  // the character
    pixel p;
    float value;
    float r, g, b;
    int phrase_idx = 0;
    int invy;

    /*
     * Output pre-PS stuff
     */
    //fprintf(ps_, "\n/%s {\n", "alpha");  // define a function

    for (int y = 0; y < image_.rows_; y++) {
	invy = image_.rows_ - y - 1;
	//for (int y = image_.rows_ - 1; y >= 0; y--) {
	fprintf(ps_, "\n0 %d moveto\n", (int)(y * char_height_));
	for (int x = 0; x < image_.cols_; x++) {
	    /* Get colors and grey value */
	    p = image_.pixels_[invy][x];
	    r = PPM_GETR(p) / 255.0;
	    g = PPM_GETG(p) / 255.0;
	    b = PPM_GETB(p) / 255.0;
	    value = (r + g + b) / 3.0;

	    /* Get smear quantization */
	    int smear = (int)((1 - value) * (float)MAX_JITTER);
	    //fprintf(stderr, "smear=%d\n", smear);

	    /* Get character */
	    c = (int)((char)phrase_[phrase_idx++ % plength_]);

	    switch (method_) {
	    case GREYVAL:
		fprintf(ps_, "%f setgray (%c) show ", value, c);
		break;
	    case COLORVAL:
		fprintf(ps_, "%f %f %f setrgbcolor (%c) show ", r, g, b, c);
		break;
	    case JITTER:
		if (smear > 0) {
		    fprintf(ps_, "currentpoint (%c) show moveto currentpoint\n", c);  // main character
		    for (j = 0; j < smear; j++) {
			fprintf(ps_, "  rand 3 mod 1 sub rand 3 mod 1 sub rmoveto (%c) show charwidth neg 0 rmoveto\n", c);
		    }
		    fprintf(ps_, "  exch charwidth add exch moveto\n");
		}
		else {
		    fprintf(ps_, "(%c) show\n", c);
		}
		break;
	    } /* switch */
	} /* for x */
    } /* for y */

    /*
     * Output post-PS stuff
     */
    //fprintf(ps_, "\n} def\n");  // close function
}

int
main(int argc, char *argv[]) 
{
    /*
     * Get command line stuff
     */
    parse_commandline(argc, argv);

    /*
     * Load image
     */
    if (!image_.read_ppm(filename_)) {
	fprintf(stderr, "Error reading %s.\n", filename_);
	exit(-1);
    }

    /*
     * Create beginning of PostScript document
     */
    print_ps_header();
    
    /*
     * Do it!
     */
    alpha_tone();

    /* 
     * Create end of PostScript document
     */
    print_ps_footer();

    /*
     * Close output file if opened
     */
    if (ps_ != stdout) {
	fclose(ps_);
    }
    
}

