content: /*******************************************************************************
   * Software Name : RCS IMS Stack
   *
   * Copyright (C) 2010-2016 Orange.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   ******************************************************************************/
  
  package com.gsma.rcs.utils;
  
  import java.util.UUID;
  
  /**
   * Unique identifier generator
   * 
   * @author JF. Jestin
   */
  public class IdGenerator {
  
      /**
       * Every 6 bit are coded using this table (see base64 encoding standard, except '/' which was
       * replaced by '_')
       */
      private final static char[] CODE_TABLE = {
              'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
              'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
              'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
              'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '_'
      };
  
      /**
       * The counter which get a new value for each subsequent call of increment()
       */
      private static int cyclicCounter = 0;
  
      /**
       * How much digits are used for coding the counter, 3 means 3*6 bits, that are 18 bits resulting
       * in a max. value of 262144 for the counter which seems to be enough.
       */
      private final static int N_COUNTERS_CHARS = 3;
  
      /**
       * The number of generated characters for the uniq identifier
       * <p>
       * System.currentTimeMillis() returns long, but only 42 bit are taken, which seems to be enough
       * for more than 100 years after 1970, these 42 bits need 7 chars for their coding, the number
       * of chars for the counter is added:
       * 
       * <pre>
       * maxDigit = 7 + N_COUNTERS_CHARS;
       * </pre>
       */
      private final static int MAX_DIGIT = 7 + N_COUNTERS_CHARS;
  
      /**
       * The central method to increment the cyclic counter, synchronized to achieve a unique value
       * for each subsequent call
       * <p>
       * there is no problem if the counter reaches the maximum counter value, defined by
       * N_COUNTERS_CHARS, only the right number of bits are taken into account for generating the
       * output
       * 
       * @return The new counter value
       */
      private static synchronized int increment() {
          return cyclicCounter++;
      }
  
      /**
       * Encode twoumbers into a textual representation using a base64 like coding table.
       * 
       * @param time This should be System.currentTimeMillis
       * @param counter The counter value, it is coded into N_COUNTERS_CHARS chars, ie for 3 chars we
       *            have 18 bit and a max. range of 262144
       * @result The converted String containing (7 + N_COUNTERS_CHARS) characters
       */
      private static String encode64(long time, int counter) {
          char[] encodedData = new char[MAX_DIGIT];
          int i, idx;
  
          for (i = 0; i < 7; i++) {
              idx = (int) time & 63;
              time >>= 6;
              encodedData[i] = CODE_TABLE[idx];
          }
  
          for (; i < MAX_DIGIT; i++) {
              idx = counter & 63;
              counter >>= 6;
              encodedData[i] = CODE_TABLE[idx];
          }
  
          return new String(encodedData);
      }
  
      /**
       * Get a unique local identifier for each subsequent call
       * 
       * @return Unique identifier
       */
      public static synchronized String getIdentifier() {
          long time = System.currentTimeMillis();
  
          int counter = -1;
          if (N_COUNTERS_CHARS > 0)
              counter = increment();
  
          return encode64(time, counter);
      }
  
      /**
       * Generate a new unique and random message ID (eg. for SIP or MSRP)
       * 
       * @return the messageID
       *         <p>
       *         <b>Note:</b><br />
       *         The message ID is a string of 32 characters in the range [a-f0-9] in compliance with
       *         RFC 4975
       *         </p>
       */
      public static synchronized String generateMessageID() {
          UUID id = UUID.randomUUID();
          return String.format("%016x%016x", id.getMostSignificantBits(),
                  id.getLeastSignificantBits());
      }
  }
  