// Emacs style mode select   -*- C++ -*- 
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
//	Main program, simply calls D_DoomMain high level loop.
//
//-----------------------------------------------------------------------------

static const char
rcsid[] = "$Id: i_main.c,v 1.4 1997/02/03 22:45:10 b1 Exp $";

#include <stdio.h>
#include <stdlib.h>
#include "doomdef.h"

#include "m_argv.h"
#include "d_main.h"
#include "PSP.h"
#include "fontb.c"

char *pg_vramtop=(char *)0x04000000;
long pg_screenmode;
long pg_showframe;
long pg_drawframe;

extern char *doomwaddir;
char doomwaddir2[256];

/* Define the module info section */
PSP_MODULE_INFO("Doom-PSP", 0, 1, 1);

/* Define the main thread's attribute value (optional) */
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);
 
extern void _DisableFPUExceptions();
extern void sound_callback(void *buf, unsigned int reqn);

// ---------------------------------------------------------------------------------
#define MAXDEPTH  16
#define MAXDIRNUM 1024
#define MAXPATH   0x108
#define PATHLIST_H 20
#define REPEAT_TIME 0x40000
#define BUFSIZE		65536

dirent_t		dlist[MAXDIRNUM];
int				dlist_num;
char			now_path[MAXPATH];
extern char			target[MAXPATH];
char			path_tmp[MAXPATH];
int				dlist_start;
int				dlist_curpos;
int				cbuf_start[MAXDEPTH];
int				cbuf_curpos[MAXDEPTH];
int				now_depth;
char			buf[BUFSIZE];


/* Exit callback */
int exit_callback(void)
{
	sceKernelExitGame();
	return 0;
}

/* Callback thread */
void CallbackThread(void *arg)
{
	int cbid;

	cbid = sceKernelCreateCallback("Exit Callback", (void *)exit_callback, NULL);
	sceKernelRegisterExitCallback(cbid);

	sceKernelSleepThreadCB();
}


/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
	int thid = 0;

	thid = sceKernelCreateThread("update_thread", (void *)CallbackThread, 0x11, 0xFA0, 0, 0);
	if(thid >= 0)
	{
		sceKernelStartThread(thid, 0, 0);
	}

	return thid;
}


int
main
( int		argc,
  char**	argv ) 
{ 
    myargc = argc; 
    myargv = argv; 

    
    char *ni;
    doomwaddir = myargv[0];
    ni = strrchr(doomwaddir, '/');
    *++ni = 0;
    char* doomwaddir2;
        

    strcpy(doomwaddir2,doomwaddir);
    strcat(doomwaddir2,"WADS/");
		
	pspAudioInit();
	pspAudioSetChannelCallback(0, (void *)&sound_callback);


	_DisableFPUExceptions();
//	pspDebugScreenInit();

	sceCtrlSetSamplingCycle(0);
	sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);

	SetupCallbacks();
        pgInit();
        pgScreenFrame(2,0);
        pgFillvram(0);

    Get_DirList(doomwaddir2);
    dlist_start  = 0;
    dlist_curpos = 0;
    now_depth    = 0;

while(1) {
    Draw_All();
switch(Control()) {
		case 1:
			Get_DirList(doomwaddir2);
			break;
		case 2:
                        pgFillvram(0);
                        strcpy(target,doomwaddir2);
                        strcat(target,dlist[dlist_curpos].name);
                        pgScreenFlipV();
                        pspDebugScreenInit();

    D_DoomMain (); 
        }
    }    

    return 0;

}

void pgInit()
{
	sceDisplaySetMode(0,SCREEN_WIDTH,SCREEN_HEIGHT);
	pgScreenFrame(0,0);
}

void pgScreenFrame(long mode,long frame)
{
	pg_screenmode=mode;
	frame=(frame?1:0);
	pg_showframe=frame;
	if (mode==0) {
		//screen off
		pg_drawframe=frame;
		sceDisplaySetFrameBuf(0,0,0,1);
	} else if (mode==1) {
		//show/draw same
		pg_drawframe=frame;
		sceDisplaySetFrameBuf(pg_vramtop+(pg_showframe?FRAMESIZE:0),LINESIZE,PIXELSIZE,1);
	} else if (mode==2) {
		//show/draw different
		pg_drawframe=(frame?0:1);
		sceDisplaySetFrameBuf(pg_vramtop+(pg_showframe?FRAMESIZE:0),LINESIZE,PIXELSIZE,1);
	}
}

void pgScreenFlipV()
{
	pgScreenFlip();
}

void pgScreenFlip()
{
	pg_showframe=(pg_showframe?0:1);
	pg_drawframe=(pg_drawframe?0:1);
	sceDisplaySetFrameBuf(pg_vramtop+(pg_showframe?FRAMESIZE:0),LINESIZE,PIXELSIZE,0);
}

