/* UtilLib - Copyright (c) 2006-2024 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.primitives;

import java.text.ParseException;
import net.mapeadores.util.text.StringUtils;


/**
 *
 * @author Vincent Calame
 */
public class RangeUtils {

    private RangeUtils() {
    }

    public static boolean isPositiveRanges(Ranges ranges) {
        return (ranges.getGlobalMin() >= 0);
    }

    /**
     *
     * @throws IllegalArgumentException si RangeList.getGlobalMin() < 0
     */
    public static String positiveRangesToString(Ranges ranges) {
        return positiveRangesToString(ranges, ";");
    }

    /**
     *
     * @throws IllegalArgumentException si RangeList.getGlobalMin() < 0
     */
    public static String positiveRangesToString(Ranges ranges, String separator) {
        if (ranges.getGlobalMin() < 0) {
            throw new IllegalArgumentException("not a positive range");
        }
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < ranges.size(); i++) {
            if (i > 0) {
                buf.append(separator);
            }
            appendRange(buf, ranges.get(i));
        }
        return buf.toString();
    }

    public static String positiveRangetoString(Range range) {
        StringBuilder buf = new StringBuilder();
        appendRange(buf, range);
        return buf.toString();
    }

    public static void appendRange(StringBuilder buf, Range range) {
        int min = range.min();
        int max = range.max();
        if (min == max) {
            buf.append(min);
            return;
        }
        if (min != 0) {
            buf.append(min);
        }
        buf.append('-');
        if (max != Range.MAXIMUM) {
            buf.append(max);
        }
    }

    /**
     * Retourne <em>null</em> si c'est vide. sinon contient au moins un élément.
     *
     */
    public static Ranges positiveRangeParse(String s) {
        if ((s == null) || (s.length() == 0)) {
            return null;
        }
        Ranges ranges = new Ranges();
        String[] tokens = StringUtils.getTechnicalTokens(s, false);
        int length = tokens.length;
        for (int i = 0; i < length; i++) {
            String token = tokens[i];
            try {
                Range range = parseRange(token);
                if (range != null) {
                    ranges.addRange(range);
                }
            } catch (ParseException pe) {
            }
        }
        if (ranges.size() == 0) {
            return null;
        }
        return ranges;
    }

    public static Range parseRange(String token) throws ParseException {
        int idx = token.indexOf('-');
        if (idx == -1) {
            int num = parseInt(token);
            if (num < 0) {
                return null;
            }
            return new Range(num, num);
        }
        int num1 = parseInt(token.substring(0, idx));
        int num2 = parseInt(token.substring(idx + 1));
        if (num1 < 0) {
            if (num2 < 0) {
                return null;
            }
            return new Range(0, num2);
        }
        if (num2 < 0) {
            return new Range(num1, Range.MAXIMUM);
        }
        return new Range(num1, num2);
    }

    private static int parseInt(String token) throws ParseException {
        int length = token.length();
        boolean done = false;
        int result = 0;
        for (int i = 0; i < length; i++) {
            char carac = token.charAt(i);
            if (carac == ' ') {
                continue;
            }
            if ((carac >= '0') && (carac <= '9')) {
                result = result * 10;
                result = result + (((int) carac) - 48);
                done = true;
            } else {
                throw new ParseException("Not a number: " + token, i);
            }
        }
        if (!done) {
            return -1;
        }
        return result;
    }

}
