#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <msdos.cf>
#include    <egb.h>
#include    <fgs.h>
#include    <xld.h>
#include    <jpeg.h>
#include    <tifflib.h>
#include    "graphic.h"
#include    "coldef.h"

#define	TRUE	1
#define	FALSE	0
#define	ERR	(-1)

#define LOAD_BUF_SIZE	(150 * 1024)
#define DATA_BUF_SIZE	( 64 * 1024)
#define	PALT_BUF_SIZE	(256 * 8 + 4)

extern	int	screen_flg;
extern	char	work[];

	char	fgs_work[FGSWorkSize + 16];

static	FILE    *input_fp;
static	int	disp_mode = 0;
static	int	pixs_mode = 0;
static	int     max_x, max_y;
static	int     scr_x, scr_y;
static	int     off_x = 0, off_y = 0;
static	int	comp;
static	long    strip, clut;
static	int	line_size;
static	char	*img = NULL;
static	char 	*palt_buf;

	char	*strnpath(char *file, int len);

static	int	TIFF_read_data(char *buf, int size )
{
    fread(buf, 1, size, input_fp);
    return 0 ;
}
static	int	TIFF_put_data(char *buf, int lofs, int lines ) 
{
    int r, g, b;
    int n, max;
    int ox, oy;
    short *s;
    unsigned char *p;
    BLOCK para;

    ox = (max_x < scr_x ? ((scr_x - max_x) / 2) : 0);
    oy = (max_y < scr_y ? ((scr_y - max_y) / 2) : 0);

    para.ptn = buf;
    para.sel = getds();
    para.x1 = ox;
    para.x2 = ox + max_x - 1;
    para.y1 = oy + lofs;
    para.y2 = oy + lofs + lines - 1;

    switch(disp_mode) {
    case 1:     /* 2値 */
        EGB_putBlockColor(work, 0, (char *)&para);
	if ( img != NULL )
	    memcpy(img + lofs * line_size, buf, lines * line_size);
	break;

    case 4:     /* 16色 */
    case 8:     /* 256色 */
    case 16:    /* 32K色 */
        EGB_putBlock(work,0,(char *)&para);
	if ( img != NULL )
	    memcpy(img + lofs * line_size, buf, lines * line_size);
	break;

    case 2416:	/* 1680K色 */
	max = max_x * lines;
	p = (unsigned char *)buf;
	s = (short *)buf;
	for ( n = 0 ; n < max ; n++ ) {
	    r = *(p++) >> 3;
	    g = *(p++) >> 3;
	    b = *(p++) >> 3;
	    *(s++) = (g << 10) | (r << 5) | b;
	}
        EGB_putBlock(work, 0, (char *)&para);
	if ( img != NULL )
	    memcpy(img + lofs * line_size, buf, lines * line_size);
	break;

    case 24:	/* フルカラ− */
        FGS_putBlock(fgs_work, 0, (char *)&para);
	if ( img != NULL )
	    memcpy(img + lofs * line_size, buf, lines * line_size);
	break;
    }

    return 0;
}
static	void	VramInit(int mode)
{
    char para[32];

    EGB_displayPage(work, 0, 0);

    switch(mode) {
    case 1:     /* 2値 */
        EGB_resolution(work, 0, 3);
	EGB_writePage(work,0);
        EGB_color(work,0, 0) ;
	EGB_color(work, 1, 15);
	EGB_clearScreen(work);
	EGB_displayPage(work, 0, 1);
	scr_x = 640;
	scr_y = 480;
	disp_mode = 1;
	break;

    case 4:     /* 16色 */
        EGB_resolution(work, 0, 3);
	EGB_writePage(work, 0);
	EGB_color(work, 1, 0);
	EGB_clearScreen(work);
	EGB_displayPage(work, 0, 1);
	scr_x = 640;
	scr_y = 480;
	disp_mode = 4;
        break;

    case 8:     /* 256色 */
        EGB_resolution(work, 0, 12);
	EGB_writePage(work, 0);
	EGB_color(work, 1, 0);
	EGB_clearScreen(work);
	EGB_displayPage(work, 0, 1);
	scr_x = 640;
	scr_y = 480;
	disp_mode = 8;
        break;

    case 16:    /* 32K色 */
	disp_mode = 16;
	goto DSP32K;
    case 2416:
	disp_mode = 2416;
    DSP32K:
	if ( max_x > 320 ) {
            EGB_resolution(work,0,17);
            EGB_displayStart(work, 3, 512, 480);
	    scr_x = 512;
	    scr_y = 480;
        } else {
            EGB_resolution(work,0,10);
            EGB_displayStart(work, 2, 2, 2);
            EGB_displayStart(work, 3, 320, 240);
	    scr_x = 320;
	    scr_y = 240;
        }
	EGB_writePage(work, 0);
	EGB_color(work, 1, 0);
	EGB_clearScreen(work);
	EGB_displayPage(work, 0, 1);
        break ;

    case 24:	/* 1680K色 */
	if ( FGS_openCheck() == 0 )
	    FGS_init(fgs_work, FGSWorkSize);
	else if ( FGS_openCheck2() == 0 )
	    FGS_init2(fgs_work, FGSWorkSize);
	else {
	    disp_mode = 2416;
	    goto DSP32K;
	}
	FGS_clearScreen(fgs_work);
	FGS_getResolutionPage(0, para);
	scr_x = DWORD(para + 8);
	scr_y = DWORD(para + 12);
	disp_mode = 24;
	break;
    }
}
static	void	DispImg(int x, int y)
{
    int n;
    int sx, sy;
    int ox, oy;
    BLOCK para;
    char *p;

    if ( img == NULL )
	return;

    ox = (max_x < scr_x ? ((scr_x - max_x) / 2) : 0);
    oy = (max_y < scr_y ? ((scr_y - max_y) / 2) : 0);

    if ( x == 0 ) {
	if ( (sy = max_y - y) > scr_y )
	    sy = scr_y;
	para.ptn = img + y * line_size;
	para.sel = getds();
	para.x1 = ox;
	para.x2 = ox + max_x - 1;
	para.y1 = oy;
	para.y2 = oy + sy - 1;

	if ( disp_mode == 24 )
            FGS_putBlock(fgs_work, 0, (char *)&para);
	else if ( disp_mode == 1 )
            EGB_putBlockColor(work, 0, (char *)&para);
	else
            EGB_putBlock(work, 0, (char *)&para);

	return;
    }

    p = img + y * line_size;
    switch(disp_mode) {
    case 1:     /* 2値 */
	p += (x / 8);
	x -= (x & 7);
	break;
    case 4:     /* 16色 */
	p += (x / 2);
	x -= (x & 1);
	break;
    case 8:     /* 256色 */
	p += x;
	break;
    case 16:    /* 32K色 */
    case 2416:	/* 1680K色 */
	p += (x * 2);
        break;
    case 24:	/* フルカラ− */
	p += (x * 3);
        break;
    }

    for ( n = 0 ; n < scr_y ; n++ ) {
	if ( (sx = max_x - x) > scr_x )
	    sx = scr_x;
	para.ptn = p;
	para.sel = getds();
	para.x1 = ox;
	para.x2 = ox + sx - 1;
	para.y1 = oy + n;
	para.y2 = oy + n;

	if ( disp_mode == 24 )
            FGS_putBlock(fgs_work, 0, (char *)&para);
	else if ( disp_mode == 1 )
            EGB_putBlockColor(work, 0, (char *)&para);
	else
            EGB_putBlock(work, 0, (char *)&para);

	p += line_size;
    }
}

