/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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
 *
 *      http://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 "otautil/paths.h"
#include "recovery_ui/wear_ui.h"

#include <string.h>

#include <string>
#include <vector>

#include <android-base/properties.h>
#include <android-base/strings.h>

#include <minui/minui.h>

constexpr int kDefaultProgressBarBaseline = 259;
constexpr int kDefaultMenuUnusableRows = 9;
constexpr int kProgressBarVerticalOffsetDp = 72;
constexpr bool kDefaultIsScreenCircle = true;

WearRecoveryUI::WearRecoveryUI()
    : ScreenRecoveryUI(true),
      progress_bar_baseline_(android::base::GetIntProperty("ro.recovery.ui.progress_bar_baseline",
                                                           kDefaultProgressBarBaseline)),
      menu_unusable_rows_(android::base::GetIntProperty("ro.recovery.ui.menu_unusable_rows",
                                                        kDefaultMenuUnusableRows)),
      is_screen_circle_(android::base::GetBoolProperty("ro.recovery.ui.is_screen_circle",
                                                             kDefaultIsScreenCircle)) {
  // TODO: menu_unusable_rows_ should be computed based on the lines in draw_screen_locked().
  touch_screen_allowed_ = true;
}

// Draw background frame on the screen.  Does not flip pages.
// Should only be called with updateMutex locked.
// TODO merge drawing routines with screen_ui
void WearRecoveryUI::draw_background_locked() {
  pagesIdentical = false;
  gr_color(0, 0, 0, 255);
  gr_fill(0, 0, gr_fb_width(), gr_fb_height());

  if (current_icon_ == ERROR) {
    const auto& frame = GetCurrentFrame();
    int frame_width = gr_get_width(frame);
    int frame_height = gr_get_height(frame);
    int frame_x = (gr_fb_width() - frame_width) / 2;
    int frame_y = (gr_fb_height() - frame_height) / 2;
    gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
  }

  if (current_icon_ != NONE) {
    // Draw recovery text on screen centered
    const auto& text = GetCurrentText();
    int text_x = (ScreenWidth() - gr_get_width(text)) / 2;
    int text_y = (ScreenHeight() - gr_get_height(text)) / 2;
    gr_color(255, 255, 255, 255);
    gr_texticon(text_x, text_y, text);
  }
}

void WearRecoveryUI::draw_screen_locked() {
  if (!show_text) {
    draw_background_locked();
    if (is_screen_circle_) {
        draw_circle_foreground_locked();
    } else {
        draw_foreground_locked();
    }
    return;
  }

  SetColor(UIElement::TEXT_FILL);
  gr_clear();

  // clang-format off
  static std::vector<std::string> SWIPE_HELP = {
    "Swipe up/down to move.",
    "Swipe left/right to select.",
    "",
  };
  // clang-format on
  draw_menu_and_text_buffer_locked(SWIPE_HELP);
}

void WearRecoveryUI::draw_circle_foreground_locked() {
    if (current_icon_ != NONE) {
        const auto& frame = GetCurrentFrame();
        int frame_width = gr_get_width(frame);
        int frame_height = gr_get_height(frame);
        int frame_x = (ScreenWidth() - frame_width) / 2;
        int frame_y = GetAnimationBaseline();
        DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
      }

    if (progressBarType == DETERMINATE) {
        const auto& first_progress_frame = rtl_locale_ ? rtl_progress_frames_[0].get()
                                                        :progress_frames_[0].get();
        int width = gr_get_width(first_progress_frame);
        int height = gr_get_height(first_progress_frame);

        int progress_x = (ScreenWidth() - width) / 2;
        int progress_y = GetProgressBaseline();

        const auto index = GetProgressFrameIndex(progress);
        const auto& frame = rtl_locale_ ? rtl_progress_frames_[index].get()
                                        : progress_frames_[index].get();

        DrawSurface(frame, 0, 0, width, height, progress_x, progress_y);
    }
}

