#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <dos/dos.h>
#include <exec/exec.h>
#include <exec/types.h>
#include <diskfont/diskfont.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/diskfont.h>
#include <proto/asl.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

extern __asm __saveds LONG count(register __d0 a, register __d1 b);

/* Private definitions */

#define MAKE_ID(a,b,c,d)        \
        ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))

#define ID_FORM MAKE_ID('F','O','R','M')
#define ID_ILBM MAKE_ID('I','L','B','M')
#define ID_BMHD MAKE_ID('B','M','H','D')
#define ID_CMAP MAKE_ID('C','M','A','P')
#define ID_BODY MAKE_ID('B','O','D','Y')

struct BitMapHeader
{
    UWORD w,h;
    WORD x,y;
    UBYTE nplanes;
    UBYTE masking;
    UBYTE compression;
    UBYTE pad1;
    UWORD transparentColor;
    UBYTE xAspect,yAspect;
    WORD pageWidth,pageHeight;
};

int gw=0,gh=0;

int ReadILBM(char *fname, struct BitMap **bmp, ULONG *palette)
{
    FILE *f;

    ULONG nam,siz,remain;
    BOOL BMHDfl=FALSE,CMAPfl=FALSE,BODYfl=FALSE;
    struct BitMapHeader bmhd;
    int bmwidth,bmheight,bmdepth;

    if(!(f=fopen(fname,"rb")))
        return 0;

    if(!fread(&nam,sizeof(ULONG),1,f))
    {
        fclose(f);
        return 0;
    }

    if(nam!=ID_FORM)
    {
        fclose(f);
        return 0;
    }

    if(!fread(&remain,sizeof(ULONG),1,f))
    {
        fclose(f);
        return 0;
    }

    if(!fread(&nam,sizeof(ULONG),1,f))
    {
        fclose(f);
        return 0;
    }

    if(nam!=ID_ILBM)
    {
        fclose(f);
        return 0;
    }

    remain-=4;

    /* Chunk reading loop */
    while(remain>0 && !feof(f) && !(BMHDfl && BODYfl && (CMAPfl || !palette)))
    {
        if(!fread(&nam,sizeof(ULONG),1,f))
        {
            fclose(f);
            return 0;
        }

        if(!fread(&siz,sizeof(ULONG),1,f))
        {
            fclose(f);
            return 0;
        }

        remain-=8+siz+(siz & 1);

        switch(nam)
        {
            case ID_BMHD:
                if(siz!=sizeof(struct BitMapHeader))
                {
                    fclose(f);
                    return 0;
                }

                if(!fread(&bmhd,sizeof(struct BitMapHeader),1,f))
                {
                    fclose(f);
                    return 0;
                }
                BMHDfl=TRUE;
                gw=bmwidth=bmhd.w;
                gh=bmheight=bmhd.h;
                bmdepth=bmhd.nplanes;

                if(bmdepth!=1)
                {
                    fclose(f);
                    return 0;
                }
                break;
            case ID_BODY:
                if(!BMHDfl)
                {
                    fclose(f);
                    return 0;
                }
                *bmp=AllocBitMap(bmwidth,bmheight,bmdepth,BMF_CLEAR /*|BMF_DISPLAYABLE*/ /*|BMF_INTERLEAVED*/,NULL);
                if(!*bmp)
                {
                    fclose(f);
                    return 0;
                }

                if(bmhd.compression)
                {
                    int i,j,k,l;
                    UBYTE *pptr;
                    BYTE sel;
                    for(i=0;i<bmheight;i++) /* Line */
                    {
                        for(j=0;j<bmdepth;j++) /* Plane */
                        {
                            pptr=(*bmp)->Planes[j]+(*bmp)->BytesPerRow*i;
                            k=2*((bmwidth+15)>>4);
                            while(k)
                            {
                                sel=fgetc(f);
                                l=(int)sel;
                                if(l>=0 && l<=127)
                                {
                                    l++;
                                    k-=l;
                                    while(l--)
                                        *pptr++=fgetc(f);
                                }
                                else if(l>=-127 && l<=-1)
                                {
                                    l=1-l;
                                    k-=l;
                                    sel=fgetc(f);
                                    while(l--)
                                        *pptr++=sel;
                                }
                            }
                        }
                    }
                }
                else
                {
                    int i,j,k;
                    UBYTE *pptr;
                    for(i=0;i<bmheight;i++) /* Line */
                    {
                        for(j=0;j<bmdepth;j++) /* Plane */
                        {
                            pptr=(*bmp)->Planes[j]+(*bmp)->BytesPerRow*i;
                            for(k=0;k<2*((bmwidth+15)>>4);k++) /* Byte */
                            {
                                *pptr++=fgetc(f);
                            }
                        }
                    }
                }
                if(siz&1)
                        fseek(f,1,SEEK_CUR);
                BODYfl=TRUE;
                break;
            case ID_CMAP:
                if(!palette)
                {
                    if(siz&1)
                        siz++;
                    fseek(f,siz,SEEK_CUR);
                }
                else
                {
                    UBYTE r,g,b;
                    int i;

                    palette[0]=(siz/3)<<16;

                    for(i=0;i<siz/3;i++)
                    {
                        r=fgetc(f);
                        g=fgetc(f);
                        b=fgetc(f);
                        palette[i*3+1]=MAKE_ID(r,r,r,r);
                        palette[i*3+2]=MAKE_ID(g,g,g,g);
                        palette[i*3+3]=MAKE_ID(b,b,b,b);
                    }

                    palette[i*3+1]=0;

                    if(siz&1)
                        fseek(f,1,SEEK_CUR);
                }
                CMAPfl=TRUE;
                break;
            default:
                if(siz&1)
                    siz++;
                fseek(f,siz,SEEK_CUR);
                break;
        }
    }

    fclose(f);
    return BMHDfl && BODYfl;
}