/****
12345678901234567890123456789012345678901234567890123456789012345678901234567890   フ ァ イ ル 名   \GRAPHICS\TIFF\ABC\ETC.TIF         |
   画  像  形  式   1677万色 (3万2千色に減色して表示)  |
   画 像 サ イ ズ   512 × 480 dots
      圧    縮      LZW圧縮
  スクリ−ンサイズ  640 × 480
*****/
#define	STAT_X1		96
#define	STAT_Y1		180
#define	STAT_X2		(STAT_X1 + 448 - 1)
#define	STAT_Y2		(STAT_Y1 + 120 - 1)

static	void	TiffStat(char *file)
{
    int sw, x, y;
    BLOCK para;
    long st, ed;
    FILE *fp;

    if ( img == NULL )
	return;

    if ( disp_mode == 24 )
	sub_FGS_close();

    EGB_displayPage(work, 0, 0);
    EGB_resolution(work, 0, 3);
    EGB_writePage(work, 0);
    DSP_palette();
    EGB_color(work, 1, 0);
    EGB_clearScreen(work);
    EGB_displayPage(work, 0, 1);

    DSP_wbox(STAT_X1, STAT_Y1, STAT_X2, STAT_Y2, LINE_COL, FILD_COL, M_PSET);

    gputs(STAT_X1 + 16, STAT_Y1 +  8, CHR_COL, FILD_COL, " フ ァ イ ル 名");
    gputs(STAT_X1 + 168, STAT_Y1 +  8, CHR_COL, FILD_COL, strnpath(file, 33));

    gputs(STAT_X1 + 16, STAT_Y1 + 28, CHR_COL, FILD_COL, " 画  像  形  式");

    switch(disp_mode) {
    case 1:
	gputs(STAT_X1 + 168, STAT_Y1 + 28, CHR_COL, FILD_COL,
		"2色");
	break;
    case 4:
	gprintf(STAT_X1 + 168, STAT_Y1 + 28, CHR_COL, FILD_COL,
		"16色%s", (clut != 0 ? "(パレット有り)" : ""));
	break;
    case 8:
	gprintf(STAT_X1 + 168, STAT_Y1 + 28, CHR_COL, FILD_COL,
		"256色%s", (clut != 0 ? "(パレット有り)" : ""));
	break;
    case 16:
	gputs(STAT_X1 + 168, STAT_Y1 + 28, CHR_COL, FILD_COL,
		"3万2千色");
	break;
    case 2416:
	gputs(STAT_X1 + 168, STAT_Y1 + 28, CHR_COL, FILD_COL,
		"1677万色 (3万2千色に減色して表示)");
	break;
    case 24:
	gputs(STAT_X1 + 168, STAT_Y1 + 28, CHR_COL, FILD_COL,
		"1677万色");
	break;
    }

    gputs(STAT_X1 + 16, STAT_Y1 + 48, CHR_COL, FILD_COL, " 画 像 サ イ ズ");
    gprintf(STAT_X1 + 168, STAT_Y1 + 48, CHR_COL, FILD_COL,
	"%d × %d dots", max_x, max_y);

    gputs(STAT_X1 + 16, STAT_Y1 + 68, CHR_COL, FILD_COL, "    圧    縮");
    gputs(STAT_X1 + 168, STAT_Y1 + 68, CHR_COL, FILD_COL, 
	(comp == 5 ? "LZW圧縮" :
	(comp == 1 ? "なし" :
	(comp == 200 ? "JPEG圧縮" : "？圧縮"))));

    gputs(STAT_X1 + 16, STAT_Y1 + 88, CHR_COL, FILD_COL, "スクリ−ンサイズ");
    gprintf(STAT_X1 + 168, STAT_Y1 + 88, CHR_COL, FILD_COL,
	"%d × %d dots", scr_x, scr_y);

    time(&st); st += 30;
    do {
	time(&ed);
	MOS_rdpos(&sw, &x, &y);
    } while ( sw == 0 && ed < st );

    do {
	time(&ed);
	MOS_rdpos(&sw, &x, &y);
    } while ( sw != 0 && ed < st );

    VramInit(disp_mode);
    if ( clut != 0 )
        EGB_palette(work, 0, palt_buf);
    DispImg(off_x, off_y);
}
static	void	DispWait(char *file)
{
    int sw, x, y;
    int ox, oy;
    int dx, dy;
    long st, ed;

    dx = off_x; dy = off_y;
    MOS_rdpos(&sw, &ox, &oy);
    time(&st); st += 30;

    do {
	time(&ed);
	MOS_rdpos(&sw, &x, &y);
	if ( (sw & 1) != 0 ) {
	    st = ed + 30;
	    TiffStat(file);
	    continue;
	}
	off_x += (ox - x);
	off_y += (oy - y);
	MOS_setpos(320, 240);
	ox = 320; oy = 240;

	if ( (off_x + scr_x) > max_x )
	    off_x = max_x - scr_x;
	if ( off_x < 0 )
	    off_x = 0;

	if ( (off_y + scr_y) > max_y )
	    off_y = max_y - scr_y;
	if ( off_y < 0 )
	    off_y = 0;

	if ( dx != off_x || dy != off_y ) {
	    st = ed + 30;
	    DispImg(off_x, off_y);
	    dx = off_x;
	    dy = off_y;
	}

    } while ( (sw & 2) == 0 && ed < st );

    do {
	MOS_rdpos(&sw, &x, &y);
    } while ( sw != 0 );
}
int	TIFF_disp(char *file)
{
    char    *load_buf;
    char    *data_buf;
    char    *comp_buf;
    int     d_line, fill;
    long    dw;
    BLOCK   *save;

    if ( (input_fp = fopen(file,"rb")) == NULL ) {
	kakunin("TIFFファイルが見当たりません");
        return ERR;
    }

    if ( (load_buf = (char *)malloc(LOAD_BUF_SIZE +
				    DATA_BUF_SIZE +
				    PALT_BUF_SIZE +
				    DECOMP_WORK_SIZE)) == NULL ) {
	fclose(input_fp);
	kakunin("TIFF作業のメモリ−不足です");
	return ERR;
    }

    data_buf = load_buf + LOAD_BUF_SIZE;
    palt_buf = data_buf + DATA_BUF_SIZE;
    comp_buf = palt_buf + PALT_BUF_SIZE;

    fread(load_buf, 1, LOAD_BUF_SIZE, input_fp);

    if ( TIFF_getHead(load_buf, LOAD_BUF_SIZE) < 0 ||
         (pixs_mode = TIFF_checkMode(&max_x, &max_y, &comp,
				     &fill, &strip, &clut)) < 0 ) {
	kakunin("TIFFの認識ができませんでした");
        goto ERROR;
    }

    switch(pixs_mode) {
    case 1:     /* 2値 */
    case 4:     /* 16色 */
    case 8:     /* 256色 */
    case 16:    /* 32K色 */
    case 24:	/* 1680K色 */
        break;
    default:
	kakunin("対応していない色数のTIFFです(%d)", pixs_mode);
	goto ERROR;
    }

    TIFF_setLoadFunc(TIFF_put_data, TIFF_read_data) ;

    /* 画面モードの設定 */

    MOS_disp(OFF);
    if ( screen_flg == FALSE )
	save = DSP_push_vram(0, 0, 639, 479);

    VramInit(pixs_mode);

    dw = max_x;
    if ( pixs_mode == 4 && (dw & 7) != 0 )
       dw += 8 - (dw & 7);
    line_size = ((dw * pixs_mode + 7) / 8);
    d_line = DATA_BUF_SIZE / line_size;
    off_x = off_y = 0;

    if ( clut != 0 ) {
        TIFF_getPal(palt_buf) ;
        EGB_palette(work, 0, palt_buf) ;
    }

    if ( disp_mode == 2416 )
	line_size = max_x * 2;

    img = (char *)malloc(line_size * max_y);

    TIFF_loadImage(pixs_mode, max_x, max_y, strip, fill,
		   comp, data_buf, dw, d_line, comp_buf);

/*********
    mos_wait();
**********/
    DispWait(file);

    if ( disp_mode == 24 )
	sub_FGS_close();

    EGB_displayPage(work, 0, 0);
    EGB_resolution(work, 0, 3);
    EGB_resolution(work, 1, 3);
    EGB_writePage(work, 1);
    DSP_palette();
    EGB_clearScreen(work);
    EGB_writePage(work, 0);
    DSP_palette();
    EGB_clearScreen(work);

    if ( screen_flg == FALSE )
	DSP_pop_vram(save);

    EGB_displayPage(work, 0, 3);
    MOS_disp(ON);

    if ( img != NULL )
	free(img);

    free(load_buf);
    fclose(input_fp);
    FILE_redisp();
    return FALSE;

ERROR:
    free(load_buf);
    fclose(input_fp);
    FILE_redisp();
    return ERR;
}

