// Copyright (c) 2010 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 "chrome/browser/chromeos/cros/syslogs_library.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/string_util.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/common/chrome_switches.h"
#include "content/browser/browser_thread.h"

namespace chromeos {

const char kContextFeedback[] = "feedback";
const char kContextSysInfo[] = "sysinfo";


class SyslogsLibraryImpl : public SyslogsLibrary {
 public:
  SyslogsLibraryImpl() {}
  virtual ~SyslogsLibraryImpl() {}

  virtual Handle RequestSyslogs(
      bool compress_logs, bool add_feedback_context,
      CancelableRequestConsumerBase* consumer,
      ReadCompleteCallback* callback);

  // Reads system logs, compresses content if requested.
  // Called from FILE thread.
  void ReadSyslogs(
      scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
      bool compress_logs, bool add_feedback_context);

  void LoadCompressedLogs(const FilePath& zip_file,
                          std::string* zip_content);

  DISALLOW_COPY_AND_ASSIGN(SyslogsLibraryImpl);
};

class SyslogsLibraryStubImpl : public SyslogsLibrary {
 public:
  SyslogsLibraryStubImpl() {}
  virtual ~SyslogsLibraryStubImpl() {}

  virtual Handle RequestSyslogs(bool compress_logs, bool add_feedback_context,
                                CancelableRequestConsumerBase* consumer,
                                ReadCompleteCallback* callback) {
    if (callback)
      callback->Run(Tuple2<LogDictionaryType*, std::string*>(NULL , NULL));

    return 0;
  }
};

// static
SyslogsLibrary* SyslogsLibrary::GetImpl(bool stub) {
  if (stub)
    return new SyslogsLibraryStubImpl();
  else
    return new SyslogsLibraryImpl();
}


CancelableRequestProvider::Handle SyslogsLibraryImpl::RequestSyslogs(
    bool compress_logs, bool add_feedback_context,
    CancelableRequestConsumerBase* consumer,
    ReadCompleteCallback* callback) {
  // Register the callback request.
  scoped_refptr<CancelableRequest<ReadCompleteCallback> > request(
         new CancelableRequest<ReadCompleteCallback>(callback));
  AddRequest(request, consumer);

  // Schedule a task on the FILE thread which will then trigger a request
  // callback on the calling thread (e.g. UI) when complete.
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(
          this, &SyslogsLibraryImpl::ReadSyslogs, request,
          compress_logs, add_feedback_context));

  return request->handle();
}

// Called from FILE thread.
void SyslogsLibraryImpl::ReadSyslogs(
    scoped_refptr<CancelableRequest<ReadCompleteCallback> > request,
    bool compress_logs, bool add_feedback_context) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  if (request->canceled())
    return;

  if (compress_logs && !CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kCompressSystemFeedback))
    compress_logs = false;

  // Create temp file.
  FilePath zip_file;
  if (compress_logs && !file_util::CreateTemporaryFile(&zip_file)) {
    LOG(ERROR) << "Cannot create temp file";
    compress_logs = false;
  }

  LogDictionaryType* logs = NULL;
  if (CrosLibrary::Get()->EnsureLoaded())
    logs = chromeos::GetSystemLogs(
        compress_logs ? &zip_file : NULL,
        add_feedback_context ? kContextFeedback : kContextSysInfo);

  std::string* zip_content = NULL;
  if (compress_logs) {
    // Load compressed logs.
    zip_content = new std::string();
    LoadCompressedLogs(zip_file, zip_content);
    file_util::Delete(zip_file, false);
  }

  // Will call the callback on the calling thread.
  request->ForwardResult(Tuple2<LogDictionaryType*,
                                std::string*>(logs, zip_content));
}


void SyslogsLibraryImpl::LoadCompressedLogs(const FilePath& zip_file,
                                            std::string* zip_content) {
  DCHECK(zip_content);
  if (!file_util::ReadFileToString(zip_file, zip_content)) {
    LOG(ERROR) << "Cannot read compressed logs file from " <<
        zip_file.value().c_str();
  }
}

}  // namespace chromeos

// Allows InvokeLater without adding refcounting. SyslogsLibraryImpl is a
// Singleton and won't be deleted until it's last InvokeLater is run.
DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::SyslogsLibraryImpl);