#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include "Scheduler.h"

#include "../Cpu/Gdt/Gdt.h"
#include "Process.h"


void Schedule(void){
	uint32_t* stack_ptr;
	uint32_t esp0, eflags;
	uint16_t ss, cs;
	asm("mov (%%ebp), %%eax; mov %%eax, %0" : "=m" (stack_ptr) : );

	if (current == 0 && n_proc) {
		current = &p_list[0];
	}

	else if (n_proc <= 1) {
		return;
	}

	else if (n_proc>1) {

		current->regs.eflags = stack_ptr[16];
		current->regs.cs  = stack_ptr[15];
		current->regs.eip = stack_ptr[14];
		current->regs.eax = stack_ptr[13];
		current->regs.ecx = stack_ptr[12];
		current->regs.edx = stack_ptr[11];
		current->regs.ebx = stack_ptr[10];
		current->regs.ebp = stack_ptr[8];
		current->regs.esi = stack_ptr[7];
		current->regs.edi = stack_ptr[6];
		current->regs.ds = stack_ptr[5];
		current->regs.es = stack_ptr[4];
		current->regs.fs = stack_ptr[3];
		current->regs.gs = stack_ptr[2];

		current->regs.esp = stack_ptr[17];
		current->regs.ss = stack_ptr[18];
		

		DefaultTss.esp0 = (uint32_t) (stack_ptr + 19);

		if (n_proc > current->pid+1)
			current = &p_list[current->pid+1];
		else 
			current = &p_list[0];
	}

	ss = current->regs.ss;
	cs = current->regs.cs;
	eflags = (current->regs.eflags | 0x200) & 0xFFFFBFFF;
	esp0 = DefaultTss.esp0;
	
	asm("	mov %0, %%esp; \
		push %1; \
		push %2; \
		push %3; \
		push %4; \
		push %5; \
		push %6; \
		ljmp $0x08, $DoSwitch" \
		:: \
		"m" (esp0), \
		"m" (ss), \
		"m" (current->regs.esp), \
		"m" (eflags), \
		"m" (cs), \
		"m" (current->regs.eip), \
		"m" (current)
	);
}
