# Basic functions for ODEInterface

"""
  supported (signed) Integer types for Fortran codes.
  """
FortranInt = Union{Int32,Int64}

"""
  dummy function returning nothing.
  """
function dummy_func()
  return nothing
end

"""
  tests if `cand` is a number.
  """
function isscalar(cand)
  return isa(cand,Base.Number)
end

"""Bitmask: log nothing."""
const LOG_NOTHING    = UInt64(0)

"""Bitmask: log some general info (esp. for main call)."""
const LOG_GENERAL    = UInt64(1)<<0

"""Bitmask: log calls to right-hand side."""
const LOG_RHS        = UInt64(1)<<1

"""Bitmask: log arguments passed to C/Fortran solvers."""
const LOG_SOLVERARGS = UInt64(1)<<2

"""Bitmask: log calls to solout function."""
const LOG_SOLOUT     = UInt64(1)<<3

"""Bitmask: log calls to julia output function."""
const LOG_OUTPUTFCN  = UInt64(1)<<4

"""Bitmask: log calls to eval_sol_fcn function."""
const LOG_EVALSOL    = UInt64(1)<<5

"""Bitmask: log calls to mass function."""
const LOG_MASS       = UInt64(1)<<6

"""Bitmask: log calls to jacobian function (of right-hand side)."""
const LOG_JAC        = UInt64(1)<<7

"""Bitmask: log calls to boundary condition function."""
const LOG_BC         = UInt64(1)<<8

"""Bitmask: during boundary value problems:
  log calls to initial value solver."""
const LOG_BVPIVPSOL  = UInt64(1)<<9

"""Bitmask: log calls to right-hand side derivative function."""
const LOG_RHSDT      = UInt64(1)<<10

"""Bitmask: log calls to jacobian function of boundary-/side-conditions."""
const LOG_JACBC      = UInt64(1)<<11

"""Bitmask: log calls to guess function."""
const LOG_GUESS      = UInt64(1)<<12

"""Bitmask: log everything."""
const LOG_ALL        = UInt64(0xFFFFFFFFFFFFFFFF)

"""
  macro for importing all the LOG bitmasks.
  """
macro import_LOG()
  :(
    using ODEInterface: LOG_NOTHING, LOG_GENERAL, LOG_RHS,
                        LOG_SOLVERARGS, LOG_SOLOUT, LOG_OUTPUTFCN,
                        LOG_EVALSOL, LOG_MASS, LOG_JAC, LOG_BC,
                        LOG_BVPIVPSOL, LOG_RHSDT, LOG_JACBC,
                        LOG_GUESS,
                        LOG_ALL
  )
end

"""
       function getVectorCheckLength(vec,T::DataType,d::Integer,copy=true)
                         -> Vector{T}

  try to convert to `Vector{T}` and checks given length.
  If the `docopy` argument is `true` then the return value will
  always be a different object than `vec`: If `convert` didn't need to
  create a copy then this is done by this function.

  throws ArgumentErrorODE this is not possible.
  """
function getVectorCheckLength(vec,T::DataType,d::Integer,docopy=true)
  result = nothing
  try
    result = convert(Vector{T},vec)
  catch e
    throw(ArgumentErrorODE(
      string("Cannot convert vec with type ",typeof(vec),
             " to Vector{",T,"}"),:vec,e))
  end
  length(result)!=d && throw(ArgumentErrorODE(
    string("vec has wrong length: expected $d found ",length(result)),:vec))
  if docopy && result ≡ vec
    result = copy(vec)
  end
  return result
end

"""
       function getMatrixCheckSize(mat,T::DataType,
                    m::Integer,n::Integer,docopy=true) -> Matrix{T}

  try to convert to `Matrix{T}' and checks the size.
  if the `docopy` argument is `true` then the return value will
  always be a different object than `mat`: If `convert` didn't need
  to create a copy then this is done by this function.

  throws ArgumentErrorODE this is not possible.
  """
function getMatrixCheckSize(mat,T::DataType,m::Integer,n::Integer,docopy=true)
  result = nothing
  try
    result = convert(Matrix{T},mat)
  catch e
    throw(ArgumentErrorODE(
      string("Cannot convert mat with type ",typeof(mat),
             "to Matrix{",T,"}"),:mat,e))
  end
  size(mat,1) ≠ m && throw(ArgumentErrorODE(
    string("mat has wrong number of rows: expedted $m found ",size(mat,1)),
    :mat))
  size(mat,2) ≠ n && throw(ArgumentErrorODE(
    string("mat has wrong number of columns: expedted $n found ",size(mat,2)),
    :mat))
  if docopy && result ≡ mat
    result = copy(mat)
  end
  return result
end

"""
  returns function view or function sub for generating views to arrays.
  """
function get_view_function()
  return isdefined(Base, :view) ? Base.view : Base.sub
end


"""
  Type encapsulating all required data for ODE-Solver-Callbacks.
  """
abstract type ODEinternalCallInfos end

# vim:syn=julia:cc=79:fdm=indent:
