// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_draw/text_area.h"

#include "pw_color/color.h"
#include "pw_draw/draw.h"
#include "pw_draw/font_set.h"
#include "pw_framebuffer/rgb565.h"

using pw::color::color_rgb565_t;
using pw::coordinates::Vector2;

namespace pw::draw {

TextArea::TextArea(pw::framebuffer::FramebufferRgb565& fb, const FontSet* font)
    : framebuffer(fb) {
  SetFont(font);
  // Default colors: White on Black
  character_wrap_enabled = true;
  foreground_color = 0xFFFF;
  background_color = 0;
  SetCursor(0, 0);
}

// Change the current font.
void TextArea::SetFont(const FontSet* new_font) { current_font = new_font; }

void TextArea::SetCursor(int x, int y) {
  cursor_x = x;
  cursor_y = y;
  column_count = 0;
}

void TextArea::SetForegroundColor(color_rgb565_t color) {
  foreground_color = color;
}

void TextArea::SetBackgroundColor(color_rgb565_t color) {
  background_color = color;
}

void TextArea::SetCharacterWrap(bool new_setting) {
  character_wrap_enabled = new_setting;
}

void TextArea::MoveCursorRightOnce() {
  cursor_x = cursor_x + current_font->width;
  column_count++;
}

void TextArea::InsertLineBreak() {
  cursor_y = cursor_y + current_font->height;
  cursor_x = cursor_x - (column_count * current_font->width);
  column_count = 0;

  if (cursor_y >= framebuffer.GetHeight()) {
    ScrollUp(1);
    cursor_y = cursor_y - current_font->height;
  }
}

void TextArea::DrawCharacter(int character) {
  if (character == '\n') {
    InsertLineBreak();
    return;
  }

  if ((int)character < current_font->starting_character ||
      (int)character > current_font->ending_character) {
    // Unprintable character
    MoveCursorRightOnce();
    return;
  }

  if (character_wrap_enabled &&
      (current_font->width + cursor_x) > framebuffer.GetWidth()) {
    InsertLineBreak();
  }

  pw::draw::DrawCharacter(character,
                          Vector2<int>{cursor_x, cursor_y},
                          foreground_color,
                          background_color,
                          *current_font,
                          framebuffer);

  // Move cursor to the right by 1 glyph.
  MoveCursorRightOnce();
}

void TextArea::DrawCharacter(int character, int x, int y) {
  SetCursor(x, y);
  DrawCharacter(character);
}

void TextArea::DrawTestFontSheet(int character_column_width, int x, int y) {
  SetCursor(x, y);
  for (int c = current_font->starting_character;
       c <= current_font->ending_character;
       c++) {
    int index = c - current_font->starting_character;
    if (index > 0 && index % character_column_width == 0) {
      DrawCharacter('\n');
    }
    DrawCharacter(c);
  }
}

// DrawText at x, y (upper left pixel of font). Carriage returns will move
// text to the next line.
void TextArea::DrawText(const char* str) {
  for (const char* ch = str; *ch != '\0'; ch++) {
    DrawCharacter(*ch);
  }
}

void TextArea::DrawText(const char* str, int x, int y) {
  SetCursor(x, y);
  DrawText(str);
}

void TextArea::DrawText(const wchar_t* str) {
  for (const wchar_t* ch = str; *ch != L'\0'; ch++) {
    DrawCharacter(*ch);
  }
}

void TextArea::DrawText(const wchar_t* str, int x, int y) {
  SetCursor(x, y);
  DrawText(str);
}

void TextArea::ScrollUp(int lines) {
  int pixel_height = lines * current_font->height;
  int start_x = 0;
  int start_y = pixel_height;

  for (int current_x = 0; current_x < framebuffer.GetWidth(); current_x++) {
    for (int current_y = start_y; current_y < framebuffer.GetHeight();
         current_y++) {
      if (auto pixel_color = framebuffer.GetPixel(current_x, current_y);
          pixel_color.ok()) {
        framebuffer.SetPixel(
            start_x + current_x, current_y - start_y, *pixel_color);
      }
    }
  }

  // Draw a filled background_color rectangle at the bottom to erase the old
  // text.
  for (int x = 0; x < framebuffer.GetWidth(); x++) {
    for (int y = framebuffer.GetHeight() - pixel_height;
         y < framebuffer.GetHeight();
         y++) {
      framebuffer.SetPixel(x, y, background_color);
    }
  }
}

}  // namespace pw::draw
