/* VectorNav HSI Calibration Library v1.0.0.2
 *
 * Copyright (c) 2018 VectorNav Technologies, LLC
 *
 * This source code is proprietary to and copyrighted by VectorNav Technologies, LLC and is
 * available solely under license from VectorNav. All rights reserved. If you do not have a
 * license to use this source code from VectorNav, any use hereof is strictly prohibited by
 * U.S. law and other applicable law. This source code is restricted for use solely with the
 * products of VectorNav and as otherwise set forth in any agreement with VectorNav. Any
 * disclosure of this source code to the public or to any third party is also prohibited.
 */
#ifndef _VN_VNVECTOR_H_
#define _VN_VNVECTOR_H_

#include <stddef.h>
#include "vncompiler.h"
#include "vnenum.h"

#ifdef __cplusplus
extern "C" {
#endif

/** \brief 3-component vector with an underlying data type of <c>float</c>. */
union vn_vec3f
{
  float c[3];    /**< Indexable. */

  #if VN_ANONYMOUS_UNIONS

  struct
  {
    float x;        /**< X component. */
    float y;        /**< Y component. */
    float z;        /**< Z component. */
  };

  struct
  {
    float c0;       /**< Component 0. */
    float c1;       /**< Component 1. */
    float c2;       /**< Component 2. */
  };

  #endif
};

/** \brief 3-component vector with an underlying data type of <c>double</c>. */
union vn_vec3d
{
  double c[3];      /**< Indexable. */

  #if VN_ANONYMOUS_UNIONS

  struct
  {
    double x;       /**< The x component. */
    double y;       /**< The y component. */
    double z;       /**< The z component. */
  };

  struct
  {
    double c0;      /**< Component 0. */
    double c1;      /**< Component 1. */
    double c2;      /**< Component 2. */
  };

  #endif
};

/** \brief Represents a 4 component vector with an underlying data type of <c>float</c>. */
union vn_vec4f
{
  float c[4];        /**< Indexable. */

  #if VN_ANONYMOUS_UNIONS

  struct
  {
    float x;        /**< The x component. */
    float y;        /**< The y component. */
    float z;        /**< The z component. */
    float w;        /**< The w component. */
  };

  struct
  {
    float c0;       /**< Component 0. */
    float c1;       /**< Component 1. */
    float c2;       /**< Component 2. */
    float c3;       /**< Component 2. */
  };

  #endif
};

#ifndef __cplusplus
typedef union vn_vec3f vn_vec3f_t;
typedef union vn_vec3d vn_vec3d_t;
typedef union vn_vec4f vn_vec4f_t;
#endif

/**\defgroup mathCreateFunctions Math Create Functions \{ */

/**\brief Creates a <c>vn_vec3f</c> initialized with provided values.
 * \param[in] x x-component.
 * \param[in] y y-component.
 * \param[in] z z-component.
 * \return The initialized <c>vn_vec3f</c>. */
union vn_vec3f
create_v3f(
    float x,
    float y,
    float z);

/**\brief Returns a <c>vn_vec3f</c> initialized to zero.
 * \return The zero <c>vn_vec3f</c>. */
union vn_vec3f
zero_v3f(void);

/**\brief Initializes a <c>vn_vec3f</c> with the given values.
 * \param[out] v <c>vn_vec3f</c> to initialize.
 * \param[in] x x-component.
 * \param[in] y y-component.
 * \param[in] z z-component. */
void
init_v3f(
    union vn_vec3f *v,
    float x,
    float y,
    float z);

/**\brief Initializes a <c>vn_vec3f</c> from a scalar value.
 * \param[out] v <c>vn_vec3f</c> to initialize.
 * \param[in] s Scalar value to initialize <c>v</c>. */
void
init_v3f_s(
    union vn_vec3f *v,
    float s);

/**\brief Initializes a <c>vn_vec3f</c> from an array of floats.
 * \param[out] v <c>vn_vec3f</c> to initialize.
 * \param[in] fa Array of floats to initialize <c>v</c> from. Must contain
 *     at least 3 elements. */
void
init_v3f_fa(
    union vn_vec3f *v,
    const float *fa);

/**\brief Adds two <c>vn_vec3f</c> together.
 * \param[in] lhs The left-hand side <c>vn_vec3f</c>.
 * \param[in] rhs The right-hand side <c>vn_vec3f</c>.
 * \return The resulting <c>vn_vec3f</c> from adding <c>lhs</c> and <c>rhs</c> together. */
union vn_vec3f
add_v3f_v3f(
    union vn_vec3f lhs,
    union vn_vec3f rhs);

/**\brief Creates a <c>vn_vec3d</c> initialized with provided values.
 * \param[in] x x-component.
 * \param[in] y y-component.
 * \param[in] z z-component.
 * \return The initialized <c>vn_vec3d</c>. */
union vn_vec3d
create_v3d(
    double x,
    double y,
    double z);

/**\brief Returns a <c>vn_vec3d</c> initialized to zero.
 * \return The zero <c>vn_vec3d</c>. */
union vn_vec3d
zero_v3d(void);

/**\brief Creates a <c>vn_vec3f</c> initialized with provided values.
 * \param[in] x x-component.
 * \param[in] y y-component.
 * \param[in] z z-component.
 * \param[in] w w-component.
 * \return The initialized <c>vn_vec4f</c>. */
union vn_vec4f
create_v4f(
    float x,
    float y,
    float z,
    float w);

/**\brief Returns a <c>vn_vec4f</c> initialized to zero.
 * \return The zero <c>vn_vec4f</c>. */
union vn_vec4f
zero_v4f(void);

/** \} */

/**\brief Converts a <c>vn_vec3f</c> to a string.
 * \param[out] out The char buffer to output the result to.
 * \param[in] outSize Size of the buffer <c>out</c>.
 * \param[in] v The <c>vn_vec3f</c> to convert.
 * \return Any errors encountered. */
enum VnError
to_string_vec3f(
    char* out,
    size_t outSize,
    union vn_vec3f v);

/**\brief Converts a <c>vn_vec3d</c> to a string.
 * \param[out] out The char buffer to output the result to.
 * \param[in] outSize Size of the buffer <c>out</c>.
 * \param[in] v The <c>vn_vec3d</c> to convert.
 * \return Any errors encountered. */
enum VnError
to_string_vec3d(
    char* out,
    size_t outSize,
    union vn_vec3d v);

/**\brief Converts a <c>vn_vec4f</c> to a string.
 * \param[out] out The char buffer to output the result to.
 * \param[in] outSize Size of the buffer <c>out</c>.
 * \param[in] v The <c>vn_vec4f</c> to convert.
 * \return Any errors encountered. */
enum VnError
to_string_vec4f(
    char* out,
    size_t outSize,
    union vn_vec4f v);

#ifdef __cplusplus
}
#endif

#endif
