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

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

namespace pw::draw {

TextArea::TextArea(pw::framebuffer::Framebuffer& 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.size().height) {
    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.size().width) {
    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;

  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
