// Copyright (c) 2012 The Chromium 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 "printing/backend/cups_helper.h"

#include <cups/ppd.h>

#include "base/file_util.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "printing/backend/print_backend.h"
#include "printing/backend/print_backend_consts.h"
#include "url/gurl.h"

namespace printing {

// This section contains helper code for PPD parsing for semantic capabilities.
namespace {

const char kColorDevice[] = "ColorDevice";
const char kColorModel[] = "ColorModel";
const char kColorMode[] = "ColorMode";
const char kProcessColorModel[] = "ProcessColorModel";
const char kPrintoutMode[] = "PrintoutMode";
const char kDraftGray[] = "Draft.Gray";
const char kHighGray[] = "High.Gray";

const char kDuplex[] = "Duplex";
const char kDuplexNone[] = "None";

#if !defined(OS_MACOSX)
void ParseLpOptions(const base::FilePath& filepath,
                    const std::string& printer_name,
                    int* num_options, cups_option_t** options) {
  std::string content;
  if (!base::ReadFileToString(filepath, &content))
    return;

  const char kDest[] = "dest";
  const char kDefault[] = "default";
  const size_t kDestLen = sizeof(kDest) - 1;
  const size_t kDefaultLen = sizeof(kDefault) - 1;
  std::vector<std::string> lines;
  base::SplitString(content, '\n', &lines);

  for (size_t i = 0; i < lines.size(); ++i) {
    std::string line = lines[i];
    if (line.empty())
      continue;

    if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 &&
        isspace(line[kDefaultLen])) {
      line = line.substr(kDefaultLen);
    } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 &&
               isspace(line[kDestLen])) {
      line = line.substr(kDestLen);
    } else {
      continue;
    }

    TrimWhitespaceASCII(line, TRIM_ALL, &line);
    if (line.empty())
      continue;

    size_t space_found = line.find(' ');
    if (space_found == std::string::npos)
      continue;

    std::string name = line.substr(0, space_found);
    if (name.empty())
      continue;

    if (base::strncasecmp(printer_name.c_str(), name.c_str(),
                          name.length()) != 0) {
      continue;  // This is not the required printer.
    }

    line = line.substr(space_found + 1);
    TrimWhitespaceASCII(line, TRIM_ALL, &line);  // Remove extra spaces.
    if (line.empty())
      continue;
    // Parse the selected printer custom options.
    *num_options = cupsParseOptions(line.c_str(), 0, options);
  }
}

void MarkLpOptions(const std::string& printer_name, ppd_file_t** ppd) {
  cups_option_t* options = NULL;
  int num_options = 0;
  ppdMarkDefaults(*ppd);

  const char kSystemLpOptionPath[] = "/etc/cups/lpoptions";
  const char kUserLpOptionPath[] = ".cups/lpoptions";

  std::vector<base::FilePath> file_locations;
  file_locations.push_back(base::FilePath(kSystemLpOptionPath));
  file_locations.push_back(base::FilePath(
      base::GetHomeDir().Append(kUserLpOptionPath)));

  for (std::vector<base::FilePath>::const_iterator it = file_locations.begin();
       it != file_locations.end(); ++it) {
    num_options = 0;
    options = NULL;
    ParseLpOptions(*it, printer_name, &num_options, &options);
    if (num_options > 0 && options) {
      cupsMarkOptions(*ppd, num_options, options);
      cupsFreeOptions(num_options, options);
    }
  }
}
#endif  // !defined(OS_MACOSX)