/**************************

	JPEG

***************************/
static	int	JPEG_read_data(char *buf, long bsize, long ofs)
{
    fseek(input_fp, ofs, SEEK_SET);
    fread(buf, 1, bsize, input_fp);
    return 0;
}
int	JPEG_disp(char *file)
{
    JPEGCard   JPCard   ;     /* JPEGカード情報格納ポインタ        */
    char       *dbuf    ;     /* ﾛｰﾄﾞﾊﾞｯﾌｧへのﾎﾟｲﾝﾀ                */
    char       *cbuf    ;     /* 作業バッファポインタ              */
    char       *sbuf    ;     /* 展開バッファへのポインタ          */
    int        width    ;     /* 画像サイズ(横)                    */
    int        height   ;     /* 画像サイズ(縦)                    */
    long       subs     ;     /* ｻﾌﾞｻﾝﾌﾟﾘﾝｸﾞ                       */
    int        color    ;     /* 色情報                            */
    int        len      ;     /* 作業領域サイズ                    */
    BLOCK      *save;

    if ( (input_fp = fopen(file, "rb")) == NULL ) {
	kakunin("TIFFファイルが見当たりません");
        return ERR;
    }

    JPEG_loadInit(&JPCard, 0);		/* Huffman = 0 */

    JPEG_setLoadFunc(TIFF_put_data, JPEG_read_data);

    if ( (dbuf = malloc(512)) == NULL )
	goto MEMERR;

    JPEG_setLoadBuffer(dbuf, 512);

    JPEG_getSOF(&width, &height, &subs, &color, 0);

    max_x = width;
    max_y = height;
    pixs_mode = 24;
    off_x = off_y = 0;
    comp = 200;
    clut = 0;

    MOS_disp(OFF);
    if ( screen_flg == FALSE )
	save = DSP_push_vram(0, 0, 639, 479);

    VramInit(pixs_mode);
    if ( disp_mode == 2416 )
	pixs_mode = 16;

    line_size = (max_x * pixs_mode) / 8;
    img = (char *)malloc(line_size * max_y);

    len = JPEG_loadBufSize(pixs_mode, width, height, subs, color);

    if ( (cbuf = malloc(len)) == NULL ||
	 (sbuf = malloc(line_size * 32)) == NULL )
	goto MEMERR;


    JPEG_loadImageJFIF(pixs_mode, width, height, 1, subs, sbuf, width,
	                    32, cbuf, color, 0, &JPCard, NULL);

    fclose(input_fp);
    free(cbuf);
    free(sbuf);
    free(dbuf);

    JPEG_loadEnd(&JPCard);

    DispWait(file);

    if ( disp_mode == 24 )
	sub_FGS_close();

    EGB_displayPage(work, 0, 0);
    EGB_resolution(work, 0, 3);
    EGB_resolution(work, 1, 3);
    EGB_writePage(work, 1);
    DSP_palette();
    EGB_clearScreen(work);
    EGB_writePage(work, 0);
    DSP_palette();
    EGB_clearScreen(work);

    if ( screen_flg == FALSE )
	DSP_pop_vram(save);

    EGB_displayPage(work, 0, 3);
    MOS_disp(ON);

    if ( img != NULL )
	free(img);

    FILE_redisp();
    return FALSE;

MEMERR:
    fclose(input_fp);
    kakunin("JPEG作業メモリが不足しています");
    FILE_redisp();
    return ERR;
}