char *pgGetVramAddr(unsigned long x,unsigned long y)
{
    return pg_vramtop+(pg_drawframe?FRAMESIZE:0)+x*PIXELSIZE*2+y*LINESIZE*2+0x40000000;
}

unsigned short num2elisa(unsigned short c) {
	if (c > 4374) {
		return 0x6b;
	} else if (c >= 1410) {
		return c + (0x20c - 1410);
	} else if (c >= 690) {
		return 0x6b;
	} else if (c >= 658) {
		return c + (0x1ec - 658);
	} else if (c >= 612) {
		return c + (0x1cb - 612);
	} else if (c >= 564) {
		return c + (0x1aa - 564);
	} else if (c >= 502) {
		return c + (0x192 - 502);
	} else if (c >= 470) {
		return c + (0x17a - 470);
	} else if (c >= 376) {
		return c + (0x124 - 376);
	} else if (c >= 282) {
		return c + (0xd1 - 282);
	} else if (c >= 252) {
		return c + (0xb7 - 252);
	} else if (c >= 220) {
		return c + (0x9d - 220);
	} else if (c >= 203) {
		return c + (0x93 - 203);
	} else if (c >= 187) {
		return 0x92;
	} else if (c >= 175) {
		return c + (0x8a - 203);
	} else if (c >= 153) {
		return c + (0x7b - 153);
	} else if (c >= 135) {
		return c + (0x74 - 135);
	} else if (c >= 119) {
		return c + (0x6c - 119);
	} else {
		return c;
	}
}

void Draw_Char_Hankaku(int x,int y,unsigned char ch,int col,int backcol,int fill) {
	unsigned short *vr;
	unsigned char  *fnt;
	unsigned char  pt;
	int x1,y1;

	// mapping
	if (ch<0x20) {
		ch = 0;
	} else if (ch<0x80) {
		ch -= 0x20;
	} else if (ch<0xa0) {
		ch = 0;
	} else {
		ch -= 0x40;
	}
	fnt = (unsigned char *)&hankaku_font10[ch*10];

	// draw
	vr = (unsigned short *)pgGetVramAddr(x,y);
	for(y1=0;y1<10;y1++) {
		pt = *fnt++;
		for(x1=0;x1<5;x1++) {
			if (pt & 1) {
				*vr = col;
			} else {
				if (fill) *vr = backcol;
			}
			vr++;
			pt = pt >> 1;
		}
		vr += LINESIZE-5;
	}
}

void Draw_Char_Zenkaku(int x,int y,unsigned char u,unsigned char d,int col,int backcol,int fill) {
	unsigned short *vr;
	unsigned short *fnt;
	unsigned short pt;
	int x1,y1;

	// mapping
	if (d > 0x7F) d--;
	d -= 0x40; u -= 0x81;
	fnt = (unsigned short *)&zenkaku_font10[num2elisa(u*0xbc+d)*10];

	// draw
	vr = (unsigned short *)pgGetVramAddr(x,y);
	for(y1=0;y1<10;y1++) {
		pt = *fnt++;
		for(x1=0;x1<10;x1++) {
			if (pt & 1) {
				*vr = col;
			} else {
				if (fill) *vr = backcol;
			}
			vr++;
			pt = pt >> 1;
		}
		vr += LINESIZE-10;
	}
}

void mh_print(int x,int y,unsigned char *str,int col,int backcol,int fill) {
	unsigned char ch = 0,bef = 0;

	while(*str != 0) {
		ch = *str++;
		if (bef!=0) {
			Draw_Char_Zenkaku(x,y,bef,ch,col,backcol,fill);
			x+=10;
			bef=0;
		} else {
			if (((ch>=0x80) && (ch<0xa0)) || (ch>=0xe0)) {
				bef = ch;
			} else {
				Draw_Char_Hankaku(x,y,ch,col,backcol,fill);
				x+=5;
			}
		}
	}
}

void Get_DirList(char *path) {
	int ret,fd;

	// Directory read
	fd = sceIoDopen(path);
	dlist_num = 0;
	ret = 1;
	while((ret>0) && (dlist_num<MAXDIRNUM)) {
		ret = sceIoDread(fd, &dlist[dlist_num]);
		if (dlist[dlist_num].name[0] == '.') continue;
		if (ret>0) dlist_num++;
	}
	sceIoDclose(fd);

	if (dlist_start  >= dlist_num) { dlist_start  = dlist_num-1; }
	if (dlist_start  <  0)         { dlist_start  = 0;           }
	if (dlist_curpos >= dlist_num) { dlist_curpos = dlist_num-1; }
	if (dlist_curpos <  0)         { dlist_curpos = 0;           }
}

