// GenFem - A high-level finite element library
// Copyright (C) 2010-2026 Eric Bechet
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org>.

#ifndef _GENTENSOR0_H_
#define _GENTENSOR0_H_

#include "genTensorBase.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>

template<class scalar=double,int N=3>
class genTensor0 : public genTensorBase<N>
{
 protected:
  scalar _val;
 public:
  // operator on the tensor
  inline int getIndex() const { return genTensorBase<N>::getIndex(); }
  inline scalar & operator()(){ return _val; }
  inline scalar operator()() const { return _val; }
  // default constructor, null tensor
  genTensor0(const scalar v=scalar())
  {
    _val = v;
  }
  genTensor0(const scalar* array)
  {
    _val = array[0];
  }
  genTensor0(const std::vector<scalar> &array)
  {
    _val = array[0];
  }
  template<int N2> genTensor0(const genTensor0<scalar,N2> &in)
  {
    _val = in._val;
  }

//  inline operator scalar &() { return _val; } // no way to modify it as it were a scalar; need to use operator()
  inline operator scalar const () const { return _val; } // direct conversion to scalar allowed

  void negate()
  {
    _val = -_val;
  }

  // operator on the data list
  genTensor0<scalar,N> operator+(const genTensor0<scalar,N> &other) const
  {
    genTensor0<scalar,N> res(*this);
    res._val += other._val;
    return res;
  }
  genTensor0<scalar,N> operator-(const genTensor0<scalar,N> &other) const
  {
    genTensor0<scalar,N> res(*this);
    res._val -= other._val;
    return res;
  }
  genTensor0<scalar,N> & operator+=(const genTensor0<scalar,N> &other)
  {
   _val += other._val;
    return *this;
  }
  genTensor0<scalar,N> & operator-=(const genTensor0<scalar,N> &other)
  {
    _val -= other._val;
    return *this;
  }
//// misuse of the operator *
//   genTensor0<scalar,N> & operator*=(const genTensor0<scalar,N> &other)
//   {
//     _val *= other._val;
//     return *this;
//   }
  genTensor0<scalar,N> & operator*=(const scalar &s)
  {
    _val *= s;
    return *this;
  }

  genTensor0<scalar,N> & operator/=(const genTensor0<scalar,N> &other)
  {
    _val /= other._val;
    return *this;
  }

  void print(std::string name="") const
  {
    std::cout << "scalar " << name << " " << *this;
  }
};

template <class scalar,int N> std::ostream & operator<<(std::ostream &output,const genTensor0<scalar,N> &t)
{
  output.precision(5);
  output << std::setiosflags( std::ios::showpos );
  output << std::setiosflags( std::ios::scientific );

  output << t();

  output << std::resetiosflags( std::ios::showpos );
  output << std::resetiosflags( std::ios::scientific );
  return output;
}

template<class scalar,int N> inline scalar dot(const genTensor0<scalar,N> &a, const genTensor0<scalar,N> &b)
{
  scalar prod = scalar();
  prod = a()*b();
  return prod;
}

template<class scalar,int N1,int N2> inline scalar dot(const genTensor0<scalar,N1> &a, const genTensor0<scalar,N2> &b)
{ 
  scalar prod = scalar();
  prod += a()*b();
  return prod;
}

template<class scalar,int N> inline scalar norm(const genTensor0<scalar,N> &v)
{
  return sqrt(dot(v,v));
}

// tensor product
template<class scalar,int N> inline void tensprod(const genTensor0<scalar,N> &a, const genTensor0<scalar,N> &b, genTensor0<scalar,N> &c)
{
  c() = a()*b();
}

// full contracted product
template <class scalar,int N> inline genTensor0<scalar,N> operator*(const scalar s, const genTensor0<scalar,N> v)
{ return genTensor0<scalar,N>(s) *= v;}

template <class scalar,int N> inline genTensor0<scalar,N> operator*(const genTensor0<scalar,N> v, const scalar s)
{ return genTensor0<scalar,N>(v) *= genTensor0<scalar,N>(s); }

template <class scalar,int N> inline genTensor0<scalar,N> operator+(const scalar s, const genTensor0<scalar,N> v)
{ return genTensor0<scalar,N>(s) += v;}

template <class scalar,int N> inline genTensor0<scalar,N> operator+(const genTensor0<scalar,N> v, const scalar s)
{ return genTensor0<scalar,N>(v)+=genTensor0<scalar,N>(s); }

template <class scalar,int N> inline genTensor0<scalar,N> operator-(const scalar s, const genTensor0<scalar,N> v)
{ return genTensor0<scalar,N>(s) -= v;}

template <class scalar,int N> inline genTensor0<scalar,N> operator-(const genTensor0<scalar,N> v, const scalar s)
{ return  genTensor0<scalar,N>(v) -= genTensor0<scalar,N>(s); }

template <class scalar,int N> inline genTensor0<scalar,N> operator/(const scalar s, const genTensor0<scalar,N> v)
{ return genTensor0<scalar,N>(s) /= v;}

template <class scalar,int N> inline genTensor0<scalar,N> operator/(const genTensor0<scalar,N> v, const scalar s)
{ return  genTensor0<scalar,N>(v) /= genTensor0<scalar,N>(s); }

template <class scalar,int N1,int N2> inline genTensor0<scalar,((N1>=N2)?N1:N2)> operator*(const genTensor0<scalar,N1> v, const genTensor0<scalar,N2> t)
{
  return  genTensor0<scalar,((N1>=N2)?N1:N2)>(v()*t());
}
template <class scalar,int N1,int N2> inline genTensor0<scalar,((N1>=N2)?N1:N2)> operator+(const genTensor0<scalar,N1> v, const genTensor0<scalar,N2> t)
{
  return  genTensor0<scalar,((N1>=N2)?N1:N2)>(v()+t());
}
template <class scalar,int N1,int N2> inline genTensor0<scalar,((N1>=N2)?N1:N2)> operator-(const genTensor0<scalar,N1> v, const genTensor0<scalar,N2> t)
{
  return  genTensor0<scalar,((N1>=N2)?N1:N2)>(v()-t());
}
template <class scalar,int N1,int N2> inline genTensor0<scalar,((N1>=N2)?N1:N2)> operator/(const genTensor0<scalar,N1> v, const genTensor0<scalar,N2> t)
{
  return  genTensor0<scalar,((N1>=N2)?N1:N2)>(v()/t());
}

#endif // _GENTENSOR0_H_
