#ifndef _PA_Main
#define _PA_Main

#ifdef __cplusplus
extern "C" {
#endif


#include "../../PA_Config.h"


#ifdef USE_8BITTEXT  
	#define TEXT_ALLSIZES   
#endif


#include <nds.h>
#include <nds/memory.h>
#include <nds/bios.h>
#include <malloc.h>

extern u8 PA_Screen;

typedef struct {
   u8 NoIdea; 
   u8 Year;
   u8 Month;
   u8 Day;
   u8 NoIdea2;
   u8 Hour;
   u8 Minutes;
   u8 Seconds;
} RTC;
extern RTC PA_RTC;

extern inline void PA_WaitForVBL(void);

extern s16 PA_ScreenSpace; // Espace entre les 2 écrans...+192

#define BG_GFX1			0x6000000
#define BG_GFX2			0x6200000
#define SPRITE_GFX1		0x6400000
#define SPRITE_GFX2		0x6600000


//Pour le DMA Copy...
#define REG_DMA3SRC *(volatile u32*)0x040000D4
#define REG_DMA3DST *(volatile u32*)0x040000D8
#define REG_DMA3CNT *(volatile u32*)0x040000DC
#define DMA_ON 0x80000000
#define DMA_NOW 0x00000000
#define DMA_16 0x00000000
#define DMA_32 0x04000000
#define DMA_16NOW (DMA_ON | DMA_NOW | DMA_16)
#define DMA_32NOW (DMA_ON | DMA_NOW | DMA_32)
#define DMA_Copy(source, dest, count, mode) {REG_DMA3SRC = (u32)source; REG_DMA3DST = (u32)dest; REG_DMA3CNT = (count) | (mode);}

#define DMA_Clear(dest, count, mode) {REG_DMA3SRC = (u32)Blank; REG_DMA3DST = (u32)dest; REG_DMA3CNT = (count) | (mode);}

#define DMA_Force(ulVal,dest, count, mode) {REG_DMA3SRC=(u32)&ulVal; REG_DMA3DST = (u32)dest; REG_DMA3CNT = (count) |(mode) | DMA_SRC_FIX;}

// Commandes pour la lumière des écrans
#define BACKLIGHT(screen)	BIT(2+screen)

#define ALWAYSINLINE __attribute__((always_inline)) static inline





#include <stdarg.h> // Pour le système de text
#include <string.h>

#include "gbfs.h"
#include "gba-jpeg-decode.h"
#include "Sound9.h"


#define _REG8 *(volatile u16 *)
#define _REG16 *(volatile u16 *)
#define _REG32 *(volatile u32 *)

#include "arm9/vidfile.h"
#include "arm9/PA_Sprite.h"
#include "arm9/PA_SpriteDual.h"
#include "arm9/PA_Sound.h"
#include "arm9/PA_Micro.h"
#include "arm9/PA_Draw.h"
#include "arm9/PA_Interrupt.h"
#include "arm9/PA_Keys.h"

#include "arm9/PA_Timer.h"

#ifdef TEXT_ALLSIZES
	#include "arm9/PA_API.h"  // API only if has text...
#endif

#include "arm9/PA_Math.h"
#include "arm9/PA_Palette.h"
#include "arm9/PA_PaletteDual.h"
#include "arm9/PA_Save.h"
#include "arm9/PA_FS.h"
#include "arm9/PA_GBFS.h"
#include "arm9/PA_SpecialFx.h"

#include "arm9/PA_Tile.h"
#include "arm9/PA_TileDual.h"

#include "arm9/PA_FAT.h"  // fat driver by chrishm

#ifdef USE_KEYBOARD
	#include "arm9/PA_Keyboard.h"
#endif

#include "arm9/PA_Text.h"
#include "arm9/PA_Window.h"

#include "arm9/PA_Mode7.h"

#ifdef USE_3D
	#include "arm9/PA_3D.h"
#endif


#include "arm9/PA_IA.h"
#include "arm9/PA_Reco.h"


#include "arm9/PA_16c.h"


#define SWITCH_SCREENS  (1<<15)



#define N_HBLS 263



/*! \file PA9.h
    \brief Contains prototypes and macros... for the arm9

    Contains prototypes and macros... for the arm9
*/



//extern u32 *Blank;
extern u32 Blank[130000>>2];






//////////////////////////////////////////////////////////////////////
// Général
//////////////////////////////////////////////////////////////////////

#define SIZEOF_8BIT(x)          (sizeof(x))
#define SIZEOF_16BIT(x)         (sizeof(x)>>1)
#define SIZEOF_32BIT(x)         (sizeof(x)>>2)




#define CODE_IN_IWRAM __attribute__ ((section (".iwram"), long_call))
#define IN_IWRAM __attribute__ ((section (".iwram")))
#define CODE_IN_EWRAM __attribute__ ((section (".ewram"), long_call))
#define IN_EWRAM __attribute__ ((section (".ewram")))
#define PACKED __attribute__ ((packed))







// Jpeg functions :
void PA_jpeg_GetImageSize(char* name, int* width, int* height);
void PA_jpeg_BltImage(char* name, u16* vram, int output_width, int output_height);

extern const s16 PA_SIN[512];



typedef struct {
   u8 Color;  // Favorite Color
   u8 BdayMonth; // Mois d'anniversaire
   u8 BdayDay;  // Jour de naissance
   u8 AlarmHour;
   u8 AlarmMinute;
   u8 Name[21];
   u8 NameLength;
   u8 Message[53];
   u8 MessageLength;
   u8 Language; // Langue... 0 pour Jap, 1 pour anglais, 2 pour francais...
} infos;
extern infos PA_UserInfo;

#define INFO_COLOR *(u8*)0x027FFC82
#define INFO_BDAY_MONTH *(u8*)0x027FFC83
#define INFO_BDAY_DAY *(u8*)0x027FFC84
#define INFO_ALARM_HOUR *(u8*)0x027FFCD2
#define INFO_ALARM_MINUTE *(u8*)0x027FFCD3
#define INFO_NAME *(u8*)0x027FFC86
#define INFO_NAME_LENGTH *(u8*)0x027FFC9A
#define INFO_MESSAGE *(u8*)0x027FFC9C
#define INFO_MESSAGE_LENGTH *(u8*)0x027FFCD0
#define INFO_LANGUAGE  *(u8*)(0x027FFCE4)


/** @defgroup General General Functions
 *  Initialise the lib, and other general functions...
 *  @{
 */


/*! \fn void PA_Init(void)
    \brief
         \~english Initialise the library. Must be used at the beginning or main()
         \~french Initialise la lib... Doit etre placé au début de main()
*/
void PA_Init(void);



/*! \fn extern inline void PA_SetVideoMode(u8 screen, u8 mode)
    \brief
         \~english Change the video mode... Use this with caution
         \~french Changer de mode video... A utiliser avec précaution
    \param screen
         \~english Screen...
         \~french Ecran...
    \param mode
         \~english Mode 0 for normal, 1 for 1 rotating backgrounds, 2 for 2
         \~french Mode 0 pour normal, 1 pour 1 fond rotatif, 2 pour 2
*/
extern inline void PA_SetVideoMode(u8 screen, u8 mode) {
	(*(vuint32*)(0x04000000 + (0x1000 * screen))) &= ~7;
	(*(vuint32*)(0x04000000 + (0x1000 * screen))) |= mode;
}



/*! \fn void PA_UpdateUserInfo(void)
    \brief
         \~english Updates the user info. This is automatically done in PA_Init. You can then get any info with the following variables : PA_UserInfo.Color (favorite color), .BdayDay, .BdayMonth, .AlarmHour, .AlarmMinute, .Name, .NameLength, .Message, .MessageLength, .Language
         \~french Met à jour les infos sur l'utilisateur... C'est fait automatiquement dans PA_Init. On peut ensuite récupérer toutes les infos avec PA_UserInfo.Color (couleur favorite), .BdayDay, .BdayMonth, .AlarmHour, .AlarmMinute, .Name, .NameLength, .Message, .MessageLength, .Language
*/
void PA_UpdateUserInfo(void);


/*! \fn void PA_UpdateRTC(void)
    \brief
         \~english Updates the Real Time Clock, with info on the current date and hour. Automatically updated in the PA VBL... Get the info with PA_RTC.Minutes, .Hour, .Seconds, .Day, .Month, and .Year
         \~french Met à jour les infos sur l'heure et la date. C'est automatiquement mis à jour dans le VBL PA... On récupère les infos avec PA_RTC.Minutes, .Hour, .Seconds, .Day, .Month, et .Year
*/
void PA_UpdateRTC(void);


/*! \fn void PA_LoadSplash(void)
    \brief
         \~english Load a PlayerAdvance splash screen... It's always nice to give some credit ;)
         \~french Affiche un splash screen PlayerAdvance... C'est toujours sympa de remercier ;)


*/
void PA_LoadSplash(void);


/*! \fn void PA_LoadSplash()
    \brief
         \~english Load a NeoFlash splash screen...
         \~french Affiche un splash screen NeoFlash
*/
void PA_NeoSplash(void);



/*! \fn extern inline void PA_WaitForVBL(void)
    \brief
         \~english Wait for the VBlank to occur
         \~french Attendre le vbl...
*/
extern inline void PA_WaitForVBL(void){
swiWaitForVBlank();
}



/*! \fn extern inline void PA_SwitchScreens(void)
    \brief
         \~english Switch the bottom and top screens...
         \~french Echange les écrans du haut et du bas
*/
extern inline void PA_SwitchScreens(void) {
POWER_CR ^= SWITCH_SCREENS; 
PA_Screen = !PA_Screen;
}


/*! \fn extern inline void PA_InitCPUMeter()
    \brief
         \~english BROKEN ----- Initialises the CPU Meter. The CPU value is saved in PA_CPU (and PA_MaxCPU for max usage)
         \~french BROKEN ----- Initialise le compteur CPU. La valeur (en %) est sauvée dans PA_CPU (et le plus gros dans PA_MaxCPU)
*/
extern inline void PA_InitCPUMeter() {
	PA_CPU = 0; 
	PA_MaxCPU = 0; 
	PA_lines = 0; 
	PA_VBLCount = 0;
	PA_nVBLs = 0;
}





/*! \def PA_LidClosed()
    \brief
         \~english Check if the DS is closed. Returns 0 if open, 1 if closed
         \~french Vérifie si la DS est fermée. Renvoie 0 si ouverte, 1 si fermée
*/
#define PA_LidClosed() (IPC->buttons>>7)


/*! \fn extern inline u8 PA_CheckLid(void)
    \brief
         \~english Check if the DS is closed. If closed, it pauses the DS, and returns 1.
         \~french Vérifie si la DS est fermée. Si fermée, ca met en pause la DS et renvoie 1.
*/
extern inline u8 PA_CheckLid(void) {

if (!PA_LidClosed()) return 0;
else {
	u16 power_cr = POWER_CR; // backup the power...
	POWER_CR = 0; // Shutdown everything :p
	
	// Wait for the lid to be opened again...
	while(PA_LidClosed()) PA_WaitForVBL();
	
	// Return the power !
	POWER_CR = power_cr;
	return 1;
}

}





/*! \fn void PA_Splash(void* tiles0, void* map0, void* tiles1, void* map1, s16 color0, s16 color1, s16 time)
    \brief
         \~english Splash screen function ! Load your own splash screen...
         \~french Fonction Splash screen ! Permet de charger son propre splash screen...
    \param tiles0
         \~english Tiles of the splash to put on the bottom screen
         \~french Tiles du splash à afficher sur l'écran du bas
    \param map0
         \~english Map of the splash to put on the bottom screen
         \~french Map du splash à afficher sur l'écran du bas
    \param tiles1
         \~english Tiles of the splash to put on the top screen
         \~french Tiles du splash à afficher sur l'écran du haut
    \param map1
         \~english Map of the splash to put on the top screen
         \~french Map du splash à afficher sur l'écran du haut
    \param color0
         \~english Fade in color, 0 for balck, 1 for white.
         \~french Couleur du fondu d'entrée : 0 pour noir, 1 pour blanc.
    \param color1
         \~english Fade out color, 0 for balck, 1 for white.
         \~french Couleur du fondu de sortie : 0 pour noir, 1 pour blanc.
    \param time
         \~english Time to stay on the splash if you do net press Start or use the Stylus, in VBLs -> 60 for 1 second, 300 for 5 seconds...
         \~french Le temps que le splash doit rester, si on n'appuye pas sur Start ou le Stylet, en VBLs -> 60 pour 1 seconde, 300 pour 5 secondes... 

*/
void PA_Splash(void* tiles0, void* map0, void* tiles1, void* map1, s16 color0, s16 color1, s16 time);


/*! \fn void PA_SetScreenLight(u8 screen, u8 light)
    \brief
         \~english Set on or off the screen's light
         \~french Allumer ou eteindre la lumière d'un écran
    \param screen
         \~english Screen...
         \~french Ecran...
    \param light
         \~english Light, 1 for on, 0 for off
         \~french Lumière, 1 pour allumé, 0 pour éteint
*/
extern inline void PA_SetScreenLight(u8 screen, u8 light){
	IPC->aux &= ~(1<<(2+screen));
	IPC->aux |= light<<(2+screen);
}


/*! \fn extern inline void PA_SetLedBlink(u8 blink, u8 speed)
    \brief
         \~english Set teh DS Led blinking
         \~french Régler le clignotement de la led
    \param blink
         \~english 1 for blinking, 0 for always on
         \~french 1 pour clignoter, 0 pour toujours allumé
    \param speed
         \~english Speed : 0 for slow, 1 for fast
         \~french Vitesse : 0 pour lent, 1 pour rapide
*/
extern inline void PA_SetLedBlink(u8 blink, u8 speed){
	IPC->aux &= ~(3<<4);
	IPC->aux |= (blink + (speed<<1))<<4;
}




/** @} */ // end of General


void PA_Nothing(void);


#ifdef __cplusplus
}
#endif
#endif