void Draw_All(void) {
	int			i,col;

	pgFillvram(0);
	
	strncpy(path_tmp,doomwaddir2,40);

          mh_print(5,5,"Please choose a game to launch (Press Circle to select)",rgb2col(255,255,255),0,0);
          mh_print(320,255,"DoomPSP-0.04 S.S. b5",rgb2col(50,255,50),0,0);

	i = dlist_start;
	while (i<(dlist_start+PATHLIST_H)) {
		if (i<dlist_num) {
			col = rgb2col(255,255,255);
		if (dlist[i].type & TYPE_DIR) {
				col = rgb2col(255,255,0);
			}
			if (i==dlist_curpos) {
				col = rgb2col(255,0,0);
			}
			strncpy(path_tmp,dlist[i].name,40);
			mh_print(32,((i-dlist_start)+2)*10,path_tmp,col,0,0);
		}
		i++;
}
    pgScreenFlipV();
}

void pgFillvram(unsigned long color)
{
	unsigned char *vptr0;		//pointer to vram
	unsigned long i;

	vptr0=pgGetVramAddr(0,0);
	for (i=0; i<FRAMESIZE/2; i++) {
		*(unsigned short *)vptr0=color;
		vptr0+=PIXELSIZE*2;
	}

}

unsigned short rgb2col(unsigned char r,unsigned char g,unsigned char b) {
	return ((((b>>3) & 0x1F)<<10)+(((g>>3) & 0x1F)<<5)+(((r>>3) & 0x1F)<<0)+0x8000);
}

void Read_Key2() {
	static int n=0;
	sceCtrlReadBufferPositive(&ctl, 1);

	if (ctl.Ly >= 0xD0) ctl.Buttons|=PSP_CTRL_DOWN;  // DOWN
	if (ctl.Ly <= 0x30) ctl.Buttons|=PSP_CTRL_UP;    // UP
	if (ctl.Lx <= 0x30) ctl.Buttons|=PSP_CTRL_LEFT;  // LEFT
	if (ctl.Lx >= 0xD0) ctl.Buttons|=PSP_CTRL_RIGHT; // RIGHT

	now_pad = ctl.Buttons;
	new_pad = now_pad & ~old_pad;
	if(old_pad==now_pad){
		n++;
		if(n>=25){
			new_pad=now_pad;
			n = 20;
		}
	}else{
		n=0;
		old_pad = now_pad;
	}
}

int Control(void) {
	
	int i;

	Read_Key2();
	pgWaitV();
	
	if (new_pad & PSP_CTRL_UP) {
		if (dlist_curpos > 0) {
			dlist_curpos--;
			if (dlist_curpos < dlist_start) { dlist_start = dlist_curpos; }
		}
	}
	if (new_pad & PSP_CTRL_DOWN) {
		if (dlist_curpos < (dlist_num-1)) {
			dlist_curpos++;
			if (dlist_curpos >= (dlist_start+PATHLIST_H)) { dlist_start++; }
		}
	}
	if (new_pad & PSP_CTRL_LEFT) {
		dlist_curpos -= PATHLIST_H;
		if (dlist_curpos <  0)          { dlist_curpos = 0;           }
		if (dlist_curpos < dlist_start) { dlist_start = dlist_curpos; }
	}
	if (new_pad & PSP_CTRL_RIGHT) {
		dlist_curpos += PATHLIST_H;
		if (dlist_curpos >= dlist_num) { dlist_curpos = dlist_num-1; }
		while (dlist_curpos >= (dlist_start+PATHLIST_H)) { dlist_start++; }
	}

	if (new_pad & PSP_CTRL_CIRCLE) {
		if (dlist[dlist_curpos].type & TYPE_DIR) {
			if (now_depth<MAXDEPTH) {
				// pathÚ®
				strcat(doomwaddir2,dlist[dlist_curpos].name);
				strcat(doomwaddir2,"/");
				cbuf_start[now_depth] = dlist_start;
				cbuf_curpos[now_depth] = dlist_curpos;
				dlist_start  = 0;
				dlist_curpos = 0;
				now_depth++;
				return 1;
			}
		} else {
			//
			return 2;
			for(i=0;i<MAXPATH;i++) {
				if (dlist[dlist_curpos].name[i]==0) break;
			}
			if (i>2) {
				if (((dlist[dlist_curpos].name[i-3] & 0xDF) == '.') &&
				    ((dlist[dlist_curpos].name[i-2] & 0xDF) == 'G') &&
				    ((dlist[dlist_curpos].name[i-1] & 0xDF) == 'B')) {
					return 2;
				}
				i--;
			}
		}
	}
	if (new_pad & PSP_CTRL_CROSS) {
		if (now_depth > 0) {
			// pathÚ®
			for(i=0;i<MAXPATH;i++) {
				if (doomwaddir2[i]==0) break;
			}
			i--;
			while(i>4) {
				if (doomwaddir2[i-1]=='/') {
					doomwaddir[i]=0;
					break;
				}
				i--;
			}
			now_depth--;
			dlist_start  = cbuf_start[now_depth];
			dlist_curpos = cbuf_curpos[now_depth];
			return 1;
		}
	}
	
	return 0;
}

void pgWaitV()
{
	sceDisplayWaitVblankStart();
}
