#include <iostream>
#include <vector>
#include <algorithm>

#include "scltypes.h"
#include "sclerror.h"

//The OpenCL C++ bindings, with exceptions
#ifdef __APPLE__
  #include "cl_ver_1_1.hpp"
#else
  #include <CL/cl.hpp>
#endif


int main()
{
  cl_int err;

  std::vector<cl::Platform> platformList;
  err = cl::Platform::get(&platformList);
  if (err != CL_SUCCESS) scl::error("Error, cl::Platform::get failed");

  std::vector<cl::Platform>::const_iterator plitr;
  for (plitr=platformList.begin(); plitr!=platformList.end(); ++plitr) {

    std::string platformVendor;
    err = plitr->getInfo((cl_platform_info)CL_PLATFORM_VENDOR, &platformVendor);
    if (err != CL_SUCCESS) scl::error("Error, cl::Platform::getInfo failed");
    std::cout << '\n';
    std::cout << platformVendor << '\n';

    std::string platformName;
    err = plitr->getInfo((cl_platform_info)CL_PLATFORM_NAME, &platformName);
    if (err != CL_SUCCESS) scl::error("Error, cl::Platform::getInfo failed");
    std::cout << platformName << '\n';

    std::vector<cl::Device> deviceList;
    err = plitr->getDevices((cl_device_type)CL_DEVICE_TYPE_ALL, &deviceList);
    if (err != CL_SUCCESS) scl::error("Error, cl::Platform::getDevices failed");

    std::vector<cl::Device>::const_iterator dlitr;
    for (dlitr=deviceList.begin(); dlitr!=deviceList.end(); ++dlitr) {

      std::string deviceName;
      err = dlitr->getInfo((cl_device_info)CL_DEVICE_NAME, &deviceName);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");
      std::cout << '\n';
      std::cout << deviceName << '\n';

      cl_device_type deviceType;
      err = dlitr->getInfo((cl_device_info)CL_DEVICE_TYPE, &deviceType);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");
      std::cout << "  Device type = " << deviceType << '\n';

      std::vector<size_t> deviceSizes;
      cl_device_info work_item_sizes = CL_DEVICE_MAX_WORK_ITEM_SIZES;
      err = dlitr->getInfo(work_item_sizes, &deviceSizes);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");

      std::vector<size_t>::const_iterator dsitr;
      std::cout << "  Max work item sizes: " << '\n';;
      for(dsitr=deviceSizes.begin(); dsitr!=deviceSizes.end(); ++dsitr) {
        std::cout << "    " << *dsitr << '\n';
      }

      cl_device_info work_group_size = CL_DEVICE_MAX_WORK_GROUP_SIZE;
      size_t groupSize;
      err = dlitr->getInfo(work_group_size, &groupSize);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");
      std::cout << "  Max work group size = " << groupSize << '\n';

      cl_device_info compute_units = CL_DEVICE_MAX_COMPUTE_UNITS;
      cl_uint computeSize;
      err = dlitr->getInfo(compute_units, &computeSize);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");
      std::cout << "  Max compute units = " << computeSize << '\n';

      cl_device_info double_info = CL_DEVICE_DOUBLE_FP_CONFIG; 
      cl_device_fp_config double_conf;
      err = dlitr->getInfo(double_info, &double_conf);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");
      std::cout << std::boolalpha;
      std::cout << "  Has double = " << bool(double_conf) << '\n'; 

      /*
      cl_device_info unified_info = CL_DEVICE_HOST_UNIFIED_MEMORY;
      cl_bool unifiedMemory;
      err = dlitr->getInfo(unified_info, &unifiedMemory);
      if (err != CL_SUCCESS) scl::error("Error, cl::Device::getInfo failed");
      std::cout << "  Has unified memory = " << unifiedMemory << '\n';
      */
    }
    std::cout << '\n';
  }

  return 0;
}

