/*

  xmunipack - tone profiles

  Copyright © 2009-2011, 2018-9 F.Hroch (hroch@physics.muni.cz)

  This file is part of Munipack.

  Munipack is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Munipack is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Munipack.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "fits.h"
#include <algorithm>
#include <cfloat>

using namespace std;


FitsItt::FitsItt(int t):
  itt(t),amp(1.0),zero(0.0),
  Func(&FitsItt::Itt_linear)
{
  SetItt(itt);
}

void FitsItt::SetItt(int i)
{
  wxASSERT(ITT_FIRST < i && i < ITT_LAST);
  itt = ITT_FIRST < i && i < ITT_LAST ? i : ITT_LINE;

  switch (itt) {
  case ITT_SQRT:  Func = &FitsItt::Itt_sqrt; break;
  case ITT_SQR:   Func = &FitsItt::Itt_square; break;
  case ITT_LOGIS: Func = &FitsItt::Itt_logis; break;
  default:        Func = &FitsItt::Itt_linear; break;
  }
}

void FitsItt::SetItt(const wxString& a)
{
  for(int i = ITT_FIRST+1; i < ITT_LAST; i++)
    if( a == Type_str(i) ) {
      SetItt(i);
      return;
    }
}


int FitsItt::GetItt() const
{
  return itt;
}

wxString FitsItt::GetItt_str() const
{
  return Type_str(itt);
}

void FitsItt::SetAmp(float x)
{
  amp = x;
}

void FitsItt::SetZero(float x)
{
  zero = x;
}

bool FitsItt::IsLinear() const
{
  return itt == ITT_LINE;
}


float FitsItt::GetAmp() const
{
  return amp;
}

float FitsItt::GetZero() const
{
  return zero;
}

float FitsItt::Itt_linear(float r) const
{
  return r;
}

float FitsItt::Itt_sqrt(float r) const
{
  return r > 0.0 ? amp*sqrtf(r)+zero : 0.0;
}

float FitsItt::Itt_square(float r) const
{
  return amp*r*r+zero;
}

float FitsItt::Itt_logis(float r) const
{
  return amp*(2.0f/(1.0f + expf(-2.5f*r)) - 1.0f) + zero;
}

wxString FitsItt::Type_str(int n)
{
  switch(n){
  case ITT_LINE:  return "Linear";
  case ITT_SQRT:  return "Square root";
  case ITT_SQR:   return "Square";
  case ITT_LOGIS: return "Logistic";
  default:        return wxEmptyString;
  }
}


wxArrayString FitsItt::Type_str()
{
  wxArrayString a;

  for(int i = ITT_FIRST+1; i < ITT_LAST; i++)
    a.Add(Type_str(i));

  return a;
}


void FitsItt::Reset()
{
  itt = ITT_LINE;
  amp = 1.0;
  zero = 0.0;
}


float *FitsItt::Scale(long n, const float *a)
{
  float *f = new float[n];

  if( itt == ITT_LINE )
    for(long i = 0; i < n; i++)
      f[i] = a[i];

  else if( itt == ITT_SQRT )
    for(long i = 0; i < n; i++)
      f[i] = (a[i] > 0.0f ? amp*sqrtf(a[i]) : 0.0f) + zero;

  else if( itt == ITT_LOGIS )
    for(long i = 0; i < n; i++)
      f[i] = amp*(2.0f/(1.0f + expf(-2.5f*a[i])) - 1.0f) + zero;

  else if( itt == ITT_SQR )
    for(long i = 0; i < n; i++)
      f[i] = amp*a[i]*a[i] + zero;

  else
    wxFAIL_MSG("An unknown ITT");

  return f;
}
