#include "interrupt/apic_timer.h"

#include "debug/debug.h"
#include "interrupt/apic.h"
#include "interrupt/timer.h"

const uint32_t kScheduleFrequency = 20;
ApicTimer* gApicTimer = nullptr;

void ApicTimer::Init() {
  gApicTimer = new ApicTimer();
  gApicTimer->StartCalibration();
  asm("sti;");
  gApicTimer->WaitCalibration();
  asm("cli;");
}

void ApicTimer::StartCalibration() {
  SetFrequency(100);
  gApic->InitializeLocalTimer(0xFFFFFFFF, Apic::ONESHOT);
  gApic->UnmaskPit();
}

void ApicTimer::Calibrate() {
  if (calibration_.initial_measurement == 0) {
    calibration_.initial_measurement = gApic->GetLocalTimerValue();
    return;
  }
  calibration_.tick_count++;

  if (calibration_.tick_count == 10) {
    calculated_frequency_ =
        10 * (calibration_.initial_measurement - gApic->GetLocalTimerValue());
    FinishCalibration();
  }
}

void ApicTimer::FinishCalibration() {
  gApic->MaskPit();
  gApic->InitializeLocalTimer(calculated_frequency_ / kScheduleFrequency,
                              Apic::PERIODIC);
}