//
// Copyright (c) 2017 The Khronos Group Inc.
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef __WRAPPERS_H
#define __WRAPPERS_H

#if defined(_WIN32)
#include <d3d9.h>
#include <dxvahd.h>
#include <tchar.h>
#endif

class CDeviceWrapper {
public:
  enum TAccelerationType
  {
    ACCELERATION_HW,
    ACCELERATION_SW,
  };

  CDeviceWrapper();
  virtual ~CDeviceWrapper();

  virtual bool AdapterNext() = 0;
  virtual unsigned int AdapterIdx() const = 0;
  virtual void *Device() const = 0;
  virtual bool Status() const = 0;
  virtual void *D3D() const = 0;

#if defined(_WIN32)
  HWND WindowHandle() const;
#endif
  int WindowWidth() const;
  int WindowHeight() const;
  void WindowInit();


  static TAccelerationType AccelerationType();
  static void AccelerationType(TAccelerationType accelerationTypeNew);

private:
  static LPCTSTR WINDOW_TITLE;
  static const int WINDOW_WIDTH;
  static const int WINDOW_HEIGHT;
  static TAccelerationType accelerationType;

#if defined(_WIN32)
  HMODULE _hInstance;
  HWND _hWnd;
#endif

  void WindowDestroy();
};

class CSurfaceWrapper
{
public:
  CSurfaceWrapper();
  virtual ~CSurfaceWrapper();
};

#if defined(_WIN32)
//windows specific wrappers
class CD3D9Wrapper: public CDeviceWrapper {
public:
  CD3D9Wrapper();
  ~CD3D9Wrapper();

  virtual bool AdapterNext();
  virtual unsigned int AdapterIdx() const;
  virtual void *Device() const;
  virtual bool Status() const;
  virtual void *D3D() const;

private:
  LPDIRECT3D9 _d3d9;
  LPDIRECT3DDEVICE9 _d3dDevice;
  D3DDISPLAYMODE _d3ddm;
  D3DADAPTER_IDENTIFIER9 _adapter;
  bool _status;
  unsigned int _adapterIdx;
  bool _adapterFound;

  D3DFORMAT Format();
  D3DADAPTER_IDENTIFIER9 Adapter();
  bool Init();
  void Destroy();
};

class CD3D9ExWrapper: public CDeviceWrapper {
public:
  CD3D9ExWrapper();
  ~CD3D9ExWrapper();

  virtual bool AdapterNext();
  virtual unsigned int AdapterIdx() const;
  virtual void *Device() const;
  virtual bool Status() const;
  virtual void *D3D() const;

private:
  LPDIRECT3D9EX _d3d9Ex;
  LPDIRECT3DDEVICE9EX _d3dDeviceEx;
  D3DDISPLAYMODEEX _d3ddmEx;
  D3DADAPTER_IDENTIFIER9 _adapter;
  bool _status;
  unsigned int _adapterIdx;
  bool _adapterFound;

  D3DFORMAT Format();
  D3DADAPTER_IDENTIFIER9 Adapter();
  bool Init();
  void Destroy();
};

class CDXVAWrapper: public CDeviceWrapper {
public:
  CDXVAWrapper();
  ~CDXVAWrapper();

  virtual bool AdapterNext();
  virtual unsigned int AdapterIdx() const;
  virtual void *Device() const;
  virtual bool Status() const;
  virtual void *D3D() const;
  const CD3D9ExWrapper &D3D9() const;

private:
  CD3D9ExWrapper _d3d9;
  IDXVAHD_Device *_dxvaDevice;
  bool _status;
  bool _adapterFound;

  static const D3DFORMAT RENDER_TARGET_FORMAT;
  static const D3DFORMAT VIDEO_FORMAT;
  static const unsigned int VIDEO_FPS;

  bool DXVAHDInit();
  void DXVAHDDestroy();
};

class CD3D9SurfaceWrapper: public CSurfaceWrapper
{
public:
  CD3D9SurfaceWrapper();
  CD3D9SurfaceWrapper( IDirect3DSurface9* mem );
  ~CD3D9SurfaceWrapper();

  operator IDirect3DSurface9*() { return mMem; }
  IDirect3DSurface9* * operator&() { return &mMem; }
  IDirect3DSurface9* operator->() const { return mMem; }

private:
  IDirect3DSurface9* mMem;
};
#endif

#endif  // __D3D_WRAPPERS
