/*
 * Copyright (c) 1987, 1988, 1989, 1990, 1991 Stanford University
 * Copyright (c) 1991 Silicon Graphics, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Stanford and Silicon Graphics may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Stanford and Silicon Graphics.
 * 
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 *
 * IN NO EVENT SHALL STANFORD OR SILICON GRAPHICS BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 */

/*
 * PSFont - use PostScript font metrics
 */

#include <InterViews/psfont.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Users can also override this by setting the PSFONTDIR environment variable.
 */
#ifndef ps_metrics_dir
#define ps_metrics_dir "/usr/lib/ps"
#endif

class PSFontImpl {
private:
    friend class PSFont;

    char* name;
    char* encoding;
    Coord size;
    Coord width;
    Coord *widths;

    static char* psfile(const char* name);
};

PSFont::PSFont(
    const char* psname, Coord size, const char* name, float scale
) : Font(name, scale) {
    PSFontImpl* p = new PSFontImpl;
    impl_ = p;
    p->name = nil;
    p->encoding = nil;
    p->size = size;
    p->width = 0;
    p->widths = nil;
    char* metrics_file = PSFontImpl::psfile(psname);
    FILE* file = fopen(metrics_file, "r");
    if (file != nil) {
	p->name = new char[256];
	p->encoding = new char[256];

	char line[256];
	int c, w, h, x1, x2;
	while (fgets(line, 255, file) != NULL) {
	    if (sscanf(line, "FontBBox %d %d %d %d", &x1, &c, &x2, &c) == 4) {
		p->width = float(x2 - x1) / 1000 * size;
	    } else if (sscanf(line, "FontName %[a-zA-Z-]", p->name) == 1) {
		;
	    } else if (sscanf(line, "EncodingScheme %s", p->encoding) == 1) {
		;
	    } else if (sscanf(line, "CharWidth %d %d", &w, &h) == 2) {
		break;
	    } else if (sscanf(line, "StartCharMetrics %d ", &c) == 1) {
		p->widths = new Coord[ (c > 255) ? 255 * 255 : 255];
	    } else if (sscanf(line, "C %d ; WX %d ;", &c, &w) == 2) {
		if (c != -1) {
		    p->widths[c] = float(w) / 1000 * p->size;
		}
	    }
	}
	fclose(file);
    }
    delete metrics_file;
}

PSFont::~PSFont() {
    delete impl_->name;
    delete impl_->encoding;
    delete impl_->widths;
    delete impl_;
}

const char* PSFont::name() const { return impl_->name; }
const char* PSFont::encoding() const { return impl_->encoding; }
Coord PSFont::size() const { return impl_->size; }

void PSFont::font_bbox(FontBoundingBox& b) const {
    Font::font_bbox(b);
    if (impl_->width != b.width_) {
	b.width_ = impl_->width;
	b.right_bearing_ += impl_->width - b.width_;
    }
}

void PSFont::char_bbox(long c, FontBoundingBox& b) const {
    Font::char_bbox(c, b);
    Coord w = impl_->widths ? impl_->widths[c] : impl_->width;
    if (w != b.width_) {
	b.width_ = w;
	b.right_bearing_ += w - b.width_;
    }
}

void PSFont::string_bbox(const char* s, int n, FontBoundingBox& b) const {
    Font::string_bbox(s, n, b);
}

Coord PSFont::width(long c) const {
    return impl_->widths ? impl_->widths[c] : impl_->width;
}

Coord PSFont::width(const char* s, int n) const {
    return Font::width(s, n);
}

boolean PSFont::exists(const char* psname) {
    char* metrics_file = PSFontImpl::psfile(psname);
    FILE* f = fopen(metrics_file, "r");
    delete metrics_file;
    if (f == nil) {
	return false;
    }
    fclose(f);
    return true;
}

char* PSFontImpl::psfile(const char* name) {
    const char* dir = getenv("PSFONTDIR");
    if (dir == nil) {
	dir = ps_metrics_dir;
    }
    char* metrics_file = new char[
	strlen(dir) + strlen("/") + strlen(name) + strlen(".afm") + 1
    ];
    sprintf(metrics_file, "%s/%s.afm", dir, name);
    return metrics_file;
}
