// SPDX-License-Identifier: MPL-2.0
#include "kernel/efifb.h"
sh_uint32 fb_height=0;
sh_uint32 fb_width=0;
sh_uint32 fb_size_bytes=0;
sh_uint32 fb_white=0;
sh_uint32 fb_gray=0;
sh_bool fb_present=SH_FALSE;
sh_uint32 *fb_base=SH_NULLPTR;
sh_uint16 bar_x0=0;
sh_uint16 bar_y0=0;
sh_uint16 bar_x1=0;
sh_uint16 bar_y1=0;
static SH_STATUS sh_efifb_fill_rectangle(sh_uint32 x,sh_uint32 y,sh_uint32 width,sh_uint32 height,sh_uint32 pixel_value) {
  if (fb_base==SH_NULLPTR) return SH_STATUS_VA_NOT_MAPPED;
  sh_uint32 end_x=x+width;
  sh_uint32 end_y=y+height;
  if (x>=fb_width || y>=fb_height) return SH_STATUS_BAD_SIZE;
  if (end_x>fb_width) end_x=fb_width;
  if (end_y>fb_height) end_y=fb_height;
  for (sh_uint32 curr_y=y;curr_y<end_y;curr_y++) {
    sh_uint32 *line=fb_base+(curr_y*fb_width);
    for (sh_uint32 curr_x=x;curr_x<end_x;curr_x++) {
      line[curr_x]=pixel_value;
    }
  }
  return SH_STATUS_SUCCESS;
}
static void sh_efifb_draw_rounded_bar(sh_uint32 x0,sh_uint32 y0,sh_uint32 x1,sh_uint32 y1,sh_uint32 r,sh_uint32 color) {
  if (x1-x0<=r*2) {
    x1=x0+r*2;
  }
  for (sh_uint32 y=y0;y<=y1;y++) {
    for (sh_uint32 x=x0;x<=x1;x++) {
      sh_bool in_rect=(x>=x0+r && x<=x1-r);
      if (in_rect) {
        fb_base[fb_width*y+x]=color;
        continue;
      }
      sh_uint32 cxL=x0+r;
      sh_uint32 cy=y0+r;
      sh_uint32 cxR=x1-r;
      sh_uint32 dx,dy;
      dx=x-cxL;
      dy=y-cy;
      if (dx*dx+dy*dy<=r*r) {
        fb_base[fb_width*y+x]=color;
        continue;
      }
      dx=x-cxR;
      dy=y-cy;
      if (dx*dx+dy*dy<=r*r) {
        fb_base[fb_width*y+x]=color;
        continue;
      }
    }
  }
}
SH_STATUS sh_efifb_init_fb(sh_conf_FB_CONFIG *fb_conf,sh_page_PAGE_TABLE_POOL *ptp) {
  if (fb_conf==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
  if (!fb_conf->fb_present) return SH_STATUS_SUCCESS;
  fb_height=fb_conf->fb_height;
  fb_width=fb_conf->fb_width;
  fb_size_bytes=fb_width*fb_height*sizeof(sh_uint32);
  if (fb_size_bytes!=fb_conf->size_in_bytes) return SH_STATUS_BAD_SIZE;
  SH_STATUS status=sh_page_map_contiguous_pages_range_ptp(ptp,fb_conf->fb_pa,fb_conf->fb_pa,SH_PAGE_PRESENT | SH_PAGE_RW | SH_PAGE_NX | SH_PAGE_PCD,(((fb_size_bytes+4096)/4096)*4096));
  if (sh_status_error(status)) return status;
  fb_white=fb_conf->white_pixel_value;
  fb_gray=fb_conf->gray_pixel_value;
  fb_base=(sh_uint32*)fb_conf->fb_pa;
  fb_present=SH_TRUE;
  status=sh_efifb_fill_rectangle(fb_conf->text_x,fb_conf->text_y,fb_conf->text_width,fb_conf->text_height,0);
  return SH_STATUS_SUCCESS;
}
SH_STATUS sh_efifb_init_bar() {
  if (!fb_present) return SH_STATUS_SUCCESS;
  bar_x0=(sh_uint16)(fb_width*0.3);
  bar_x1=(sh_uint16)(fb_width-bar_x0);
  bar_y0=(sh_uint16)(fb_height*0.93);
  bar_y1=(sh_uint16)(fb_height*0.96);
  sh_efifb_draw_rounded_bar(bar_x0,bar_y0,bar_x1,bar_y1,(bar_y1-bar_y0)/2U,fb_gray);
  sh_efifb_draw_rounded_bar(bar_x0+3,bar_y0+3,bar_x1-3,bar_y1-3,((bar_y1-3U)-(bar_y0+3U))/2U,0);
  return SH_STATUS_SUCCESS;
}
SH_STATUS sh_efifb_set_bar(sh_uint8 percent) {
  if (!fb_present) return SH_STATUS_SUCCESS;
  sh_uint16 bar_width=(sh_uint16)((bar_x1-3U)-(bar_x0+3U));
  sh_uint16 bar_percent=(sh_uint16)(((double)percent/100)*(double)(bar_width));
  sh_uint16 bar_xp=(sh_uint16)(bar_x0+3U+bar_percent);
  sh_efifb_fill_rectangle(bar_x0,bar_y0,(bar_x1-bar_x0),(bar_y1-bar_y0),0);
  sh_efifb_draw_rounded_bar(bar_x0,bar_y0,bar_x1,bar_y1,(bar_y1-bar_y0)/2U,fb_gray);
  sh_efifb_draw_rounded_bar(bar_x0+3,bar_y0+3,bar_x1-3,bar_y1-3,((bar_y1-3U)-(bar_y0+3U))/2U,0);
  sh_efifb_draw_rounded_bar(bar_x0+3,bar_y0+3,bar_xp,bar_y1-3,((bar_y1-3U)-(bar_y0+3U))/2U,fb_white);
  return SH_STATUS_SUCCESS;
}
