// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// operand-fraction.go
package expr

//https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html

import (
	"errors"
	"fmt"
)

// -------- fraction term
func newFractionTerm(tk *Token) *term {
	return &term{
		tk:       *tk,
		parent:   nil,
		children: make([]*term, 0, 2),
		position: posInfix,
		priority: priFraction,
		evalFunc: evalFraction,
	}
}

// -------- eval func
func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) {
	var numValue, denValue any
	var num, den int64
	var ok bool

	if numValue, denValue, err = opTerm.evalInfix(ctx); err != nil {
		return
	}
	if num, ok = numValue.(int64); !ok {
		err = fmt.Errorf("numerator must be integer, got %T (%v)", numValue, numValue)
		return
	}
	if den, ok = denValue.(int64); !ok {
		err = fmt.Errorf("denominator must be integer, got %T (%v)", denValue, denValue)
		return
	}
	if den == 0 {
		err = errors.New("division by zero")
		return
	}

	if den < 0 {
		den = -den
		num = -num
	}
	g := gcd(num, den)
	num = num / g
	den = den / g
	if den == 1 {
		v = num
	} else {
		v = &FractionType{num, den}
	}
	return
}

// init
func init() {
	registerTermConstructor(SymVertBar, newFractionTerm)
}