// Copyright 2024 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/framebuffer.h"
#include "pw_framebuffer/writer.h"

using pw::color::color_rgb565_t;
using pw::framebuffer::FramebufferWriter;
using pw::geometry::Vector2;

namespace pw::draw {

TextArea::TextArea(pw::framebuffer::Framebuffer& fb, const FontSet& font)
    : font_(font), framebuffer_(fb) {
  // SetFont(font);
  // Default colors: White on Black
  character_wrap_enabled_ = true;
  foreground_color_ = 0xFFFF;
  background_color_ = 0;
  SetCursor(0, 0);
}

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_ + font_.width;
  column_count_++;
}

void TextArea::InsertLineBreak() {
  cursor_y_ = cursor_y_ + font_.height;
  cursor_x_ = cursor_x_ - (column_count_ * font_.width);
  column_count_ = 0;

  if (cursor_y_ >= framebuffer_.size().height) {
    ScrollUp(1);
    cursor_y_ = cursor_y_ - font_.height;
  }
}

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

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

  if (character_wrap_enabled_ &&
      (font_.width + cursor_x_) > framebuffer_.size().width) {
    InsertLineBreak();
  }

  pw::draw::DrawCharacter(character,
                          Vector2<int>{cursor_x_, cursor_y_},
                          foreground_color_,
                          background_color_,
                          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 = font_.starting_character; c <= font_.ending_character; c++) {
    int index = c - 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 * font_.height;
  int start_x = 0;
  int start_y = pixel_height;

  FramebufferWriter writer(framebuffer_);
  for (int current_x_ = 0; current_x_ < framebuffer_.size().width;
       current_x_++) {
    for (int current_y_ = start_y; current_y_ < framebuffer_.size().height;
         current_y_++) {
      if (auto pixel_color = writer.GetPixel(current_x_, current_y_);
          pixel_color.ok()) {
        writer.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_.size().width; x++) {
    for (int y = framebuffer_.size().height - pixel_height;
         y < framebuffer_.size().height;
         y++) {
      writer.SetPixel(x, y, background_color_);
    }
  }
}

}  // namespace pw::draw
