/*
 *  MS Windows - dependent code
 */

#include <Interviews\bitmap.h>
#include <Interviews\paint.h>
#include <Interviews\defs.h>
#include <Interviews\X11\worldrep.h>
#include <InterViews\X11\palette.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <dir.h>
#include <stdio.h>
#include <fstream.h>

char* Stock_Fonts[] = { { "ANSI_FIXED_FONT" },
			{ "ANSI_VAR_FONT" },
			{ "DEVICE_DEFAULT_FONT" },
			{ "OEM_FIXED_FONT" },
			{ "SYSTEM_FONT" } };

/*
 ********************  class Brush  *************************
 */

BrushRep::BrushRep (int* pattern, int c, int width) {
    count = c;
    if (c != 0) {
	info = new int[count];
	for (int i = 0; i < count; ++i) {
	    *(info + i) = pattern[i];
	}
    }
}

BrushRep::~BrushRep () {
    if ((info != nil) && (count != 0)) {
	delete info;
    }
}

/*
 **************************  class Color  *********************************
 */

boolean ColorRep::ScanColorFile (
    const char* name, ColorIntensity& r, ColorIntensity& g, ColorIntensity& b
) {
    char *file, *ptr;
    char color[30];
    char buf[50];
    FILE* source;
    boolean result = false;

    r = 0; g = 0; b = 0;
    if ((file = searchpath("colors.ali")) == 0) {
	return result;
    }
    source = fopen(file, "r");

/*
 * Der Farbstring wird in einen String, wie ihn "colors.ali" verwendet,
 * umgwandelt.
 */

    for (int j = 0, i = 0; i < strlen(name); i++) {
	if (name[i] != ' ') {
	    color[j++] = tolower(name[i]);
	}
    }
    color[j] = ' ';
    color[j+1] = '\0';

/*
 * "Colors.ali" wird auf Vorhandensein des Strings berprft.
 * Erfolg wird dann gemeldet, wenn der String in einer Zeile
 * zu finden ist, und wenn er an der ersten Position der Zeile
 * beginnt (d.h. er ist nicht Teilstring einer anderen Farbe, wie
 * z.B. "blue" von "mediumblue").
 */

    while (!feof(source)) {
	fgets(buf, 50, source);
	if ((ptr = strstr(buf, color)) != NULL && ptr == buf) {
	    char* tmp;
	    tmp = strtok(buf, " ");
	    tmp = strtok(NULL, " ");
	    r = atoi(tmp);
	    tmp = strtok(NULL, " ");
	    g = atoi(tmp);
	    tmp = strtok(NULL, " \n\0");
	    b = atoi(tmp);
	    result = true;
	    break;
	}
    }
    fclose(source);
    return result;
}

inline unsigned MakeXIntensity (unsigned i) {
    return ((i << 8) + i);
}

inline unsigned MakeWinIntensity (unsigned i) {
    return (i >> 8);
}

ColorRep::ColorRep (
    ColorIntensity r, ColorIntensity g, ColorIntensity b
) {
    red   = MakeWinIntensity(r);
    green = MakeWinIntensity(g);
    blue  = MakeWinIntensity(b);
    pixel = _palette->SetEntry(red, green, blue);
}

ColorRep::ColorRep (
    long p, ColorIntensity& r, ColorIntensity& g, ColorIntensity& b
) {
    r = GetRValue(p);
    g = GetGValue(p);
    b = GetBValue(p);
    pixel = _palette->SetEntry(r, g, b);
    red = r; green = g; blue = b;
    r = MakeXIntensity(red);
    g = MakeXIntensity(green);
    b = MakeXIntensity(blue);
}

ColorRep::ColorRep (
    const char* name, ColorIntensity& r, ColorIntensity& g, ColorIntensity& b
) {
    if (ScanColorFile(name, red, green, blue)) {
	pixel = _palette->SetEntry(red, green, blue);
    } else {
	pixel = 0;
    }
    r = MakeXIntensity(red);
    g = MakeXIntensity(green);
    b = MakeXIntensity(blue);
}

ColorRep::~ColorRep () {
    /*** aus Palette entfernen ***/
}

int ColorRep::GetPixel () {
    return pixel;
}

void ColorRep::GetIntensities (
     ColorIntensity& r, ColorIntensity& g, ColorIntensity& b
) {
    r = red;
    g = green;
    b = blue;
}

/*
 ******************************  class Font  ***********************
 */

FontRep::FontRep () {
    height = 0;
    id = nil;
}

FontRep::~FontRep() {
}