int main(int argc, char *argv[])
{
    struct BitMap *imgbm, *fntbm;
    struct RastPort imgrp,fntrp;
    struct TextFont *fnt;
    static struct TextAttr ta=
    {
        NULL,
        8,
        FS_NORMAL,
        0
    };
    char chrs[193];
    int i,x,y;
    int mej,cuan;
    int cuaneste;
    int y2;
    int mchar=192;
    int gris[192],mgris=0;
    
    UBYTE *p1,*p2,*p3;

    if(argc!=4 || (argv[3][0]!='8' && argv[3][0]!='7'))
    {
        printf("Usage: %s iff-file fontname.font {7|8} >output-file\n",argv[0]);
        exit(5);
    }
    
    if(argv[3][0]=='7')
    {
        mchar=96;
    }
    
    ta.ta_Name=argv[2];
    
    if(fnt=OpenDiskFont(&ta))
    {
        if(fntbm=AllocBitMap(192*8,8,1,BMF_CLEAR /*|BMF_DISPLAYABLE*/,NULL))
        {
            InitRastPort(&fntrp);
            fntrp.BitMap=fntbm;
            
            if(ReadILBM(argv[1],&imgbm,NULL))
            {
                InitRastPort(&imgrp);
                imgrp.BitMap=imgbm;
                
                SetFont(&fntrp,fnt);
                
                for(i=0;i<192;i++)
                {
                    chrs[i]=32+i+32*(i>=96);
                }
                chrs[192]=0;
                
                SetAPen(&fntrp,1);
                SetBPen(&fntrp,0);
                Move(&fntrp,0,fnt->tf_Baseline);
                Text(&fntrp,chrs,192);
                
                for(i=0;i<mchar;i++)
                {
                    cuaneste=0;
                    p2=fntbm->Planes[0]+i;
                    
                    for(y2=0;y2<8;y2++)
                    {
                        cuaneste+=count(0,*p2);
                        p2+=fntbm->BytesPerRow;
                    }
                    gris[i]=cuaneste;
                    if(cuaneste>mgris)
                        mgris=cuaneste;
                }
                
                gw/=8;
                gh/=8;
                
                if(gw && gh)
                {
                    for(y=0;y<gh;y++)
                    {
                        p1=imgbm->Planes[0]+y*8*imgbm->BytesPerRow;
                        for(x=0;x<gw;x++)
                        {
                            mej=0;
                            cuan=0;
                            
                            p3=p1;
                            for(y2=0;y2<8;y2++)
                            {
                                cuan+=count(*p3,0);
                                p3+=imgbm->BytesPerRow;
                            }
                            cuan=(cuan*mgris)/64;
                            for(i=1;i<mchar && cuan;i++)
                            {
                                if((gris[i]-cuan)*(gris[i]-cuan)<(gris[mej]-cuan)*(gris[mej]-cuan))
                                {
                                    mej=i;
                                }
                            }
                            printf("%c",32+mej+32*(mej>=96));
                            p1++;
                        }
                        printf("\n");
                    }
                }
                
                FreeBitMap(imgbm);
            }
            FreeBitMap(fntbm);
        }
        CloseFont(fnt);
    }
}