/* (C) Copyright 2009 WiiGator */
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <gctypes.h>
#include <ogc/cache.h>
#include <ogcsys.h>
#include <gccore.h>
#include <string.h>
#include <ogc/lwp_watchdog.h>
#include <ogc/cache.h>

#include "dvd.h"
#include "gameloader.h"
#include "debugprintf.h"
#include "loadapp.h"
#include "screen.h"
#include "dvdreadpatch.h"
#include "systemconfig.h"
#include "video.h"
#include "Toy.h"
#include "patchcode.h"

unsigned long second_disc_idx;

extern u32 hookselect;
extern u32 hook2select;
extern u32 ocarinaselect;
extern u32 debuggerselect;


void Con_ClearLine(void)
{
	s32 cols, rows;
	u32 cnt;

	printf("\r");
	fflush(stdout);

	CON_GetMetrics(&cols, &rows);

	for (cnt = 1; cnt < cols; cnt++) {
		printf(" ");
		fflush(stdout);
	}

	printf("\r");
	fflush(stdout);
}


void start_from_NeoGamma(void)
{
	base_offset = 0;
	int rv;
	u8 reloader;
	u8 high;
	u32 errornumber;
	
	base_offset = *(u32 *)0x807FFF20;
	second_disc_offset = *(u32 *)0x807FFF24;
	set_patchmode(*(u8 *)0x807FFF30);
	reloader = *(u8 *)0x807FFF34;
	high = *(u8 *)0x807FFF36;

	set_codes_settings(*(u8 *)0x807FFF31, *(u8 *)0x807FFF32, *(u8 *)0x807FFF33, *(u8 *)0x807FFF35);

	wii_dvd_reset_unlock();

	// check if the disc is a backup or retail
	dvd_read_id();

	// Do a reset for retail discs, otherwise the audio streaming doesn't work properly
	if (!backuploading)
	{
		printf("Resetting the drive...");
		
		ack_cover_interrupt();
		dvd_reset();

		unsigned int cvstatus;
		// Wait until reset is finished.
		do {
			cvstatus = get_cover_status();
		} while ((cvstatus & 0x01) != 0);
		
		dvd_read_id();

		Con_ClearLine();
	}
	
	if (backuploading)
	{
		printf("Loading backup disc...\n");
	} else
	{
		printf("Loading retail disc...\n");
	}

	u32 streaming = dvd_set_streaming();
		
	if (streaming > 0)
	{
		errornumber = dvd_get_error();
		if (errornumber != 0)
		{
			streaming += 2;
			dvd_disable_streaming();
		}		
	}

	errornumber = dvd_get_error();
	if (errornumber != 0)
	{
		//The audio streaming always causes an error on backups
		if (!backuploading)
		{
			printf("DVD Error: 0x%x\n", errornumber);
			sleep(5);
		}
		dvd_get_error();
	}

	// Read the name of the game
	static dvdinfo_t gcm_disk __attribute((aligned(32)));
	rv = dvd_read(&gcm_disk, sizeof(gcm_disk), 0);
	DVD_CHECK();

	char discid[7];
	memset(discid, 0, 7);
	memcpy(discid, (void *) GAMECODE_ADDRESS, 6);
	
	printf("DiscID: %s, Name: %s\n", discid, gcm_disk.GameName);
	debug_printf("DiscID: %s, Name: %s\n", discid, gcm_disk.GameName);

	if (streaming == 0)
	{
		printf("No audio streaming\n");
	} else
	if (backuploading)
	{
		printf("The game has audio streams, expect missing audio\n");
	} else
	switch(streaming)
	{
		case 1:
			printf("Enabled audio streaming with default streaming size\n");
		break;
		
		case 2:
			printf("Enabled audio streaming with 10 bytes streaming size\n");
		break;
		
		case 3:
			printf("Audio streaming with default streaming size failed\n");
		break;

		case 4:
			printf("Audio streaming with 10 bytes streaming size failed\n");
		break;
	}

#ifdef DONTTELL
	if ( (hookselect != 0 || hook2select != 0) && (ocarinaselect != 0 || debuggerselect != 0))
#else
	if (!backuploading && hookselect != 0 && (ocarinaselect != 0 || debuggerselect != 0))
#endif
	{
		if (ocarinaselect != 0)
		{
			// Copy codes now before the memory is cleared
			memcpy((void *)0x800027B0, (void *)0x807FF6B0, 0x0850);
		} else
		{
			// Clear codes area for debugger
			memset((void *)0x800027B0, 0, 0x0850);
		}
	}

	u32 mode;
	
	switch (*(u32 *)0x807FFF28)	// video mode
	{
		case 0:	// Video Mode Wii
			if (*(u32 *)0x807FFF2C == 0)	// region: NTSC
			{
				mode = VIDEO_MODE_NTSC;
			} else							// region: PAL
			{
				if (gcm_disk.CountryCode == 'E' || gcm_disk.CountryCode == 'J')
				{
					mode = VIDEO_MODE_PAL60;
				} else
				{
					mode = VIDEO_MODE_PAL;		// PAL games can't be booted with PAL60...
				}
			}
		break;
		
		case 2:	// NTSC480i
			mode = VIDEO_MODE_NTSC;
		break;
		
		case 3:	// NTSC480p
			mode = VIDEO_MODE_NTSC480P;
		break;
		
		case 4:	// PAL(auto)
			if (gcm_disk.CountryCode == 'E' || gcm_disk.CountryCode == 'J')
			{
				mode = VIDEO_MODE_PAL60;
			} else
			{
				mode = VIDEO_MODE_PAL;		// PAL games can't be booted with PAL60...
			}
		break;	
		
		case 5:	// PAL576i
			mode = VIDEO_MODE_PAL;
		break;
		
		case 6:	// PAL480i
			mode = VIDEO_MODE_PAL60;
		break;
		
		case 7:	// PAL480p
			mode = VIDEO_MODE_PAL480P;
		break;

		case 1:	// video Mode Disc
		default:
			mode = gcm_disk.CountryCode;
		break;
	}
	
	setup_video(mode);	// Also clears memory
	load_app(reloader, high);
}