boolean FontRep::IsStockFont (const char* f) {
    char tmp[FONTSTRINGSIZE];
    int stock_font = -1;

    strcpy(name, f);
    strcpy(tmp, name);
    if (strcmpi(tmp, Stock_Fonts[0]) == 0) {
	stock_font = ANSI_FIXED_FONT;
    } else if (strcmpi(tmp, Stock_Fonts[1]) == 0) {
	stock_font = ANSI_VAR_FONT;
    } else if (strcmpi(tmp, Stock_Fonts[2]) == 0) {
	stock_font = DEVICE_DEFAULT_FONT;
    } else if (strcmpi(tmp, Stock_Fonts[3]) == 0) {
	stock_font = OEM_FIXED_FONT;
    } else if (strcmpi(tmp, Stock_Fonts[4]) == 0) {
	stock_font = SYSTEM_FONT;
    }
    if (stock_font != -1) {
	id = (void*)GetStockObject(stock_font);
	return true;
    }
    return false;
}

void Font::GetFontByName (const char* name) {
    if (!rep->IsStockFont(name)) {
	rep->MakeNewFont(name);
    }
}

Font::~Font () {
    Unref(rep);
}

void FontRep::GetFontString (char** fontstring) {
    FILE* source;
    char buf[FONTSTRINGSIZE];
    char str[FONTSTRINGSIZE];
    char *file, *ptr;
    int num_substrs = 0;
    char* substrs[13];
    boolean result;

    (*fontstring)[0] = '\0';

    //
    //   Der String mit den Wildcards wird in diejenigen Teilstrings
    //   aufgespalten, die im eigentlichen Fontstring enthalten sein mssen.
    //

    strcpy(str, name);
    if ((substrs[num_substrs] = strtok(str, "*\0")) != NULL) {
	num_substrs++;
    }
    while ((substrs[num_substrs] = strtok(NULL, "*\0")) != NULL) {
	num_substrs++;
    }

    //
    // Es wird Zeile fr Zeile der Fontdatenbank gelesen und auf Vorkommen
    // der Teilstrings untersucht. Die erste Zeile, die alle Teilstrings
    // enthlt, ist der eigentliche Fontstring.
    //


    file = searchpath("fonts.dir");
    if (file == 0) {
        return;
    }

    source = fopen(file, "r");

    while (!feof(source)) {
	fgets(buf, FONTSTRINGSIZE, source);
	result = true;
	ptr = buf;
	for (int i = 0; i < num_substrs; i++) {
	    if ((ptr = strstr(ptr, substrs[i])) == NULL) {
		result = false;
		break;
	    }
	    ptr++;
	}
	if (result) {
	    strcpy((*fontstring), buf);
	    break;
	}
    }
    fclose(source);
}

unsigned char FontRep::GetLogFontCharSet () {
    char tmp[LF_FACESIZE];
    BYTE char_set = ANSI_CHARSET;

    strcpy(tmp, typeface);
    if (strcmpi(typeface, "terminal") == 0 ||
	    strcmpi(typeface, "modern") == 0 ||
	    strcmpi(typeface, "roman") == 0 ||
	    strcmpi(typeface, "script") == 0 ) {
	    char_set = OEM_CHARSET;
    }
    return char_set;
}


void FontRep::GetLogFontTypeFace (char* ptr) {
    ifstream source;
    char buf[128];
    char *p, *file;

    strcpy(typeface, ptr);

    if ((file = searchpath("fonts.tfc")) == 0) {
        return;
    }
    source.open(file, ios::nocreate);
    while (!source.eof()) {
	source.getline(buf, 128);
	if (strstr(buf, typeface)) {
	    p = strchr(buf, '@') + 1;
	    strcpy(typeface, p);
	    source.close();
	    return;
	}
    }
    source.close();
}

