001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util;
018
019import org.apache.wicket.util.string.PrependingStringBuffer;
020
021/**
022 * Encodes long values into the specified alphabet. Encoding is useful when long values need to be
023 * represented in their string form and shorter values are preferred; by using alphabets of length
024 * greater than ten shorter values can be obtained. For example, to encode values into their
025 * hexadecimal representations the {@code 0123456789ABCDEF-} can be used. Long values can be
026 * shortened even further by using longer alphabets. The last character in the alphabet is used as
027 * the negative sign.
028 * 
029 * @author igor
030 */
031public class LongEncoder
032{
033        /**
034         * default alphabet that should be safe to use in most circumstances, while still providing good
035         * shortening of long values
036         */
037        public static final String DEFAULT = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
038
039        private LongEncoder()
040        {
041        }
042
043        /**
044         * Encodes the value into the default alphabet: {@value #DEFAULT}
045         * 
046         * @param value
047         * @return encoded value
048         */
049        public static String encode(final long value)
050        {
051                return encode(value, DEFAULT);
052        }
053
054        /**
055         * Decodes value using the default alphabet: {@value #DEFAULT}
056         * 
057         * @param value
058         * @return decoded value
059         */
060        public static long decode(final String value)
061        {
062                return decode(value, DEFAULT);
063        }
064
065        /**
066         * Encodes value into the specified alphabet
067         * 
068         * @param value
069         * @param alphabet
070         * @return encoded value
071         */
072        public static String encode(long value, final String alphabet)
073        {
074                final int len = alphabet.length() - 1;
075                PrependingStringBuffer buff = new PrependingStringBuffer();
076                final boolean negative = value < 0;
077                if (negative)
078                {
079                        value = -value;
080                }
081                do
082                {
083                        int mod = (int)(value % len);
084                        buff.prepend(alphabet.charAt(mod));
085                        value = value / len;
086                }
087                while (value > 0);
088                if (negative)
089                {
090                        buff.prepend(alphabet.charAt(len));
091                }
092                return buff.toString();
093        }
094
095        /**
096         * Decodes value using the specified alphabet
097         * 
098         * @param value
099         * @param alphabet
100         * @return decoded value
101         */
102        public static long decode(final String value, final String alphabet)
103        {
104                final int factor = alphabet.length() - 1;
105                final boolean negative = alphabet.charAt(factor) == value.charAt(0);
106                long num = 0;
107                for (int i = (negative) ? 1 : 0, len = value.length(); i < len; i++)
108                {
109                        num = num * factor + alphabet.indexOf(value.charAt(i));
110                }
111                if (negative)
112                {
113                        num = -num;
114                }
115                return num;
116        }
117}