#include "fat12.h"
#include "mode16.h"
#include "graph16.h"
#include "math.h"
#include "type.h"

FAT_ENTRY far * root=MK_FP(0x220,0);
BS_FAT12 far* boot=MK_FP(0x7c0,0);
BYTE far * fat=MK_FP(0x100,0);

// retrouve une entree dans le dossier root
int find_entry(char *c)
{
	int i,j;
	for(i=0;i<224;i++)
	{
		for(j=0;j<11;j++)
		{
			if(c[j]!=root[i].Name[j])
				break;
		}

		if(j>=11)
			break;
	}
	if(i>=224)
		return -1;
	else
		return i;
}

// Lit un secteur LBA
BYTE read_sector(WORD lba,char far* buffer)
{
	WORD c,h,s;
	c=lba/18;
	if(c%2==0)
	{
		h=0;
		c=(WORD)c/2;
	}
	else
	{
		h=1;
		c=(WORD)(c-1)/2;
	}
	s=(WORD)(lba%18)+1;

	return read_sector_chs((BYTE)c,(BYTE)h,(BYTE)s,buffer);
}

// lit un secteur de disquette
BYTE read_sector_chs(BYTE cylinder,BYTE head,BYTE sector,char far* buffer)
{
	BYTE err,drive;
	drive=boot->DriveNumber;
	asm{
		les	bx,buffer;

		mov	ax,0x0201;
		mov	dl,drive;
		mov	dh,head;
		mov	ch,cylinder;
		mov	cl,sector;
		int	0x13;
		mov	err,ah;
	}
	return err;
}

WORD get_next_sector(WORD sector)
{
	WORD next = 0;
	WORD index=(sector*3)/2;

	if(sector%2)
	{
		next=fat[index+1];
		next<<=4;
		next|=fat[index]>>4;
	}
	else
	{
		next=fat[index+1]&0x0F;
		next<<=8;
		next|=fat[index];
	}
	return next;
}

int get_max_sectors(WORD sect)
{
	int result=1;
	while((sect=get_next_sector(sect))<0xFF8)
		result++;
	return result;
}

struct
	{
		WORD   size;
		WORD   a_0_15;
		BYTE   a_16_23;
		BYTE   flag;
		WORD   reserved;
	}temp_gdt[6]={{0,0,0,0,0},
                  {0,0,0,0,0},
                  {0xFFFF,0x0000,0x02,0x93,0},
                  {0xFFFF,0x0000,0x10,0x93,0},
                  {0,0,0,0,0},
                  {0,0,0,0,0}};

BYTE move_block(BYTE off,WORD size)
{
     BYTE err;

	 temp_gdt[3].a_16_23=off;
     asm{
         mov    ax,ds;
         mov    es,ax;
         mov    si,offset temp_gdt;
         mov    ah,0x87;
         mov    cx,size;
		 int   0x15;
         mov   err,ah;
     }
     return err;
}

int load_12()
{
	WORD sect,nmax,n=0;
	int index;
	char far*buffer=(char far*)MK_FP(0x2000,0);
	DWORD far* kernel_size=(DWORD far*)MK_FP(0x2000,0);
	BYTE offset=0x10;
	
	if((index=find_entry("KERNEL  BIN"))==-1)
		return-1;

	sect=root[index].ClusterLow;
	nmax=get_max_sectors(sect);
	gotoxy(0,21);
	print_text("Chargement du system");

	while(n<nmax)
	{
		if(read_sector(sect+31,buffer))
			return -1;
		
		n++;
		buffer+=512;

		if(n%128==0)
		{
			if(move_block(offset,0x8000))
					return -1;
			offset++;
		}
		
		draw_bar(ldiv(lmul(n,100),nmax));

		if((sect=get_next_sector(sect))>=0xFF8)
		{
			if(n%128)
				move_block(offset,FP_OFF(buffer)/2);
			break;
		}
	}
	*kernel_size=root[index].Size;
	return 0;
}