boolean FontRep::GetLogFont (void* logfont) {
    char* buffer = new char[FONTSTRINGSIZE];
    char* ptr;
    int value;
    LPLOGFONT lf = (LPLOGFONT)logfont;

    strcpy(buffer, name);
    GetFontString(&buffer);
    if (buffer[0] == '\0') {
	return false;
    }

						/* Foundry */
    if ((ptr = strtok(buffer, "-")) != NULL);

						/* Font Family */

    if ((ptr = strtok(NULL, "-")) != NULL) {
	GetLogFontTypeFace(ptr);
	for (int i = 0; i <= strlen(typeface); i++) {
	    lf->lfFaceName[i] = typeface[i];
	}
    }
    lf->lfCharSet = GetLogFontCharSet();

						/* Weight */
    lf->lfWeight = 400;
    if ((ptr = strtok(NULL, "-")) != NULL) {
	if (!strcmpi(ptr, "bold")) {
	    lf->lfWeight = 700;
	}
    }

						/* Slant */
    lf->lfItalic = 0;
    if ((ptr = strtok(NULL, "-")) != NULL) {
	if (!strcmpi(ptr, "i") || !strcmpi(ptr, "o")) {
	    lf->lfItalic = 1;
	}
    }

						/* Set Width */
    if ((ptr = strtok(NULL, "-")) != NULL);


						/* Pixels */
    lf->lfHeight = 0;
    if (((ptr = strtok(NULL, "-")) != NULL) && (value = atoi(ptr))) {
	lf->lfHeight = value;
    }

						/* Points */
    if ((ptr = strtok(NULL, "-")) != NULL);

						/* Hor. Resolution */
    if ((ptr = strtok(NULL, "-")) != NULL);

						/* Vert. Resolution */
    if ((ptr = strtok(NULL, "-")) != NULL);

						/* Spacing */
    lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    if ((ptr = strtok(NULL, "-")) != NULL) {
	if (!strcmpi(ptr, "m")) {
	    lf->lfPitchAndFamily |= FIXED_PITCH;
	}
	if (!strcmpi(ptr, "p")) {
	    lf->lfPitchAndFamily |= VARIABLE_PITCH;
	}
    }

						/* Width */
    lf->lfWidth = 0;
    if ((ptr = strtok(NULL, "-")) != NULL);


						/* Character Set */
    if ((ptr = strtok(NULL, "-\n")) != NULL);

						/* Defaults */
    lf->lfEscapement = 0;
    lf->lfOrientation = 0;
    lf->lfUnderline = 0;
    lf->lfStrikeOut = 0;
    lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
    lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf->lfQuality = DEFAULT_QUALITY;

    delete buffer;
    return true;
}

void FontRep::GetFontAlias (const char* f) {
    ifstream source;
    char buf[FONTSTRINGSIZE];
    char *ptr, *file;

    if ((file = searchpath("fonts.ali")) == 0) {
        return;
    }
    source.open(file, ios::nocreate);
    while (!source.eof()) {
	source.getline(buf, FONTSTRINGSIZE);
	if (strstr(buf, f)) {
	    ptr = &buf[strlen(f)];
	    while (*ptr == ' ') {
		ptr++;
	    }
	    strcpy(name, ptr);
	    return;
	}
    }
    source.close();
}

boolean FontRep::GetFontResource (char** font_resource) {
    ifstream source;
    char buf[128];
    char *ptr, *file;

    if ((file = searchpath("fonts.rsc")) == 0) {
        return false;
    }
    source.open(file, ios::nocreate);
    while (!source.eof()) {
	source.getline(buf, 128);
	if (strstr(buf, typeface)) {
	    ptr = strchr(buf, '@') + 1;
	    strcpy(*font_resource, ptr);
	    source.close();
	    return true;
	}
    }
    source.close();
    return false;
}

void FontRep::MakeNewFont (const char* font) {
    char* font_res = new char[13];
    LOGFONT logFont;

    id = (void*)GetStockObject(SYSTEM_FONT);
    strcpy(name, font);
    GetFontAlias(font);
    if (GetLogFont(&logFont)) {
	if (GetFontResource(&font_res)) {
	    if (AddFontResource(font_res)) {
		id = (void*)CreateFontIndirect(&logFont);
	    }
	}
    }
    delete font_res;
}

int Font::Baseline () {
    TEXTMETRIC metrics;
    int result = 0;
    HDC hDC = _world->hdc();

    HFONT holdFont = nil;
    if (Valid()) {
	holdFont = SelectObject(hDC, (HFONT)Id());
    }
    if (GetTextMetrics(hDC, (LPTEXTMETRIC)&metrics)) {
	result = metrics.tmDescent;
    }
    if (holdFont != nil) {
	SelectObject(hDC, holdFont);
    }
    return result;
}

int Font::Width (const char* s) {
    return Width(s, strlen(s));
}

int Font::Width (const char* s, int len) {
    int result, length;
    HDC hDC = _world->hdc();

    length = strlen(s);
    if (length > len) {
	length = len;
    }
    HFONT holdFont;
    holdFont = SelectObject(hDC, (HFONT)Id());
    result = GetTextExtent(hDC, (LPSTR)s, length);
    SelectObject(hDC, holdFont);
    return result;
}

int Font::Height () {
    TEXTMETRIC tm;
    int result;
    HDC hDC = _world->hdc();

    HFONT holdFont = SelectObject(hDC, (HFONT)rep->id);
    GetTextMetrics(hDC, &tm);
    result = tm.tmHeight;
    SelectObject(hDC, holdFont);
    return result;
}