bool GetBasicColorModelSettings(ppd_file_t* ppd,
                                ColorModel* color_model_for_black,
                                ColorModel* color_model_for_color,
                                bool* color_is_default) {
  ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
  if (!color_model)
    return false;

  if (ppdFindChoice(color_model, printing::kBlack))
    *color_model_for_black = printing::BLACK;
  else if (ppdFindChoice(color_model, printing::kGray))
    *color_model_for_black = printing::GRAY;
  else if (ppdFindChoice(color_model, printing::kGrayscale))
    *color_model_for_black = printing::GRAYSCALE;

  if (ppdFindChoice(color_model, printing::kColor))
    *color_model_for_color = printing::COLOR;
  else if (ppdFindChoice(color_model, printing::kCMYK))
    *color_model_for_color = printing::CMYK;
  else if (ppdFindChoice(color_model, printing::kRGB))
    *color_model_for_color = printing::RGB;
  else if (ppdFindChoice(color_model, printing::kRGBA))
    *color_model_for_color = printing::RGBA;
  else if (ppdFindChoice(color_model, printing::kRGB16))
    *color_model_for_color = printing::RGB16;
  else if (ppdFindChoice(color_model, printing::kCMY))
    *color_model_for_color = printing::CMY;
  else if (ppdFindChoice(color_model, printing::kKCMY))
    *color_model_for_color = printing::KCMY;
  else if (ppdFindChoice(color_model, printing::kCMY_K))
    *color_model_for_color = printing::CMY_K;

  ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
  if (!marked_choice)
    marked_choice = ppdFindChoice(color_model, color_model->defchoice);

  if (marked_choice) {
    *color_is_default =
        (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) &&
        (base::strcasecmp(marked_choice->choice, printing::kGray) != 0) &&
        (base::strcasecmp(marked_choice->choice, printing::kGrayscale) != 0);
  }
  return true;
}

bool GetPrintOutModeColorSettings(ppd_file_t* ppd,
                                  ColorModel* color_model_for_black,
                                  ColorModel* color_model_for_color,
                                  bool* color_is_default) {
  ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
  if (!printout_mode)
    return false;

  *color_model_for_color = printing::PRINTOUTMODE_NORMAL;
  *color_model_for_black = printing::PRINTOUTMODE_NORMAL;

  // Check to see if NORMAL_GRAY value is supported by PrintoutMode.
  // If NORMAL_GRAY is not supported, NORMAL value is used to
  // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to
  // represent color.
  if (ppdFindChoice(printout_mode, printing::kNormalGray))
    *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;

  // Get the default marked choice to identify the default color setting
  // value.
  ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
  if (!printout_mode_choice) {
      printout_mode_choice = ppdFindChoice(printout_mode,
                                           printout_mode->defchoice);
  }
  if (printout_mode_choice) {
    if ((base::strcasecmp(printout_mode_choice->choice,
                          printing::kNormalGray) == 0) ||
        (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) ||
        (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) {
      *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
      *color_is_default = false;
    }
  }
  return true;
}

bool GetColorModeSettings(ppd_file_t* ppd,
                          ColorModel* color_model_for_black,
                          ColorModel* color_model_for_color,
                          bool* color_is_default) {
  // Samsung printers use "ColorMode" attribute in their ppds.
  ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
  if (!color_mode_option)
    return false;

  if (ppdFindChoice(color_mode_option, printing::kColor))
    *color_model_for_color = printing::COLORMODE_COLOR;

  if (ppdFindChoice(color_mode_option, printing::kMonochrome))
    *color_model_for_black = printing::COLORMODE_MONOCHROME;

  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
  if (!mode_choice) {
    mode_choice = ppdFindChoice(color_mode_option,
                                color_mode_option->defchoice);
  }

  if (mode_choice) {
    *color_is_default =
        (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
  }
  return true;
}

bool GetHPColorSettings(ppd_file_t* ppd,
                        ColorModel* color_model_for_black,
                        ColorModel* color_model_for_color,
                        bool* color_is_default) {
  // HP printers use "Color/Color Model" attribute in their ppds.
  ppd_option_t* color_mode_option = ppdFindOption(ppd, printing::kColor);
  if (!color_mode_option)
    return false;

  if (ppdFindChoice(color_mode_option, printing::kColor))
    *color_model_for_color = printing::HP_COLOR_COLOR;
  if (ppdFindChoice(color_mode_option, printing::kBlack))
    *color_model_for_black = printing::HP_COLOR_BLACK;

  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
  if (!mode_choice) {
    mode_choice = ppdFindChoice(color_mode_option,
                                color_mode_option->defchoice);
  }
  if (mode_choice) {
    *color_is_default =
        (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
  }
  return true;
}

bool GetProcessColorModelSettings(ppd_file_t* ppd,
                                  ColorModel* color_model_for_black,
                                  ColorModel* color_model_for_color,
                                  bool* color_is_default) {
  // Canon printers use "ProcessColorModel" attribute in their ppds.
  ppd_option_t* color_mode_option =  ppdFindOption(ppd, kProcessColorModel);
  if (!color_mode_option)
    return false;

  if (ppdFindChoice(color_mode_option, printing::kRGB))
    *color_model_for_color = printing::PROCESSCOLORMODEL_RGB;
  else if (ppdFindChoice(color_mode_option, printing::kCMYK))
    *color_model_for_color = printing::PROCESSCOLORMODEL_CMYK;

  if (ppdFindChoice(color_mode_option, printing::kGreyscale))
    *color_model_for_black = printing::PROCESSCOLORMODEL_GREYSCALE;

  ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
  if (!mode_choice) {
    mode_choice = ppdFindChoice(color_mode_option,
                                color_mode_option->defchoice);
  }

  if (mode_choice) {
    *color_is_default =
        (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0);
  }
  return true;
}

bool GetColorModelSettings(ppd_file_t* ppd,
                           ColorModel* cm_black,
                           ColorModel* cm_color,
                           bool* is_color) {
  bool is_color_device = false;
  ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL);
  if (attr && attr->value)
    is_color_device = ppd->color_device;

  *is_color = is_color_device;
  return (is_color_device &&
          GetBasicColorModelSettings(ppd, cm_black, cm_color, is_color)) ||
      GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) ||
      GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
      GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
      GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color);
}

