// Copyright (c) 2010 The Chromium OS 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 "monitor_reconfig/monitor_reconfigure_main.h"

#include <algorithm>
#include <cstdio>
#include <cstdlib>

#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_util.h"

using std::map;
using std::sort;
using std::string;
using std::vector;

namespace monitor_reconfig {

static const char kLcdOutputName[] = "LVDS1";
static const float kScreenDpi = 96.0;
static const float kInchInMm = 25.4;

MonitorReconfigureMain::MonitorReconfigureMain(Display* display,
                                               Window window,
                                               XRRScreenResources* screen_info)
    : display_(display),
      window_(window),
      screen_info_(screen_info),
      lcd_output_(0),
      lcd_output_info_(NULL),
      external_output_(0),
      external_output_info_(NULL) {
  for (int i = 0; i < screen_info_->nmode; ++i) {
    XRRModeInfo* current_mode = &screen_info_->modes[i];
    mode_map_[current_mode->id] = current_mode;
  }
  DetermineOutputs();
}

void MonitorReconfigureMain::Run() {
  vector<ResolutionSelector::Mode> lcd_modes;
  SortModesByResolution(lcd_output_, &lcd_modes);
  DCHECK(!lcd_modes.empty());

  vector<ResolutionSelector::Mode> external_modes;
  if (IsExternalMonitorConnected()) {
    SortModesByResolution(external_output_, &external_modes);
    DCHECK(!external_modes.empty());
  }

  ResolutionSelector selector;
  ResolutionSelector::Mode lcd_resolution;
  ResolutionSelector::Mode external_resolution;
  ResolutionSelector::Mode screen_resolution;

  CHECK(selector.FindBestResolutions(lcd_modes,
                                     external_modes,
                                     &lcd_resolution,
                                     &external_resolution,
                                     &screen_resolution));
  CHECK(!lcd_resolution.name.empty() || !external_resolution.name.empty());

  // Grab the server during mode changes.
  XGrabServer(display_);

  // Disable the LCD if we were told to do so (because we're using a higher
  // resolution that'd be clipped on the LCD).
  // Otherwise enable the LCD if appropriate.
  if (lcd_resolution.name.empty())
    DisableDevice(lcd_output_, lcd_output_info_);
  else
    SetDeviceResolution(lcd_output_, lcd_output_info_, lcd_resolution);

  // If there's no external output connected, disable the device before we try
  // to set the screen resolution; otherwise xrandr will complain if we're
  // trying to set the screen to a smaller size than what the now-unplugged
  // device was using.
  // Otherwise enable the external device if appropriate.
  if (external_resolution.name.empty())
    DisableDevice(external_output_, external_output_info_);
  else
    SetDeviceResolution(external_output_, external_output_info_,
                        external_resolution);

  // Set the fb resolution.
  SetScreenResolution(screen_resolution);

  // Now let the server go and sync all changes.
  XUngrabServer(display_);
  XSync(display_, False);
}

void MonitorReconfigureMain::DetermineOutputs() {
  CHECK(screen_info_->noutput > 1) << "Expected at least two outputs";
  CHECK(!lcd_output_info_);
  CHECK(!external_output_info_);

  RROutput first_output = screen_info_->outputs[0];
  RROutput second_output = screen_info_->outputs[1];

  XRROutputInfo* first_output_info =
      XRRGetOutputInfo(display_, screen_info_, first_output);
  XRROutputInfo* second_output_info =
      XRRGetOutputInfo(display_, screen_info_, second_output);

  if (strcmp(first_output_info->name, kLcdOutputName) == 0) {
    lcd_output_ = first_output;
    lcd_output_info_ = first_output_info;
    external_output_ = second_output;
    external_output_info_ = second_output_info;
  } else {
    lcd_output_ = second_output;
    lcd_output_info_ = second_output_info;
    external_output_ = first_output;
    external_output_info_ = first_output_info;
  }

  LOG(INFO) << "LCD name: " << lcd_output_info_->name << " (xid "
            << lcd_output_ << ")";
  for (int i = 0; i < lcd_output_info_->nmode; ++i) {
    XRRModeInfo* mode = mode_map_[lcd_output_info_->modes[i]];
    LOG(INFO) << "  Mode: " << mode->width << "x" << mode->height
              << " (xid " << mode->id << ")";
  }

  LOG(INFO) << "External name: " << external_output_info_->name
            << " (xid " << external_output_ << ")";
  for (int i = 0; i < external_output_info_->nmode; ++i) {
    XRRModeInfo* mode = mode_map_[external_output_info_->modes[i]];
    LOG(INFO) << "  Mode: " << mode->width << "x" << mode->height
              << " (xid " << mode->id << ")";
  }
}

bool MonitorReconfigureMain::IsExternalMonitorConnected() {
  return (external_output_info_->connection == RR_Connected);
}

void MonitorReconfigureMain::SortModesByResolution(
    RROutput output,
    vector<ResolutionSelector::Mode>* modes_out) {
  modes_out->clear();

  XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_info_, output);
  for (int i = 0; i < output_info->nmode; ++i) {
    const XRRModeInfo* mode = mode_map_[output_info->modes[i]];
    DCHECK(mode);
    LOG(INFO) << "Adding mode " << mode->width << " " << mode->height
              << " (xid " << mode->id << ")";
    modes_out->push_back(
        ResolutionSelector::Mode(mode->width, mode->height, mode->name,
                                 mode->id));
  }

  sort(modes_out->begin(), modes_out->end(),
       ResolutionSelector::ModeResolutionComparator());

  XRRFreeOutputInfo(output_info);
}

bool MonitorReconfigureMain::SetDeviceResolution(
    RROutput output, const XRROutputInfo* output_info,
    const ResolutionSelector::Mode& resolution) {
  Status s = XRRSetCrtcConfig(display_, screen_info_, output_info->crtcs[0],
                              CurrentTime, 0, 0, resolution.id, RR_Rotate_0,
                              &output, 1);
  return (s == RRSetConfigSuccess);
}

bool MonitorReconfigureMain::SetScreenResolution(
    const ResolutionSelector::Mode& resolution) {
  LOG(INFO) << "Setting resolution " << resolution.name.c_str() << " "
            << resolution.width << "x" << resolution.height;
  XRRSetScreenSize(display_, window_,
                   resolution.width,
                   resolution.height,
                   resolution.width * kInchInMm / kScreenDpi,
                   resolution.height * kInchInMm / kScreenDpi);

  return true;
}

bool MonitorReconfigureMain::DisableDevice(RROutput output,
                                           const XRROutputInfo* output_info) {
  if (!output_info->crtc)
    return true;
  LOG(INFO) << "Disabling output " << output_info->name;
  Status s = XRRSetCrtcConfig(display_, screen_info_, output_info->crtc,
    CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0);
  return (s == RRSetConfigSuccess);
}

}  // end namespace monitor_reconfig

int main(int argc, char** argv) {
  CommandLine::Init(argc, argv);
  logging::InitLogging(NULL,
                       logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
                       logging::DONT_LOCK_LOG_FILE,
                       logging::APPEND_TO_OLD_LOG_FILE);
  Display* display = XOpenDisplay(NULL);
  CHECK(display) << "Could not open display";

  Window window = RootWindow(display, DefaultScreen(display));
  XRRScreenResources* screen_info = XRRGetScreenResources(display, window);
  monitor_reconfig::MonitorReconfigureMain main_app(display, window,
                                                    screen_info);
  main_app.Run();
  XRRFreeScreenResources(screen_info);
  return 0;
}
