// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef BASE_SCOPED_HANDLE_H__
#define BASE_SCOPED_HANDLE_H__

#include <windows.h>

#include "base/basictypes.h"

// Used so we always remember to close the handle. Example:
//   ScopedHandle hfile(CreateFile(...));
//   if (!hfile.Get())
//     ...process error
//   ReadFile(hfile.Get(), ...);
//
// To sqirrel the handle away somewhere else:
//   secret_handle_ = hfile.Take();
//
// To explicitly close the handle:
//   CloseHandle(hfile.Take());
class ScopedHandle {
 public:
  ScopedHandle() : handle_(NULL) {
  }

  explicit ScopedHandle(HANDLE h) : handle_(NULL) {
    Set(h);
  }

  ~ScopedHandle() {
    Close();
  }

  // Use this instead of comparing to INVALID_HANDLE_VALUE to pick up our NULL
  // usage for errors.
  bool IsValid() const {
    return handle_ != NULL;
  }

  void Set(HANDLE new_handle) {
    Close();

    // Windows is inconsistent about invalid handles, so we always use NULL
    if (handle_ != INVALID_HANDLE_VALUE)
      handle_ = new_handle;
  }

  HANDLE Get() {
    return handle_;
  }

  operator HANDLE() { return handle_; }

  HANDLE Take() {
    // transfers ownership away from this object
    HANDLE h = handle_;
    handle_ = NULL;
    return h;
  }

 private:
  void Close() {
    if (handle_) {
      CloseHandle(handle_);
      handle_ = NULL;
    }
  }

  HANDLE handle_;
  DISALLOW_EVIL_CONSTRUCTORS(ScopedHandle);
};

// Like ScopedHandle, but for HANDLEs returned from FindFile().
class ScopedFindFileHandle {
 public:
  explicit ScopedFindFileHandle(HANDLE handle) : handle_(handle) {
    // Windows is inconsistent about invalid handles, so we always use NULL
    if (handle_ == INVALID_HANDLE_VALUE)
      handle_ = NULL;
  }

  ~ScopedFindFileHandle() {
    if (handle_)
      FindClose(handle_);
  }

  // Use this instead of comparing to INVALID_HANDLE_VALUE to pick up our NULL
  // usage for errors.
  bool IsValid() const { return handle_ != NULL; }

  operator HANDLE() { return handle_; }

 private:
  HANDLE handle_;

  DISALLOW_EVIL_CONSTRUCTORS(ScopedFindFileHandle);
};

// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
// CreateCompatibleDC.  For an HDC returned by GetDC, use ReleaseDC instead.
class ScopedHDC {
 public:
  explicit ScopedHDC(HDC h) : hdc_(h) { }

  ~ScopedHDC() {
    if (hdc_)
      DeleteDC(hdc_);
  }

  operator HDC() { return hdc_; }

 private:
  HDC hdc_;
  DISALLOW_EVIL_CONSTRUCTORS(ScopedHDC);
};

// Like ScopedHandle but for HBITMAP.
class ScopedBitmap {
 public:
  explicit ScopedBitmap(HBITMAP h) : hbitmap_(h) { }

  ~ScopedBitmap() {
    if (hbitmap_)
      DeleteObject(hbitmap_);
  }

  operator HBITMAP() { return hbitmap_; }

 private:
  HBITMAP hbitmap_;
  DISALLOW_EVIL_CONSTRUCTORS(ScopedBitmap);
};

// Like ScopedHandle but for HRGN.
class ScopedHRGN {
 public:
  explicit ScopedHRGN(HRGN h) : hrgn_(h) { }

  ~ScopedHRGN() {
    if (hrgn_)
      DeleteObject(hrgn_);
  }

  operator HRGN() { return hrgn_; }

  ScopedHRGN& operator=(HRGN hrgn) {
    if (hrgn_ && hrgn != hrgn_)
      DeleteObject(hrgn_);
    hrgn_ = hrgn;
    return *this;
  }

 private:
  HRGN hrgn_;
  DISALLOW_EVIL_CONSTRUCTORS(ScopedHRGN);
};

// Like ScopedHandle except for HGLOBAL.
template<class T>
class ScopedHGlobal {
 public:
  explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) {
    data_ = static_cast<T*>(GlobalLock(glob_));
  }
  ~ScopedHGlobal() {
    GlobalUnlock(glob_);
  }

  T* get() { return data_; }

  size_t Size() const { return GlobalSize(glob_); }

  T* operator->() const  {
    assert(data_ != 0);
    return data_;
  }

 private:
  HGLOBAL glob_;

  T* data_;

  DISALLOW_EVIL_CONSTRUCTORS(ScopedHGlobal);
};

#endif // BASE_SCOPED_HANDLE_H__