/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
/**
 * itkOpenCLMacro.h defines standard OpenCL macros, constants, and other
 * parameters. Macros are available for built-in types; for string classes;
 * vector arrays; object pointers; and debug, warning,
 * and error printout information.
 */

#ifndef __itkOpenCLMacro_h
#define __itkOpenCLMacro_h

#include "itkMacro.h"
#include "itkOpenCLExport.h"

#include <string>
#include <sstream>

//! This macro is used to print out debug message to the current message handler
//! in instance methods
//! itkOpenCLDebugMacro(<< "Debug message" << this->SomeVariable);
#define itkOpenCLDebugMacro( x ) \
  itkOpenCLDebugWithObjectMacro( this, x )

//! This macro is used to print out warning message to the current message
//! handler in instance methods
//! itkOpenCLWarningMacro(<< "Warning message" << this->SomeVariable);
#define itkOpenCLWarningMacro( x ) \
  itkOpenCLWarningWithObjectMacro( this, x )

//! This macro is used to print out error message to the current message handler
//! in instance methods
//! itkOpenCLErrorMacro(<< "Error message" << this->SomeVariable);
#define itkOpenCLErrorMacro( x ) \
  itkOpenCLErrorWithObjectMacro( this, x )

//! This macro is used to print out debug message to the current message handler
//! in main() function or generic functions
//! itkOpenCLDebugMacroGeneric(<< "Debug message generic" << SomeVariable);
#define itkOpenCLDebugMacroGeneric( x )                          \
  {                                                              \
    std::stringstream itkmsg;                                    \
    itkmsg << __FILE__                                           \
           << "(" << __LINE__ << "): itkOpenCL generic debug."   \
           << "\nDebug: in function: " << __FUNCTION__           \
           << "\nDetails: " x << "\n\n";                         \
    ::itk::OutputWindowDisplayDebugText( itkmsg.str().c_str() ); \
  }

//! This macro is used to print out warning message to the current message
//! handler in main() function or generic functions
//! itkOpenCLWarningMacroGeneric(<< "Warning message generic" << SomeVariable);
#define itkOpenCLWarningMacroGeneric( x )                          \
  {                                                                \
    std::stringstream itkmsg;                                      \
    itkmsg << __FILE__                                             \
           << "(" << __LINE__ << "): itkOpenCL generic warning."   \
           << "\nWarning: in function: " << __FUNCTION__           \
           << "\nDetails: " x << "\n\n";                           \
    ::itk::OutputWindowDisplayWarningText( itkmsg.str().c_str() ); \
  }

//! This macro is used to print out error message to the current message handler
//! in main() function or generic functions
//! itkOpenCLErrorMacroGeneric(<< "Error message generic" << SomeVariable);
#define itkOpenCLErrorMacroGeneric( x )                          \
  {                                                              \
    std::stringstream itkmsg;                                    \
    itkmsg << __FILE__                                           \
           << "(" << __LINE__ << "): itkOpenCL generic error."   \
           << "\nError: in function: " << __FUNCTION__           \
           << "\nDetails: " x << "\n\n";                         \
    ::itk::OutputWindowDisplayErrorText( itkmsg.str().c_str() ); \
  }

/** This macro is used to print out debug statements. For example:
 * \code
 * itkOpenCLDebugWithObjectMacro(self, "Debug message" << variable);
 * \endcode
 * File and line information will be printed in Visual Studio format.
 * \sa itkOpenCLWarningWithObjectMacro(), itkOpenCLErrorWithObjectMacro() */
#define itkOpenCLDebugWithObjectMacro( self, x )                          \
  {                                                                       \
    std::stringstream itkmsg;                                             \
    itkmsg << __FILE__                                                    \
           << "(" << __LINE__ << "): itkOpenCL debug."                    \
           << "\nDebug: in function: " << __FUNCTION__                    \
           << "; Name: " << self->GetNameOfClass() << " (" << self << ")" \
           << "\nDetails: " x << "\n\n";                                  \
    ::itk::OutputWindowDisplayDebugText( itkmsg.str().c_str() );          \
  }

/** This macro is used to print out warnings. For example:
 * \code
 * itkOpenCLWarningWithObjectMacro(self, "Warning message" << variable);
 * \endcode
 * File and line information will be printed in Visual Studio format.
 * \sa itkOpenCLDebugWithObjectMacro(), itkOpenCLErrorWithObjectMacro() */
#define itkOpenCLWarningWithObjectMacro( self, x )                        \
  {                                                                       \
    std::stringstream itkmsg;                                             \
    itkmsg << __FILE__                                                    \
           << "(" << __LINE__ << "): itkOpenCL warning."                  \
           << "\nWarning: in function: " << __FUNCTION__                  \
           << "; Name: " << self->GetNameOfClass() << " (" << self << ")" \
           << "\nDetails: " x << "\n\n";                                  \
    ::itk::OutputWindowDisplayWarningText( itkmsg.str().c_str() );        \
  }

/** This macro is used to print out errors. For example:
 * \code
 * itkOpenCLErrorWithObjectMacro(self, "Error message" << variable);
 * \endcode
 * File and line information will be printed in Visual Studio format.
 * \sa itkOpenCLWarningWithObjectMacro(), itkOpenCLDebugWithObjectMacro() */
#define itkOpenCLErrorWithObjectMacro( self, x )                          \
  {                                                                       \
    std::stringstream itkmsg;                                             \
    itkmsg << __FILE__                                                    \
           << "(" << __LINE__ << "): itkOpenCL error."                    \
           << "\nError: in function: " << __FUNCTION__                    \
           << "; Name: " << self->GetNameOfClass() << " (" << self << ")" \
           << "\nDetails: " x << "\n\n";                                  \
    ::itk::OutputWindowDisplayErrorText( itkmsg.str().c_str() );          \
  }

namespace itk
{
/** \class OpenCLCompileError
 * Exception thrown when OpenCL program failed to build.
 */
class ITKOpenCL_EXPORT OpenCLCompileError : public ExceptionObject
{
public:

  /** Default constructor. Needed to ensure the exception object can be copied. */
  OpenCLCompileError() : ExceptionObject() {}

  /** Constructor. Needed to ensure the exception object can be copied. */
  OpenCLCompileError( const char * file, unsigned int lineNumber ) : ExceptionObject( file, lineNumber ) {}

  /** Constructor. Needed to ensure the exception object can be copied. */
  OpenCLCompileError( const std::string & file, unsigned int lineNumber ) : ExceptionObject( file, lineNumber ) {}

  /** Virtual destructor needed for subclasses. */
  ~OpenCLCompileError() override {}

  const char * GetNameOfClass() const override
  { return "OpenCLCompileError"; }
};

}
#endif /* __itkOpenCLMacro_h */
