package com.alibaba.druid.util;

import java.lang.reflect.Array;
import java.text.Collator;
import java.util.Comparator;
import java.util.Date;
import java.util.Map;

public class MapComparator<K, V> implements Comparator<Map<K, V>> {
   private boolean isDesc;
   private K orderByKey;

   public MapComparator(K orderByKey, boolean isDesc) {
      this.orderByKey = orderByKey;
      this.isDesc = isDesc;
   }

   private int compare(Number o1, Number o2) {
      return (int)(o1.doubleValue() - o2.doubleValue());
   }

   private int compare(String o1, String o2) {
      return Collator.getInstance().compare(o1, o2);
   }

   private int compare(Date o1, Date o2) {
      return (int)(o1.getTime() - o2.getTime());
   }

   public int compare(Map<K, V> o1, Map<K, V> o2) {
      int result = this.compare_0(o1, o2);
      if (this.isDesc) {
         result = -result;
      }

      return result;
   }

   private Object getValueByKey(Map<K, V> map, K key) {
      if (key instanceof String) {
         String keyStr = (String)key;
         int bracketIndex = keyStr.indexOf(91);
         if (bracketIndex > 0) {
            Object value = map.get(keyStr.substring(0, bracketIndex));
            if (value == null) {
               return null;
            }

            int p2 = keyStr.indexOf(93, bracketIndex);
            if (p2 == -1) {
               return null;
            }

            String indexText = keyStr.substring(bracketIndex + 1, p2);
            int index = Integer.parseInt(indexText);
            if (value.getClass().isArray() && Array.getLength(value) >= index) {
               return Array.get(value, index);
            }

            return null;
         }
      }

      return map.get(key);
   }

   private int compare_0(Map<K, V> o1, Map<K, V> o2) {
      Object v1 = this.getValueByKey(o1, this.orderByKey);
      Object v2 = this.getValueByKey(o2, this.orderByKey);
      if (v1 == null && v2 == null) {
         return 0;
      } else if (v1 == null) {
         return -1;
      } else if (v2 == null) {
         return 1;
      } else if (v1 instanceof Long) {
         return (int)((Long)v1 - ((Number)v2).longValue());
      } else if (v1 instanceof Number) {
         return this.compare((Number)v1, (Number)v2);
      } else if (v1 instanceof String) {
         return this.compare((String)v1, (String)v2);
      } else {
         return v1 instanceof Date ? this.compare((Date)v1, (Date)v2) : 0;
      }
   }
}
