// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cstdlib>
#include <iostream>
#include <memory>

#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <trace-provider/provider.h>

#include "lib/component/cpp/startup_context.h"
#include "lib/fsl/vmo/vector.h"
#include "lib/fxl/command_line.h"
#include "lib/fxl/log_settings_command_line.h"
#include "lib/fxl/logging.h"

// These are the only values we want to track
const int kBlack = 0x000000;
const int kWhite = 0xeeeeee;
const int kGreen = 0x4dac26;
const int kRed = 0xd01c8b;

const int kMinExpectedPixels = 950000;  // Typical value is ~1.5M
const int kMinPixelsForReport = 50000;

class ScreenshotTaker {
 public:
  explicit ScreenshotTaker(async::Loop* loop, bool output_screen)
      : loop_(loop),
        output_screen_(output_screen),
        context_(component::StartupContext::CreateFromStartupInfo()) {
    // Connect to the Scenic service.
    scenic_ =
        context_->ConnectToEnvironmentService<fuchsia::ui::scenic::Scenic>();
    scenic_.set_error_handler([this](zx_status_t status) {
      FXL_LOG(ERROR) << "Lost connection to Scenic service.";
      encountered_error_ = true;
      loop_->Quit();
    });
  }

  bool encountered_error() const { return encountered_error_; }

  void TakeScreenshot() {
    FXL_LOG(INFO) << "start TakeScreenshot";
    // If we wait for a call back from GetDisplayInfo, we are guaranteed that
    // the GFX system is initialized, which is a prerequisite for taking a
    // screenshot. TODO(SCN-678): Remove call to GetDisplayInfo once bug done.
    scenic_->GetDisplayInfo([this](fuchsia::ui::gfx::DisplayInfo /*unused*/) {
      TakeScreenshotInternal();
    });
  }

 private:
  void TakeScreenshotInternal() {
    FXL_LOG(INFO) << "start TakeScreenshotInternal";
    scenic_->TakeScreenshot(
        [this](fuchsia::ui::scenic::ScreenshotData screenshot, bool status) {
          FXL_LOG(INFO) << "start pixel capture";
          std::vector<uint8_t> imgdata;
          if (!status || !fsl::VectorFromVmo(screenshot.data, &imgdata)) {
            FXL_LOG(ERROR) << "TakeScreenshot failed";
            encountered_error_ = true;
            loop_->Quit();
            return;
          }

          std::map<int, int> histogram;
          if (output_screen_) {
            std::cout << "P6\n";
            std::cout << screenshot.info.width << "\n";
            std::cout << screenshot.info.height << "\n";
            std::cout << 255 << "\n";
          }

          FXL_LOG(INFO) << "capturing pixels";
          const uint8_t* pchannel = &imgdata[0];
          for (uint32_t pixel = 0;
               pixel < screenshot.info.width * screenshot.info.height;
               pixel++) {
            uint8_t rgb[] = {pchannel[2], pchannel[1], pchannel[0]};
            if (output_screen_) {
              std::cout.write(reinterpret_cast<const char*>(rgb), 3);
            } else {
              int rgb_value = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
              if (histogram.find(rgb_value) != histogram.end()) {
                histogram[rgb_value] = histogram[rgb_value] + 1;
              } else {
                histogram[rgb_value] = 1;
              }
            }
            pchannel += 4;
          }
          if (!output_screen_) {
            // For success, there should be at least 1M green or red pixels
            // combined The typical number is > 1.5M
            if (histogram[kGreen] + histogram[kRed] > kMinExpectedPixels) {
              FXL_LOG(INFO) << "success";
              printf("success\n");
            } else {
              FXL_LOG(INFO) << "failure";
              printf("failure\n");
              printf("black: %d, white: %d, green: %d, red: %d\n",
                     histogram[kBlack], histogram[kWhite], histogram[kGreen],
                     histogram[kRed]);
              // To help debug failures, if the majority of values aren't
              // already expected, output the values that were over a threshold
              // count.
              if (histogram[kBlack] + histogram[kWhite] + histogram[kGreen] +
                      histogram[kRed] <
                  kMinExpectedPixels) {
                const int MIN_REPORT_THRESHOLD = kMinPixelsForReport;
                std::map<int, int>::iterator it;
                for (const auto& pair : histogram) {
                  if (pair.second > MIN_REPORT_THRESHOLD) {
                    printf("Pixel 0x%06x occurred %d times\n", pair.first,
                           pair.second);
                  }
                }
              }
              encountered_error_ = true;
            }
          }
          loop_->Quit();
        });
  }
  async::Loop* loop_;
  const bool output_screen_;
  std::unique_ptr<component::StartupContext> context_;
  bool encountered_error_ = false;
  fuchsia::ui::scenic::ScenicPtr scenic_;
};

int main(int argc, const char** argv) {
  FXL_LOG(INFO) << "starting screen capture";
  bool output_screen = true;
  auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
  if (!fxl::SetLogSettingsFromCommandLine(command_line))
    return 1;

  const auto& positional_args = command_line.positional_args();
  if (!positional_args.empty()) {
    if (positional_args.size() == 1 &&
        positional_args[0].compare("-histogram") == 0) {
      output_screen = false;
      FXL_LOG(INFO) << "in histogram mode";
    } else {
      FXL_LOG(ERROR) << "Usage: screencap\n"
                     << "Takes a screenshot in PPM format and writes it "
                     << "to stdout.\n"
                     << "To write to a file, redirect stdout, e.g.: "
                     << "screencap > \"${DST}\"";
      return 1;
    }
  }
  FXL_LOG(INFO) << "setting up event loop";

  async::Loop loop(&kAsyncLoopConfigAttachToThread);
  trace::TraceProvider trace_provider(loop.dispatcher());

  FXL_LOG(INFO) << "starting taker";
  ScreenshotTaker taker(&loop, output_screen);
  taker.TakeScreenshot();
  FXL_LOG(INFO) << "starting Run()";
  loop.Run();

  FXL_LOG(INFO) << "returning result";
  return taker.encountered_error() ? EXIT_FAILURE : EXIT_SUCCESS;
}
