/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.

	This file is part of Sortix.

	Sortix is free software: you can redistribute it and/or modify it under the
	terms of the GNU General Public License as published by the Free Software
	Foundation, either version 3 of the License, or (at your option) any later
	version.

	Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
	WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
	FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
	details.

	You should have received a copy of the GNU General Public License along
	with Sortix. If not, see <http://www.gnu.org/licenses/>.

	kernel.cpp
	A common interface shared by all devices that can be printed text to.

******************************************************************************/

#include "platform.h"
#include "globals.h"
#include "iprintable.h"
#include "log.h"
#include "panic.h"
#include "descriptor_tables.h"
#include "iirqhandler.h"
#include "timer.h"
#include "keyboard.h"
#include "shell.h"
#include "multiboot.h"
#include "memorymanagement.h"

// TODO: Move these to their own header!
inline void *operator new(size_t, void *p)     { return p; }
inline void *operator new[](size_t, void *p)   { return p; }
inline void  operator delete  (void *, void *) { };
inline void  operator delete[](void *, void *) { };

namespace Sortix
{
	void KernelConstructors()
	{
		GLog = new (GLog) Log;
		GPanic = new (GPanic) PanicClass;
		GTimer = new (GTimer) Timer;
		GKeyboard = new (GKeyboard) Keyboard;
		GShell = new (GShell) Shell;
	}

	extern "C" void KernelInit(unsigned long Magic, multiboot_info_t* BootInfo)
	{
		// Initialize the global object's by calling their constructors.
		KernelConstructors();

		// Initialize the kernel log.
		GLog->Init();

		if ( BootInfo == NULL ) { Panic("kernel.cpp: The bootinfo structure was NULL. Are your bootloader multiboot compliant?"); }

		// Initialize the paging system.
		GPaging->Init(BootInfo);

		// This is just debug stuff that can be safely removed.
		GLog->PrintF("Allocation test...\n");
		size_t Amount = 0;
		size_t Count = 0;
		void* OldPos = NULL;
		while ( true )
		{
			void* Pos = GPaging->Allocate();
			if ( Pos == NULL || ((uintptr_t) Pos) & 0x1 ) { break; }		
			Count++; Amount++;
			// Test
			if ( Count % 100 == 50 ) { OldPos = Pos; }
			if ( Count % 100 == 75 ) { GPaging->Free(OldPos); Amount--; }
			if ( Count % 20 == 0 ) { GPaging->Free(Pos); Amount--; }
		}
		GLog->PrintF("Done! (%z MiB successfully allocated!)\n", Amount * 0x1000 / 1024 / 1024);

		// Write out a sample string
		GLog->Print("Hello, world! This is the Sortix echo driver! (No backspace support)\n\n$ ");
		GLog->UpdateScreen();

		// Initialise all the ISRs and segmentation
		init_descriptor_tables();

		GTimer->Init();

		GKeyboard->Init();

		//GShell->Init();
		//GKeyboard->SetReader(GShell);

		int a = 1337;
		while ( true  ) { a++; }
	}
}
