// KEKS -- Go KEKS codec implementation
// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, version 3 of the License.
//
// 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program.  If not, see <http://www.gnu.org/licenses/>.

package keks

import (
	"fmt"
	"math/big"
)

type Float struct {
	M    *big.Int
	E    *big.Int
	NaN  bool
	Pinf bool
	Ninf bool
}

func (f *Float) MarshalJSON() ([]byte, error) {
	if f.NaN {
		return fmt.Appendf(nil, "FLOAT[NaN]"), nil
	}
	if f.Pinf {
		return fmt.Appendf(nil, "FLOAT[+inf]"), nil
	}
	if f.Ninf {
		return fmt.Appendf(nil, "FLOAT[-inf]"), nil
	}
	return fmt.Appendf(nil, "FLOAT[%d, %d]", f.M, f.E), nil
}

func (f *Float) BigFloat() *big.Float {
	exp := big.NewFloat(0).SetInt(big.NewInt(0).Exp(
		big.NewInt(2),
		big.NewInt(0).Abs(f.E),
		nil,
	))
	if f.E.Sign() == -1 {
		exp = exp.Quo(big.NewFloat(1.0), exp)
	}
	return exp.Mul(exp, big.NewFloat(0).SetInt(f.M))
}

func (f *Float) IsZero() bool {
	if f.NaN || f.Pinf || f.Ninf {
		return false
	}
	z := big.NewInt(0)
	return (f.M.Cmp(z) == 0) && (f.E.Cmp(z) == 0)
}
