package com.jscape.util;

import java.text.DecimalFormat;

public class ByteFormat {

    public static String format(double value) {
        Measurement measurement = Measurement.valueOf(value);
        String pattern = measurement.factor == 1 ? "#,##0" : "#,##0.00";
        DecimalFormat format = new DecimalFormat(pattern + " " + measurement.unit);

        return format.format(value / measurement.factor);
    }

    public static String format(double value, String pattern) {
        Measurement measurement = Measurement.valueOf(value);
        DecimalFormat format = new DecimalFormat(pattern + " " + measurement.unit);

        return format.format(value / measurement.factor);
    }

    private ByteFormat() {
    }

    public enum Measurement {

        BYTE(1L, "byte(s)"),
        KILOBYTE(1024L, "KB"),
        MEGABYTE(1024L * 1024, "MB"),
        GIGABYTE(1024L * 1024 * 1024, "GB"),
        TERABYTE(1024L * 1024 * 1024 * 1024, "TB");

        public final long factor;
        public final String unit;

        public static Measurement valueOf(double value) {
            value = Math.abs(value);

            if (0 <= value && value < KILOBYTE.factor) {
                return BYTE;
            } else if (KILOBYTE.factor <= value && value < MEGABYTE.factor) {
                return KILOBYTE;
            } else if (MEGABYTE.factor <= value && value < GIGABYTE.factor) {
                return MEGABYTE;
            } else if (GIGABYTE.factor <= value && value < TERABYTE.factor) {
                return GIGABYTE;
            } else {
                return TERABYTE;
            }
        }

        public static Measurement equalize(double[] values) {
            Measurement measurement = Measurement.valueOf(max(values));

            for (int i = 0; i < values.length; ++i) {
                values[i] = values[i] / measurement.factor;
            }

            return measurement;
        }

        private static double max(double[] values) {
            double max = Double.MIN_VALUE;

            for (double value : values) {
                max = Math.max(value, max);
            }

            return max;
        }

        Measurement(long factor, String unit) {
            this.factor = factor;
            this.unit = unit;
        }
    }
}