// Default port for IPP print servers.
const int kDefaultIPPServerPort = 631;

}  // namespace

// Helper wrapper around http_t structure, with connection and cleanup
// functionality.
HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url,
                                       http_encryption_t encryption)
    : http_(NULL) {
  // If we have an empty url, use default print server.
  if (print_server_url.is_empty())
    return;

  int port = print_server_url.IntPort();
  if (port == url_parse::PORT_UNSPECIFIED)
    port = kDefaultIPPServerPort;

  http_ = httpConnectEncrypt(print_server_url.host().c_str(), port, encryption);
  if (http_ == NULL) {
    LOG(ERROR) << "CP_CUPS: Failed connecting to print server: "
               << print_server_url;
  }
}

HttpConnectionCUPS::~HttpConnectionCUPS() {
  if (http_ != NULL)
    httpClose(http_);
}

void HttpConnectionCUPS::SetBlocking(bool blocking) {
  httpBlocking(http_, blocking ?  1 : 0);
}

http_t* HttpConnectionCUPS::http() {
  return http_;
}

bool ParsePpdCapabilities(
    const std::string& printer_name,
    const std::string& printer_capabilities,
    PrinterSemanticCapsAndDefaults* printer_info) {
  base::FilePath ppd_file_path;
  if (!base::CreateTemporaryFile(&ppd_file_path))
    return false;

  int data_size = printer_capabilities.length();
  if (data_size != file_util::WriteFile(
                       ppd_file_path,
                       printer_capabilities.data(),
                       data_size)) {
    base::DeleteFile(ppd_file_path, false);
    return false;
  }

  ppd_file_t* ppd = ppdOpenFile(ppd_file_path.value().c_str());
  if (!ppd)
    return false;

  printing::PrinterSemanticCapsAndDefaults caps;
#if !defined(OS_MACOSX)
  MarkLpOptions(printer_name, &ppd);
#endif
  ppd_choice_t* duplex_choice = ppdFindMarkedChoice(ppd, kDuplex);
  if (!duplex_choice) {
    ppd_option_t* option = ppdFindOption(ppd, kDuplex);
    if (option)
      duplex_choice = ppdFindChoice(option, option->defchoice);
  }

  if (duplex_choice) {
    caps.duplex_capable = true;
    if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0)
      caps.duplex_default = printing::LONG_EDGE;
    else
      caps.duplex_default = printing::SIMPLEX;
  }

  bool is_color = false;
  ColorModel cm_color = UNKNOWN_COLOR_MODEL, cm_black = UNKNOWN_COLOR_MODEL;
  if (!GetColorModelSettings(ppd, &cm_black, &cm_color, &is_color)) {
    VLOG(1) << "Unknown printer color model";
  }

  caps.color_changeable = ((cm_color != UNKNOWN_COLOR_MODEL) &&
                           (cm_black != UNKNOWN_COLOR_MODEL) &&
                           (cm_color != cm_black));
  caps.color_default = is_color;
  caps.color_model = cm_color;
  caps.bw_model = cm_black;

  ppdClose(ppd);
  base::DeleteFile(ppd_file_path, false);

  *printer_info = caps;
  return true;
}

}  // namespace printing
