/*
 * File:	wx_clipb.cc
 * Purpose:	Clipboard implementation
 * Author:	Julian Smart
 * Created:	1993
 * Updated:	April 1995
 * Copyright:	(c) 1995, AIAI, University of Edinburgh
 */

/* static const char sccsid[] = "@(#)wx_clipb.cc	1.2 5/9/94"; */

#if !defined(_MSC_VER) && !defined(wx_wxh)
#define wx_wxh
#endif

#include "wx.h"
#pragma hdrstop
#include "wx_setup.h"

#if USE_CLIPBOARD
#include "wx_clipb.h"
#include "wx_mf.h"
#include "wx_privt.h"
#include "wx_main.h"

Bool wxClipboardIsOpen = FALSE;

Bool wxOpenClipboard(void)
{
  if (wxTheApp->wx_frame && !wxClipboardIsOpen)
  {
    wxClipboardIsOpen = (Bool)::OpenClipboard(((wxWnd *)wxTheApp->wx_frame->handle)->handle);
    return wxClipboardIsOpen;
  }
  else return FALSE;
}

Bool wxCloseClipboard(void)
{
  if (wxClipboardIsOpen)
  {
    wxClipboardIsOpen = FALSE;
  }
  return (Bool)::CloseClipboard();
}

Bool wxEmptyClipboard(void)
{
  return (Bool)::EmptyClipboard();
}

Bool wxIsClipboardFormatAvailable(int dataFormat)
{
  return ::IsClipboardFormatAvailable(dataFormat);
}

Bool wxSetClipboardData(int dataFormat, wxObject *obj, int width, int height)
{
  switch (dataFormat)
  {
    case wxCF_TEXT:
    case wxCF_OEMTEXT:
    {
      char *s = (char *)obj;
      int length = strlen(s);
      HANDLE hGlobalMemory = GlobalAlloc(GHND, (DWORD) length + 1);
      if (!hGlobalMemory)
        return FALSE;

      LPSTR lpGlobalMemory = (LPSTR)GlobalLock(hGlobalMemory);

      for (int i = 0; i < length; i ++)
        *lpGlobalMemory++ = *s++;
      *lpGlobalMemory++ = 0;

      GlobalUnlock(hGlobalMemory);
      HANDLE success = SetClipboardData(CF_TEXT, hGlobalMemory);
      return (Bool)success;
      break;
    }

    case wxCF_BITMAP:
    {
      wxBitmap *wxBM = (wxBitmap *)obj;

      HDC hdcMem = CreateCompatibleDC(NULL);
      HDC hdcSrc = CreateCompatibleDC(NULL);
      HBITMAP old = ::SelectObject(hdcSrc, wxBM->ms_bitmap);
      HBITMAP hBitmap = CreateCompatibleBitmap(hdcMem,
                                  wxBM->GetWidth(), wxBM->GetHeight());
      if (!hBitmap)
        return FALSE;
      HBITMAP old1 = SelectObject(hdcMem, hBitmap);
      BitBlt(hdcMem, 0, 0, wxBM->GetWidth(), wxBM->GetHeight(),
             hdcSrc, 0, 0, SRCCOPY);

      // Select new bitmap out of memory DC
      SelectObject(hdcMem, old1);

      // Set the data
      Bool success = (Bool)::SetClipboardData(CF_BITMAP, hBitmap);

      // Clean up
      SelectObject(hdcSrc, old);
      DeleteDC(hdcSrc);
      DeleteDC(hdcMem);      
      return success;
      break;
    }

    case wxCF_METAFILE:
    {
      wxMetaFile *wxMF = (wxMetaFile *)obj;
      HANDLE data = GlobalAlloc(GHND, sizeof(METAFILEPICT) + 1);
      METAFILEPICT *mf = (METAFILEPICT *)GlobalLock(data);

      mf->mm = MM_TEXT;
      mf->xExt = width;
      mf->yExt = height;
      mf->hMF = wxMF->metafile;
      GlobalUnlock(data);
      wxMF->metafile = NULL;

      return (Bool)SetClipboardData(CF_METAFILEPICT, data);
      break;
    }
    case CF_SYLK:
    case CF_DIF:
    case CF_TIFF:
    case CF_PALETTE:
    case wxCF_DIB:
    {
      return FALSE;
      break;
    }
    default:
    {
      // Assume a user-defined block of data, NULL terminated
      break;
    }
  }
  return FALSE;
}

wxObject *wxGetClipboardData(int dataFormat)
{
  switch (dataFormat)
  {
    case wxCF_OEMTEXT:
    case wxCF_TEXT:
    {
      HANDLE hGlobalMemory = GetClipboardData(CF_TEXT);
      if (!hGlobalMemory)
        return NULL;

      char *s = new char[(int)GlobalSize(hGlobalMemory)];
      if (!s)
        return NULL;

      LPSTR lpGlobalMemory = (LPSTR)GlobalLock(hGlobalMemory);
//      for (int i = 0; i < GlobalSize(hGlobalMemory); i++)
//        s[i] = lpGlobalMemory[i];
#ifdef WIN32
      memcpy(s, lpGlobalMemory, GlobalSize(hGlobalMemory));
#elif __WATCOMC__
      memcpy(s, lpGlobalMemory, GlobalSize(hGlobalMemory));
#else
      hmemcpy(s, lpGlobalMemory, GlobalSize(hGlobalMemory));
#endif

      GlobalUnlock(hGlobalMemory);

      return (wxObject *)s;
      break;
    }

    case wxCF_BITMAP:
    {
      BITMAP bm;
      HBITMAP hBitmap = GetClipboardData(CF_BITMAP);
      if (!hBitmap)
        return NULL;

      HDC hdcMem = CreateCompatibleDC(NULL);
      HDC hdcSrc = CreateCompatibleDC(NULL);

      HBITMAP old = ::SelectObject(hdcSrc, hBitmap);
      GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);

      HBITMAP hNewBitmap = CreateBitmapIndirect(&bm);

      if (!hNewBitmap)
        return NULL;
        
      HBITMAP old1 = SelectObject(hdcMem, hNewBitmap);
      BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight,
             hdcSrc, 0, 0, SRCCOPY);

      // Select new bitmap out of memory DC
      SelectObject(hdcMem, old1);

      // Clean up
      SelectObject(hdcSrc, old);
      DeleteDC(hdcSrc);
      DeleteDC(hdcMem);

      // Create and return a new wxBitmap
      wxBitmap *wxBM = new wxBitmap;
      wxBM->ms_bitmap = hNewBitmap;
      wxBM->SetWidth(bm.bmWidth);
      wxBM->SetHeight(bm.bmHeight);
      wxBM->SetDepth(bm.bmPlanes);
      wxBM->SetOk(TRUE);
      return (wxObject *)wxBM;
      break;
    }
    case wxCF_METAFILE:
    case CF_SYLK:
    case CF_DIF:
    case CF_TIFF:
    case CF_PALETTE:
    case wxCF_DIB:
    {
      return FALSE;
      break;
    }
    default:
    {
      break;
    }
  }
  return NULL;
}

int  wxEnumClipboardFormats(int dataFormat)
{
  return ::EnumClipboardFormats(dataFormat);
}

int  wxRegisterClipboardFormat(char *formatName)
{
  return ::RegisterClipboardFormat(formatName);
}

Bool wxGetClipboardFormatName(int dataFormat, char *formatName, int maxCount)
{
  return (::GetClipboardFormatName(dataFormat, formatName, maxCount) > 0);
}

#endif // USE_CLIPBOARD
