/*
 * このプログラムは XKOBO (Akira Higuchi a-higuti@math.hokudai.ac.jp さん作)
 * に収録されていたものを Eiju Tsuboi s1021127@u-aizu.ac.jp が Cosmo Gang
 * the Puzzle 用に改良したものです。Cosmo Gang the Puzzle での使用を快く承諾
 * して下さった Akira Higuchi さんにこの場を借りてお礼申し上げます。
 *                                                            １９９６年３月
 */

/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>

#define CM_MIN 0
#define CM_MAX 255
 
/********    tiny TIFF loader  ( 256 colors, not compressed )   ********/

static int pos_image   = 0;
static int pos_cmap    = 0;
static int sizex       = 0;
static int sizey       = 0;
static int endianness;

static unsigned int get_16bits(unsigned char *p)
{
    if (endianness == 0x49)
        return (p[0] + (p[1]<<8));
    return (p[1] + (p[0]<<8));
}

static unsigned int get_32bits(unsigned char *p)
{
    if (endianness == 0x49)
        return (p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24));
    return (p[3] + (p[2]<<8) + (p[1]<<16) + (p[0]<<24));
}

static int read_tag(unsigned char *data)
{
    unsigned char *p = data;
    int dir_p = 0;
    int tag_max;
    int tag_type;
    int i;
    
    endianness = p[0];
    if ((endianness != 0x49) && (endianness != 0x4d)) return 1;
    if (endianness != p[1]) return 2;
    if (get_16bits(p + 2) != 0x2a) return 3;
    p += 4;

    for (;;){
        dir_p = get_32bits(p);
        if (dir_p == 0) break;
        p = data + dir_p;
        
        tag_max = get_16bits(p);
        p += 2;
        for (i=0; i<tag_max; i++){
            tag_type = get_16bits(p);
            switch (tag_type){
              case 0x0100:
                {
                    /* image width */
                    sizex = get_16bits(p + 8);
                    break;
                };
              case 0x0101:
                {
                    /* image length */
                    sizey = get_16bits(p + 8);
                    break;
                };
              case 0x0102:
                {
                    /* bitss per sample */
                    if (get_16bits(p + 8) != 8)
                        return 4;
                    break;
                }
              case 0x0103:
                {
                    /* compression */
                    if (get_16bits(p + 8) != 1)
                        return 5;
                    break;
                }
              case 0x0111:
                {
                    /* strip offset */
                    pos_image = get_32bits(p + 8);
                    break;
                }
              case 0x0140:
                {
                    /* color map */
                    pos_cmap = get_32bits(p + 8);
                    break;
                }
            }
            p += 12;
        }
    }
    
    if ((!pos_image) || (!pos_cmap) || (!sizex) || (!sizey))
        return 6;
    return 0;
}

int link_tiff(
  Display *d,
  Window win1, Window win2,
  GC gc,
  Colormap cmap,
  unsigned char *data,
  int ox, int oy,
  int *width, int *height)
{
    unsigned long pixel[256],mask[256];
    int num[256],index[257];
    int i;
    unsigned char *ptr;
    XColor col;
    XPoint *xpos;
    int x,y;
    
    if (read_tag(data)){
         fprintf(stderr, "tiff_loader : fatal error (Illegal format)\n");
         return -1;
    }

    for (i=0; i<256; i++){
	num[i]=0;
    }

    ptr = (unsigned char *)(data + pos_image);
    for (y=oy; y<sizey+oy; y++){
      for (x=ox; x<sizex+ox; x++){
	num[*ptr]++;
	ptr++;
	if(num[*ptr]==1)
	{
	  col.red   = *(data + pos_cmap + *ptr*2      ) << 8;
	  col.green = *(data + pos_cmap + *ptr*2 +512 ) << 8;
	  col.blue  = *(data + pos_cmap + *ptr*2 +1024) << 8;
	  if(col.red==0 && col.green==0 && col.blue==0xfe00)
	  {
	    pixel[*ptr]=0;
	    mask[*ptr]=0xffffffff;
	  }
	  else
	  {
	    XAllocColor(d, cmap, &col);
	    pixel[*ptr] = col.pixel;
	    mask[*ptr]=0;
	  }
	}
      }
    }

    index[0]=0;
    for(i=1;i<=256;i++) index[i]=num[i-1]+index[i-1];
    xpos = (XPoint *)malloc(sizex*sizey*sizeof(XPoint));

    ptr = (unsigned char *)(data + pos_image);
    for (y=oy; y<sizey+oy; y++){
      for (x=ox; x<sizex+ox; x++){
	num[*ptr]--;
	xpos[index[*ptr]+num[*ptr]].x=x;
	xpos[index[*ptr]+num[*ptr]].y=y;
	ptr++;
      }
    }

    for(i=0;i<256;i++)
    {
      XSetForeground(d, gc, pixel[i]);
      XDrawPoints(d, win1, gc, &xpos[index[i]],
		  index[i+1]-index[i], CoordModeOrigin);
    }
    free(xpos);

    if(win2)
    {
        ptr = (unsigned char *)(data + pos_image);
        for (y=oy; y<sizey+oy; y++){
            for (x=ox; x<sizex+ox; x++){
	        XSetForeground(d, gc, mask[*ptr]);
		XDrawPoint(d, win2, gc, x, y);
		ptr++;
	    }
	}
    }

    if(width ) *width=sizex;
    if(height) *height=sizey;

    return 0;
}