int Font::Index (const char* s, int len, int offset, boolean between) {
    const char* p;
    int n, w;
    int coff, cw;
    HDC hDC = _world->hdc();

    HFONT holdFont = nil;
    holdFont = SelectObject(hDC, (HFONT)Id());

    if (offset < 0 || *s == '\0' || len == 0) {
	return 0;
    }
    w = 0;
    for (p = s, n = 0; *p != '\0' && n < len; ++p, ++n) {
	w += GetTextExtent(hDC, (LPSTR)s, n+1);
	cw = GetTextExtent(hDC, (LPSTR)p, 1);
//      w += cw;
	if (w > offset) {
	    break;
	}
	coff = offset - w;
    }
    if (between && coff > cw/2) {   // der Index, der am nchsten zu offset
      ++n;
    }

    SelectObject(hDC, holdFont);
    return min(++n, len);
}

boolean Font::FixedWidth () {
    LOGFONT logFont;

    if (Valid()) {
	GetObject((HFONT)Id(), sizeof(logFont), (LPSTR)&logFont);
	if (logFont.lfPitchAndFamily & FIXED_PITCH) {
	    return true;
	}
    }
    return false;
}

/*
 **************************  class Pattern  ***********************
 */
/*
int _xpos = 0;
int _ypos = 400;

void _DisplayBitmap(void* map, int width, int height) {

    WNDCLASS wc;

    wc.style = NULL;
    wc.lpfnWndProc = DefWindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = _world->hinstance();
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "iii";
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    HBRUSH bg = CreateSolidBrush(RGB(0, 0, 255));
    wc.hbrBackground = bg;

    RegisterClass(&wc);

    HWND hWnd = CreateWindow(
		"iii",
		"Bitmap",
		WS_BORDER,
		_xpos,
		_ypos,
		50,
		80,
		NULL,
		NULL,
		_world->hinstance(),
		NULL
	   );

     _xpos += 50;
     if (_xpos >= 600) {
	 _xpos = 0;
	 _ypos += 80;
     }
     if (hWnd) {
	void* c;
	c = (void*)hWnd;
	ShowWindow((HWND)c, SW_SHOW);
    }

    HDC hDC = GetDC(hWnd);
    HDC hMemDC = CreateCompatibleDC(hDC);
    HBITMAP holdBitmap = SelectObject(hMemDC, (HBITMAP)map);
    BitBlt(hDC, 5, 5, width, height, hMemDC, 0, 0, SRCCOPY);
    SelectObject(hMemDC, holdBitamp);
    DeleteDC(hMemDC);
    ReleaseDC(hWnd, hDC);
}

*/

#ifdef bitmap_h

HBITMAP GetInvertedBitmap (Bitmap* b) {
    HBITMAP hBitmap = CreateBitmap(b->Width(), b->Height(), 1, 1, NULL);
    HDC hMemDC = CreateCompatibleDC(_world->hdc());
    HDC hMemDC1 = CreateCompatibleDC(_world->hdc());
    HBITMAP holdBitmap = SelectObject(hMemDC, (HBITMAP)b->Map());
    HBITMAP holdBitmap1 = SelectObject(hMemDC1, hBitmap);
    PatBlt(hMemDC1, 0, 0, b->Width(), b->Height(), BLACKNESS);
    BitBlt(hMemDC1, 0, 0, b->Width(), b->Height(), hMemDC, 0, 0, SRCINVERT);
    SelectObject(hMemDC1, holdBitmap1);
    SelectObject(hMemDC, holdBitmap1);
    DeleteDC(hMemDC1);
    DeleteDC(hMemDC);
    return hBitmap;
}

Pattern::Pattern (Bitmap* b) {
    HBITMAP hBitmap = GetInvertedBitmap(b);
    info = (void*)CreatePatternBrush(hBitmap);
    DeleteObject(hBitmap);
}

Pattern::Pattern (int p[patternHeight]) {
    int newp[patternHeight];
    for (int i = 0; i < patternHeight; i++) {
	newp[i] = ~p[i];
    }
    HBITMAP hBitmap = CreateBitmap(8, 8, 1, 1, (LPSTR)newp);
    info = (void*)CreatePatternBrush(hBitmap);
    DeleteObject(hBitmap);
}

Pattern::Pattern (int dither) {
    int i, seed;
    short int r[8];

    seed = dither;
    for (i = 0; i < 4; i++) {
	r[i] = (seed & 0xf000) >> 12;
	r[i] |= r[i] << 4;
	r[i] |= r[i] << 8;
	seed <<= 4;
	r[i] = ~r[i];
	r[i+4] = r[i];
    }
    HBITMAP hBitmap = CreateBitmap(8, 8, 1, 1, (LPSTR)r);
    info = (void*)CreatePatternBrush(hBitmap);
    DeleteObject(hBitmap);
}

Pattern::~Pattern () {
    if (info != nil) {
	DeleteObject((HBRUSH)info);
    }
}

#endif

