//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2016 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
//
#include <Cuda.hpp>
#include <ThrustTypes.hpp>
#include <DistObjectCuda.hpp>

using std::cerr;
using std::cerr;
using std::endl;
using std::cerr;
using std::exception;

// Public Cuda interface methods
namespace mgx
{
  // Instantiate the copy and alloc for the types we will use.
  // How can this be avoided, type cannot propagate from .cpp to .cu files

  // Host to Device
  template int copyGPU<HostVu, DeviceVu>(HostVu*, DeviceVu*);
  template int copyGPU<HostV1u, DeviceV1u>(HostV1u*, DeviceV1u*);
  template int copyGPU<HostV2u, DeviceV2u>(HostV2u*, DeviceV2u*);
  template int copyGPU<HostV3u, DeviceV3u>(HostV3u*, DeviceV3u*);
  template int copyGPU<HostV6u, DeviceV6u>(HostV6u*, DeviceV6u*);

  template int copyGPU<HostVd, DeviceVd>(HostVd*, DeviceVd*);
  template int copyGPU<HostV1d, DeviceV1d>(HostV1d*, DeviceV1d*);
  template int copyGPU<HostV2d, DeviceV2d>(HostV2d*, DeviceV2d*);
  template int copyGPU<HostV3d, DeviceV3d>(HostV3d*, DeviceV3d*);

  template int copyGPU<HostVM1d, DeviceVM1d>(HostVM1d*, DeviceVM1d*);
  template int copyGPU<HostVM2d, DeviceVM2d>(HostVM2d*, DeviceVM2d*);
  template int copyGPU<HostVM3d, DeviceVM3d>(HostVM3d*, DeviceVM3d*);

  // Device to Host
  template int copyGPU<DeviceVu, HostVu>(DeviceVu*, HostVu*);
  template int copyGPU<DeviceV1u, HostV1u>(DeviceV1u*, HostV1u*);
  template int copyGPU<DeviceV2u, HostV2u>(DeviceV2u*, HostV2u*);
  template int copyGPU<DeviceV3u, HostV3u>(DeviceV3u*, HostV3u*);
  template int copyGPU<DeviceV6u, HostV6u>(DeviceV6u*, HostV6u*);

  template int copyGPU<DeviceVd, HostVd>(DeviceVd*, HostVd*);
  template int copyGPU<DeviceV1d, HostV1d>(DeviceV1d*, HostV1d*);
  template int copyGPU<DeviceV2d, HostV2d>(DeviceV2d*, HostV2d*);
  template int copyGPU<DeviceV3d, HostV3d>(DeviceV3d*, HostV3d*);

  template int copyGPU<DeviceVM1d, HostVM1d>(DeviceVM1d*, HostVM1d*);
  template int copyGPU<DeviceVM2d, HostVM2d>(DeviceVM2d*, HostVM2d*);
  template int copyGPU<DeviceVM3d, HostVM3d>(DeviceVM3d*, HostVM3d*);

  // Device to Device
  template int copyGPU<DeviceVu, DeviceVu>(DeviceVu*, DeviceVu*);
  template int copyGPU<DeviceV1u, DeviceV1u>(DeviceV1u*, DeviceV1u*);
  template int copyGPU<DeviceV2u, DeviceV2u>(DeviceV2u*, DeviceV2u*);
  template int copyGPU<DeviceV3u, DeviceV3u>(DeviceV3u*, DeviceV3u*);
  template int copyGPU<DeviceV6u, DeviceV6u>(DeviceV6u*, DeviceV6u*);

  template int copyGPU<DeviceVd, DeviceVd>(DeviceVd*, DeviceVd*);
  template int copyGPU<DeviceV1d, DeviceV1d>(DeviceV1d*, DeviceV1d*);
  template int copyGPU<DeviceV2d, DeviceV2d>(DeviceV2d*, DeviceV2d*);
  template int copyGPU<DeviceV3d, DeviceV3d>(DeviceV3d*, DeviceV3d*);

  template int copyGPU<DeviceVM1d, DeviceVM1d>(DeviceVM1d*, DeviceVM1d*);
  template int copyGPU<DeviceVM2d, DeviceVM2d>(DeviceVM2d*, DeviceVM2d*);
  template int copyGPU<DeviceVM3d, DeviceVM3d>(DeviceVM3d*, DeviceVM3d*);

  // Allocate and Resize
  template int allocGPU<DeviceVu>(DeviceVu**, size_t);
  template int allocGPU<DeviceV1u>(DeviceV1u**, size_t);
  template int allocGPU<DeviceV2u>(DeviceV2u**, size_t);
  template int allocGPU<DeviceV3u>(DeviceV3u**, size_t);
  template int allocGPU<DeviceV6u>(DeviceV6u**, size_t);

  template int allocGPU<DeviceVd>(DeviceVd**, size_t);
  template int allocGPU<DeviceV1d>(DeviceV1d**, size_t);
  template int allocGPU<DeviceV2d>(DeviceV2d**, size_t);
  template int allocGPU<DeviceV3d>(DeviceV3d**, size_t);

  template int allocGPU<DeviceVM1d>(DeviceVM1d**, size_t);
  template int allocGPU<DeviceVM2d>(DeviceVM2d**, size_t);
  template int allocGPU<DeviceVM3d>(DeviceVM3d**, size_t);
} 
