/*
    CaPriCe Forever - Amstrad CPC 464/664/6128 emulator
    Copyright (C) 2014-2019 by Frédéric Coste

    This program 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.

    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "..\..\Engine\Native_CPC.h"
#include "..\Math.h"
#include "..\STD\Strings.h"


/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif


#define HUGE					 1.0e+300


tDouble BASIC_FloatToDouble(tUChar* FloatBytesP)
/***********************************************************************
 *
 *  BASIC_FloatToDouble
 *
 ***********************************************************************/
{
  tRawDouble Convert;
  tULong Mantissa;
  tChar Exp;
  tUChar Sign;

  if (FloatBytesP == NULL) return (HUGE * HUGE);

  Sign = FloatBytesP[3] & 0x80;
  Mantissa = (FloatBytesP[3] & 0x7f) << 24;
  Mantissa += FloatBytesP[2] << 16;
  Mantissa += FloatBytesP[1] << 8;
  Mantissa += FloatBytesP[0];
  Exp = FloatBytesP[4] - 129;

  /*Convert.d = 1 + (tDouble)Mantissa / 0x80000000;
  Convert.d = Convert.d * math_pow(2, Exp);
  if (Sign)
  {
    Convert.d = -Convert.d;
  }*/

#if (__BORLANDC__ == 0x551)

  Convert.sl.l = Mantissa << 21;
  Convert.sl.h = Mantissa >> 11;
  Convert.sl.h |= (1023 + Exp) << 20;
  Convert.sl.h |= (Sign) ? 0x80000000 : 0;

#else /* __BORLANDC__ */

  Convert.i = Mantissa;
  Convert.i <<= 21;
  Convert.s.Exp = 1023 + Exp;
  Convert.s.Sign = (Sign) ? 1 : 0;

#endif /* __BORLANDC__ */

  return (Convert.d);
}
/*----------------------------------------------------------------------------*/


tUChar* BASIC_DoubleToFloat(tUChar* FloatBytesP, tDouble Value)
/***********************************************************************
 *
 *  BASIC_DoubleToFloat
 *
 ***********************************************************************/
{
  tRawDouble RawDouble;
  tULong Mantissa;
  tChar Exp;
  tUChar Sign;

  if (FloatBytesP == NULL) return NULL;

  RawDouble.d = Value;

#if (__BORLANDC__ == 0x551)

  Mantissa = RawDouble.sl.l >> 21;
  Mantissa |= RawDouble.sl.h << 11;
  Exp = ((RawDouble.sl.h >> 20) & 0x7FF) - 1023;
  Sign = (RawDouble.sl.h & 0x80000000) >> 24;

#else /* __BORLANDC__ */

  Mantissa = (RawDouble.i >> 21) & 0x7fffffff;
  Exp = RawDouble.s.Exp - 1023;
  Sign = (RawDouble.s.Sign) ? 0x80 : 0;

#endif /* __BORLANDC__ */

  FloatBytesP[0] = (Mantissa >> 0) & 0xFF;
  FloatBytesP[1] = (Mantissa >> 8) & 0xFF;
  FloatBytesP[2] = (Mantissa >> 16) & 0xFF;
  FloatBytesP[3] = Sign | ((Mantissa >> 24) & 0x7F);
  FloatBytesP[4] = Exp + 129;

  return (FloatBytesP);
}
/*----------------------------------------------------------------------------*/


tChar* BASIC_FloatToString(tUChar* FloatBytesP, tChar* StringP)
/***********************************************************************
 *
 *  BASIC_FloatToString
 *
 ***********************************************************************/
{
  tRawDouble Value;
  tRawDouble FracPart;
	tChar* StringStartP;
  tLong IntPart;
  tLong ExpPart;
  tUChar Size;
  tUChar MaxSize;

  if (FloatBytesP == NULL) return (0L);
  if (StringP == NULL) return (0L);

  StringStartP = StringP;

  Value.d = BASIC_FloatToDouble(FloatBytesP);

  if (Value.d >= 0)
  {
    ExpPart = (tLong)math_log10(Value.d);
  }
  else
  {
    ExpPart = -(tLong)math_log10(-Value.d);
  }
  if (ExpPart < 0) ExpPart--;

  if (ExpPart >= 9)
  {
    Value.d = Value.d / math_pow(10, ExpPart);
    IntPart = (tLong)(Value.d);
    FracPart.d = Value.d - IntPart;
  }
  else if (ExpPart >= 0)
  {
    IntPart = (tLong)(Value.d);
    FracPart.d = Value.d - IntPart;
    ExpPart = 0;
  }
  else if (ExpPart < -10)
  {
    Value.d = Value.d / math_pow(10, ExpPart);
    IntPart = (tLong)(Value.d);
    FracPart.d = Value.d - IntPart;
  }
  else
  {
    IntPart = 0;
    FracPart.d = Value.d;
    ExpPart = 0;
  }

  MaxSize = 10; // Max number of figures

  // Add Integer Part
  if (IntPart < 0)
  {
    *(StringP++) = '-';
    IntPart = -IntPart;
  }
  Size = StringIntToStr(IntPart, StringP);
  StringP += Size;
  if (IntPart)
  {
    MaxSize -= Size;
  }

  // Add fractional part
  if (FracPart.d > 0)
  {
    tUChar Int;
    tUChar FirstZeros = 1;
    *(StringP++) = '.';

    do
    {
      Int = (tUChar)(FracPart.d * 10);
      if (Int || FirstZeros)
      {
        *(StringP++) = '0' + Int;
      }
      if (Int) FirstZeros = 0;
      FracPart.d = (FracPart.d * 10) - Int;
      MaxSize--;
    }
    while ((Int || FirstZeros) && (MaxSize));
  }

  // Add exponant part
  if (ExpPart != 0)
  {
    *(StringP++) = 'E';
    if (ExpPart < 0)
    {
      *(StringP++) = '-';
      ExpPart = -ExpPart;
    }
    else
    {
      *(StringP++) = '+';
    }
    if (ExpPart < 10)
    {
      *(StringP++) = '0';
    }
    StringP = StringP + StringIntToStr(ExpPart, StringP);
  }

  // Terminate string
  *StringP = '\0';

  return (StringStartP);
}
/*----------------------------------------------------------------------------*/


#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif

