package com.googlecode.totallylazy.numbers;

import com.googlecode.totallylazy.functions.CurriedMonoid;

public class Average implements CurriedMonoid<Number> {
    public Number call(Number average, Number value) {
        return weighted(average).combine(weighted(value));
    }

    @Override
    public Number identity() {
        return weighted(0, 0);
    }

    public static Weighted weighted(Number number, Number count) {
        return new Weighted(number, count);
    }

    public static Weighted weighted(Number number) {
        if (number instanceof Weighted) return (Weighted) number;
        return weighted(number, 1);
    }

    private static class Weighted extends Num {
        private final Num weight;

        private Weighted(Number value, Number weight) {
            super(value);
            this.weight = num(weight);
        }

        public Weighted combine(Weighted value) {
            Num newWeight = weight.add(value.weight);
            return weighted(sum().add(value.sum()).divide(newWeight), newWeight);
        }

        private Num sum() {
            return weight.multiply(value());
        }
    }
}
