package com.uas.search.sort;

import com.uas.search.util.CharUtils;
import com.uas.search.util.StringUtils;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;

import java.io.IOException;

/**
 * 用于 StringField 的排序
 *
 * @author sunyj
 * @since 2017/11/23 17:27
 */
public class StringFieldComparatorSource extends FieldComparatorSource {

    /**
     * 搜索的关键词
     */
    private String keyword;

    /**
     * 本次排序之后是否还有其他排序
     */
    private boolean hasOtherSort;

    public StringFieldComparatorSource(String keyword) {
        this(keyword, false);
    }

    public StringFieldComparatorSource(String keyword, boolean hasOtherSort) {
        this.keyword = keyword;
        this.hasOtherSort = hasOtherSort;
    }

    @Override
    public FieldComparator<?> newComparator(final String fieldname, int numHits, int sortPos, boolean reversed)
            throws IOException {
        return new DefaultFieldComparator(fieldname, numHits) {
            @Override
            protected int compare(String str1, String str2) {
                int superCompare = super.compare(str1, str2);
                if (superCompare != UNKOWN || StringUtils.isEmpty(keyword)) {
                    return superCompare;
                }

                str1 = str1.toLowerCase();
                str2 = str2.toLowerCase();
                keyword = keyword.toLowerCase();

                int index1 = str1.indexOf(keyword);
                int index2 = str2.indexOf(keyword);
                // 一方包含关键词，另一方不包含时，该方排序靠前
                if (index1 >= 0) {
                    if (index2 >= 0) {
                        // 均包含关键词时，比较关键词在字符串中的位置，位置越靠前，最终排序越靠前
                        if (index1 < index2) {
                            return AHEAD;
                        } else if (index1 > index2) {
                            return BEHIND;
                        } else {
                            // 关键词在字符串中的位置相同时，比较字符串长度。长度较短，则排序靠前；长度相同时再按字符排序
                            int compareLength = compareLength(str1, str2);
                            return compareLength != PARALLEL ? compareLength : compareCharacter(str1, str2);
                        }
                    } else {
                        return AHEAD;
                    }
                } else {
                    if (index2 >= 0) {
                        return BEHIND;
                    } else {
                        // 均不包含关键词时
                        // 如果之后没有其他排序，则比较字符串长度。长度较短，则排序靠前；长度相同时再按字符排序
                        // 如果有其他排序，则这里排序优先级相等，由之后的排序再进行比较
                        if (!hasOtherSort) {
                            int compareLength = compareLength(str1, str2);
                            return compareLength != PARALLEL ? compareLength : compareCharacter(str1, str2);
                        } else {
                            return PARALLEL;
                        }
                    }
                }
            }

            /**
             * 比较长度，长度较短，则排序靠前
             */
            private int compareLength(String str1, String str2) {
                int length1 = str1.length();
                int length2 = str2.length();
                if (length1 < length2) {
                    return AHEAD;
                } else if (length1 > length2) {
                    return BEHIND;
                } else {
                    return PARALLEL;
                }
            }

            /**
             * 比较字母顺序，优先级：字母 > 其他字符(优先级视为相等) > 数字
             */
            private int compareCharacter(String str1, String str2) {
                char[] array1 = str1.toLowerCase().toCharArray();
                char[] array2 = str2.toLowerCase().toCharArray();
                for (int i = 0; i < array1.length; i++) {
                    char c1 = array1[i];
                    char c2 = array2[i];
                    // 字母 > 其他字符(优先级视为相等) > 数字
                    if (CharUtils.isCharacter(c1)) {
                        if (CharUtils.isCharacter(c2)) {
                            // 均为字母，值越小优先级越高
                            if (c1 < c2) {
                                return AHEAD;
                            } else if (c1 > c2) {
                                return BEHIND;
                            }
                        } else {
                            return AHEAD;
                        }
                    } else if (CharUtils.isNumber(c1)) {
                        if (CharUtils.isNumber(c2)) {
                            // 均为数字，数字越小优先级越高
                            if (c1 > c2) {
                                return BEHIND;
                            } else if (c1 < c2) {
                                return AHEAD;
                            }
                        } else {
                            return BEHIND;
                        }
                    } else {
                        if (CharUtils.isCharacter(c2)) {
                            return BEHIND;
                        } else if (CharUtils.isNumber(c2)) {
                            return AHEAD;
                        }
                    }
                }
                return PARALLEL;
            }
        };
    }
}
