/**
  * Returns the description of the {@code number}. This method distinguishes the case of an invalid
  * prefix and a prefix for which the name is not available in the current language. If the
  * description is not available in the current language an empty string is returned. If no
  * description was found for the provided number, null is returned.
  *
  * @param number the phone number to look up
  * @return the description of the number
  */
 String lookup(long number) {
   int numOfEntries = phonePrefixMapStorage.getNumOfEntries();
   if (numOfEntries == 0) {
     return null;
   }
   long phonePrefix = number;
   int currentIndex = numOfEntries - 1;
   SortedSet<Integer> currentSetOfLengths = phonePrefixMapStorage.getPossibleLengths();
   while (currentSetOfLengths.size() > 0) {
     Integer possibleLength = currentSetOfLengths.last();
     String phonePrefixStr = String.valueOf(phonePrefix);
     if (phonePrefixStr.length() > possibleLength) {
       phonePrefix = Long.parseLong(phonePrefixStr.substring(0, possibleLength));
     }
     currentIndex = binarySearch(0, currentIndex, phonePrefix);
     if (currentIndex < 0) {
       return null;
     }
     int currentPrefix = phonePrefixMapStorage.getPrefix(currentIndex);
     if (phonePrefix == currentPrefix) {
       return phonePrefixMapStorage.getDescription(currentIndex);
     }
     currentSetOfLengths = currentSetOfLengths.headSet(possibleLength);
   }
   return null;
 }
 /**
  * Gets the size of the provided phone prefix map storage. The map storage passed-in will be
  * filled as a result.
  */
 private static int getSizeOfPhonePrefixMapStorage(
     PhonePrefixMapStorageStrategy mapStorage, SortedMap<Integer, String> phonePrefixMap)
     throws IOException {
   mapStorage.readFromSortedMap(phonePrefixMap);
   ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
   ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
   mapStorage.writeExternal(objectOutputStream);
   objectOutputStream.flush();
   int sizeOfStorage = byteArrayOutputStream.size();
   objectOutputStream.close();
   return sizeOfStorage;
 }
 /** Supports Java Serialization. */
 public void readExternal(ObjectInput objectInput) throws IOException {
   // Read the phone prefix map storage strategy flag.
   boolean useFlyweightMapStorage = objectInput.readBoolean();
   if (useFlyweightMapStorage) {
     phonePrefixMapStorage = new FlyweightMapStorage();
   } else {
     phonePrefixMapStorage = new DefaultMapStorage();
   }
   phonePrefixMapStorage.readExternal(objectInput);
 }
 /**
  * Does a binary search for {@code value} in the provided array from {@code start} to {@code end}
  * (inclusive). Returns the position if {@code value} is found; otherwise, returns the position
  * which has the largest value that is less than {@code value}. This means if {@code value} is the
  * smallest, -1 will be returned.
  */
 private int binarySearch(int start, int end, long value) {
   int current = 0;
   while (start <= end) {
     current = (start + end) >>> 1;
     int currentValue = phonePrefixMapStorage.getPrefix(current);
     if (currentValue == value) {
       return current;
     } else if (currentValue > value) {
       current--;
       end = current;
     } else {
       start = current + 1;
     }
   }
   return current;
 }
 /** Dumps the mappings contained in the phone prefix map. */
 @Override
 public String toString() {
   return phonePrefixMapStorage.toString();
 }
 /** Supports Java Serialization. */
 public void writeExternal(ObjectOutput objectOutput) throws IOException {
   objectOutput.writeBoolean(phonePrefixMapStorage instanceof FlyweightMapStorage);
   phonePrefixMapStorage.writeExternal(objectOutput);
 }