package astikit

import (
	"bytes"
	"fmt"
	"strconv"
)

// Rational represents a rational
type Rational struct{ den, num int }

// NewRational creates a new rational
func NewRational(num, den int) *Rational {
	return &Rational{
		den: den,
		num: num,
	}
}

// Num returns the rational num
func (r *Rational) Num() int {
	return r.num
}

// Den returns the rational den
func (r *Rational) Den() int {
	return r.den
}

// ToFloat64 returns the rational as a float64
func (r *Rational) ToFloat64() float64 {
	return float64(r.num) / float64(r.den)
}

// MarshalText implements the TextMarshaler interface
func (r *Rational) MarshalText() (b []byte, err error) {
	b = []byte(fmt.Sprintf("%d/%d", r.num, r.den))
	return
}

// UnmarshalText implements the TextUnmarshaler interface
func (r *Rational) UnmarshalText(b []byte) (err error) {
	r.num = 0
	r.den = 1
	if len(b) == 0 {
		return
	}
	items := bytes.Split(b, []byte("/"))
	if r.num, err = strconv.Atoi(string(items[0])); err != nil {
		err = fmt.Errorf("astikit: atoi of %s failed: %w", string(items[0]), err)
		return
	}
	if len(items) > 1 {
		if r.den, err = strconv.Atoi(string(items[1])); err != nil {
			err = fmt.Errorf("astifloat: atoi of %s failed: %w", string(items[1]), err)
			return
		}
	}
	return
}

func MinMaxInt(v, min, max int) int {
	if v < min {
		return min
	} else if v > max {
		return max
	}
	return v
}