void WearRecoveryUI::LoadAnimation() {
  ScreenRecoveryUI::LoadAnimation();
  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(Paths::Get().resource_dir().c_str()),
                                                closedir);
  dirent* de;
  std::vector<std::string> progress_frame_names;
  std::vector<std::string> rtl_progress_frame_names;

  if(dir.get() == nullptr) abort();

  while ((de = readdir(dir.get())) != nullptr) {
    int value, num_chars;
    if (sscanf(de->d_name, "progress%d%n.png", &value, &num_chars) == 1) {
      progress_frame_names.emplace_back(de->d_name, num_chars);
    } else if (sscanf(de->d_name, "rtl_progress%d%n.png", &value, &num_chars) == 1) {
      rtl_progress_frame_names.emplace_back(de->d_name, num_chars);
    }
  }

  size_t progress_frames = progress_frame_names.size();
  size_t rtl_progress_frames = rtl_progress_frame_names.size();

  // You must have an animation.
  if (progress_frames == 0 || rtl_progress_frames == 0) abort();

  std::sort(progress_frame_names.begin(), progress_frame_names.end());
  std::sort(rtl_progress_frame_names.begin(), rtl_progress_frame_names.end());

  progress_frames_.clear();
  progress_frames_.reserve(progress_frames);
  for (const auto& frame_name : progress_frame_names) {
    progress_frames_.emplace_back(LoadBitmap(frame_name));
  }

  rtl_progress_frames_.clear();
    rtl_progress_frames_.reserve(rtl_progress_frames);
    for (const auto& frame_name : rtl_progress_frame_names) {
      rtl_progress_frames_.emplace_back(LoadBitmap(frame_name));
  }
}

void WearRecoveryUI::SetProgress(float fraction) {
    if (is_screen_circle_) {
       std::lock_guard<std::mutex> lg(updateMutex);
       if (fraction < 0.0) fraction = 0.0;
       if (fraction > 1.0) fraction = 1.0;
       if (progressBarType == DETERMINATE && fraction > progress) {
          // Skip updates that aren't visibly different.
          if (GetProgressFrameIndex(fraction) != GetProgressFrameIndex(progress)) {
              // circular display
              progress = fraction;
              update_progress_locked();
          }
       }
    } else {
        // rectangular display
        ScreenRecoveryUI::SetProgress(fraction);
    }
}

int WearRecoveryUI::GetProgressBaseline() const {
  int progress_height = gr_get_height(progress_frames_[0].get());
  return (ScreenHeight() - progress_height) / 2 + PixelsFromDp(kProgressBarVerticalOffsetDp);
}

int WearRecoveryUI::GetTextBaseline() const {
  if (is_screen_circle_) {
        return GetProgressBaseline() - PixelsFromDp(kProgressBarVerticalOffsetDp) -
                                    gr_get_height(installing_text_.get());
  } else {
       return ScreenRecoveryUI::GetTextBaseline();
  }
}

size_t WearRecoveryUI::GetProgressFrameIndex(float fraction) const {
  return static_cast<size_t>(fraction * (progress_frames_.size() - 1));
}

// TODO merge drawing routines with screen_ui
void WearRecoveryUI::update_progress_locked() {
  draw_screen_locked();
  gr_flip();
}

bool WearRecoveryUI::IsWearable() {
  return true;
}

void WearRecoveryUI::SetStage(int /* current */, int /* max */) {}

std::unique_ptr<Menu> WearRecoveryUI::CreateMenu(const std::vector<std::string>& text_headers,
                                                 const std::vector<std::string>& text_items,
                                                 size_t initial_selection) const {
  if (text_rows_ > 0 && text_cols_ > 0) {
    return std::make_unique<TextMenu>(scrollable_menu_, text_rows_ - menu_unusable_rows_ - 1,
                                      text_cols_ - 1, text_headers, text_items, initial_selection,
                                      char_height_, *this);
  }

  return nullptr;
}
