//
// 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 test_conformance_checker_Image_MEM_HOST_NO_ACCESS_h
#define test_conformance_checker_Image_MEM_HOST_NO_ACCESS_h

#include "checker_image_mem_host_write_only.hpp"

template < class T>
class cImage_check_mem_host_no_access : public cImage_check_mem_host_write_only<T>
{
public:
  cImage_check_mem_host_no_access (cl_device_id deviceID, cl_context context, cl_command_queue queue)
  : cImage_check_mem_host_write_only <T> (deviceID,context, queue)
  {
  }

  ~cImage_check_mem_host_no_access() {};

  cl_int verify_RW_Image();
  cl_int verify_RW_Image_Mapping();
};

template < class T>
cl_int cImage_check_mem_host_no_access<T>:: verify_RW_Image()
{
  this->Init_rect();

  cl_event event;
  size_t img_orig[3] = {0, 0, 0};
  size_t img_region[3] = {0, 0, 0};
  img_region[0] = this->m_cl_Image_desc.image_width;
  img_region[1] = this->m_cl_Image_desc.image_height;
  img_region[2] = this->m_cl_Image_desc.image_depth;

  int color[4] = {0xFF, 0xFF, 0xFF, 0xFF};
  cl_int err = CL_SUCCESS;
  err = clEnqueueFillImage(this->m_queue, this->m_Image,
                          &color,
                          img_orig, img_region,
                          0, NULL, &event);

  if (!this->m_blocking) {
    err = clWaitForEvents(1, &event);
    test_error(err, "clWaitForEvents error");
  }

  this->update_host_mem_2();

  int total = (int)(this->region[0] * this->region[1] * this->region[2]);

  T v = 0xFFFFFFFF;
  int tot = (int)(this->host_m_2.Count(v));
  if(tot != total){
    log_error("Buffer data content difference found\n");
    return FAILURE;
  }

  err = clEnqueueWriteImage(this->m_queue, this->m_Image, this->m_blocking,
                            this->buffer_origin, this->region,
                            this-> buffer_row_pitch_bytes, this->buffer_slice_pitch_bytes,
                            this->host_m_1.pData, 0, NULL, &event);

  if (err == CL_SUCCESS) {
    log_error("Calling clEnqueueWriteImage on a memory object created with the CL_MEM_HOST_NO_ACCESS flag should not return CL_SUCCESS\n");
    err = FAILURE;
    return err;

  } else {
    log_info("Test succeeded\n\n");
    err = CL_SUCCESS;
  }

  v = 0;
  this->host_m_2.Set_to(v);
  err = clEnqueueReadImage(this->m_queue, this->m_Image, this->m_blocking,
                           this->buffer_origin, this->region,
                           this-> buffer_row_pitch_bytes, this->buffer_slice_pitch_bytes,
                           this->host_m_2.pData, 0, NULL, &event);

  if (err == CL_SUCCESS) {
    log_error("Calling clEnqueueReadImage on a memory object created with the CL_MEM_HOST_NO_ACCESS flag should not return CL_SUCCESS\n");
    err = FAILURE;
    return err;

  } else {
    log_info("Test succeeded\n\n");
    err = CL_SUCCESS;
  }

  return err;
}

template < class T>
cl_int cImage_check_mem_host_no_access<T>::verify_RW_Image_Mapping()
{
  this->Init_rect();

  cl_event event;
  cl_int err = CL_SUCCESS;

  T * dataPtr = (T*) clEnqueueMapImage(this->m_queue, this->m_Image, this->m_blocking,
                                       CL_MAP_WRITE,
                                       this->buffer_origin, this->region,
                                       &(this-> buffer_row_pitch_bytes),
                                       &(this->buffer_slice_pitch_bytes),
                                       0, NULL, &event, &err);

  if ( err ==  CL_SUCCESS)    {
    log_error("Calling clEnqueueMapImage (CL_MAP_WRITE) on a memory object created with the CL_MEM_HOST_NO_ACCESS flag should not return CL_SUCCESS\n");
    err = FAILURE;
    return err;

  } else {
    log_info("Test succeeded\n\n");
    err = CL_SUCCESS;
  }

  dataPtr = (T*) clEnqueueMapImage(this->m_queue, this->m_Image, this->m_blocking,
                                   CL_MAP_READ,
                                   this->buffer_origin, this->region,
                                   &(this-> buffer_row_pitch_bytes),
                                   &(this->buffer_slice_pitch_bytes),
                                   0, NULL, &event, &err);

  if (err == CL_SUCCESS) {
    log_error("Calling clEnqueueMapImage (CL_MAP_READ) on a memory object created with the CL_MEM_HOST_NO_ACCESS flag should not return CL_SUCCESS\n");
    err = FAILURE;
    return err;

  } else {
    log_info("Test succeeded\n\n");
    err = CL_SUCCESS;
  }

  return err;
}

#endif
