package com.apobates.forum.utils.lang;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.IntStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author xiaofanku
 * @since 20200515
 */
public class CommonDoubleBean implements Serializable {
    private static final long serialVersionUID = -8695062954072685003L;
    private final double value;
    private final String title;
    private final int id;
    
    public CommonDoubleBean(int id, String title, double value) {
        super();
        this.id = id;
        this.title = title;
        this.value = value;
    }
    
    public double getValue() {
        return value;
    }
    
    public String getTitle() {
        return title;
    }
    
    public int getId() {
        return id;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        long temp;
        temp = Double.doubleToLongBits(value);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        result = prime * result + ((title == null) ? 0 : title.hashCode());
        return result;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        CommonDoubleBean other = (CommonDoubleBean) obj;
        if (Double.doubleToLongBits(value) != Double.doubleToLongBits(other.value)) {
            return false;
        }
        if (title == null) {
            if (other.title != null) {
                return false;
            }
        } else if (!title.equals(other.title)) {
            return false;
        }
        return true;
    }
    
    public static CommonDoubleBean empty() {
        return new CommonDoubleBean(0, "VA", 0);
    }
    
    public DoubleBeanFormatter getFormatter(Collection<CommonDoubleBean> source){
        return new DoubleBeanFormatter(source);
    }
    public class DoubleBeanFormatter {
        //不可变
        private final List<CommonDoubleBean> source;
        private final Logger logger = LoggerFactory.getLogger(DoubleBeanFormatter.class);
        
        public DoubleBeanFormatter(Collection<CommonDoubleBean> source) {
            List<CommonDoubleBean> sortSource = new ArrayList<>();
            sortSource.addAll(source);
            sortSource.sort((CommonDoubleBean o1, CommonDoubleBean o2) -> Double.compare(o1.getId(), o2.getId()));
            this.source = List.copyOf(sortSource);
        }
        
        /**
         * 使用java.util.stream.IntStream的方式来查找索引
         *
         * @param value
         * @return
         */
        public String format(double value) {
            int maxIndex = source.size();
            int index = IntStream.range(0, maxIndex).filter(i -> source.get(i).getValue() >= value).findAny().orElse(-1);
            //logger.info("[DoubleBeanFormatter][format]look up index: " + index);
            
            if (index == -1) {
                //可能大于上限值
                index = maxIndex - 1;
            }
            //介于中间值
            if (source.get(index).getValue() > value && index > 0) {
                index -= 1;
            }
            return source.get(index).getTitle();
        }
        
        /**
         * 使用java.text.ChoiceFormat类的代码查找索引
         *
         * @param value
         * @return
         */
        public String getTitle(double value) {
            double[] data = source.stream().map(CommonDoubleBean::getValue).mapToDouble(Double::doubleValue).toArray();
            int indexOfData = lookIndex(value, data);
            //logger.info("[DoubleBeanFormatter][getTitle]look up index: " + indexOfData);
            return source.get(indexOfData).getTitle();
        }
        
        //代码来自: StringBuffer ChoiceFormat.format(double number, StringBuffer toAppendTo,FieldPosition status);
        private int lookIndex(double number, double[] limits) {
            int i;
            for (i = 0; i < limits.length; ++i) {
                if (!(number >= limits[i])) {
                    // same as number < choiceLimits, except catchs NaN
                    break;
                }
            }
            --i;
            if (i < 0) {
                i = 0;
            }
            // return either a formatted number, or a string
            return i;
        }
    }
}