/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;
import static java.lang.Math.*;

/**
 * String hashing functions.
 * @author Arash Partow
 */
final class Hash
{

    /**
     * A simple hash function from Robert Sedgwicks Algorithms in C book.
     * @param str
     * @return
     */
    public static long RSHash(String str) {
        int b = 378551;
        int a = 63689;
        long hash = 0;
        for (int i = 0; i < str.length(); i++) {
            hash = hash * a + str.charAt(i);
            a = a * b;
        }
        return hash;
    }

    /**
     * A bitwise hash function written by Justin Sobel.
     * @param str
     * @return
     */
    public static long JSHash(String str) {
        long hash = 1315423911;
        for (int i = 0; i < str.length(); i++) {
            hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
        }
        return hash;
    }

    /**
     * This hash algorithm is based on work by Peter J. Weinberger of AT&T Bell Labs.
     * @param str
     * @return
     */
    public static long PJWHash(String str) {
        long BitsInUnsignedInt = (long) (4 * 8);
        long ThreeQuarters = (long) ((BitsInUnsignedInt * 3) / 4);
        long OneEighth = (long) (BitsInUnsignedInt / 8);
        long HighBits = (long) (0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
        long hash = 0;
        long test = 0;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash << OneEighth) + str.charAt(i);

            if ((test = hash & HighBits) != 0) {
                hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
            }
        }
        return hash;
    }

    /**
     * Similar to the PJW Hash function, but tweaked for 32-bit processors.
     * Its the hash function widely used on most UNIX systems.
     * @param str
     * @return
     */
    public static long ELFHash(String str) {
        long hash = 0;
        long x = 0;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash << 4) + str.charAt(i);
            if ((x = hash & 0xF0000000L) != 0) {
                hash ^= (x >> 24);
            }
            hash &= ~x;
        }
        return hash;
    }

    /**
     * This hash function comes from Brian Kernighan and Dennis Ritchie's book
     * "The C Programming Language". It is a simple hash function using a
     * strange set of possible seeds which all constitute a pattern of
     * 31....31...31 etc, it seems to be very similar to the DJB hash function.
     * @param str
     * @return
     */
    public static long BKDRHash(String str) {
        long seed = 131; // 31 131 1313 13131 131313 etc..
        long hash = 0;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash * seed) + str.charAt(i);
        }
        return hash;
    }

    /**
     * This is the algorithm of choice which is used in the open source
     * SDBM project. The hash function seems to have a good over-all
     * distribution for many different data sets. It seems to work well in
     * situations where there is a high variance in the MSBs of the elements
     * in a data set.
     * @param str
     * @return
     */
    public static long SDBMHash(String str) {
        long hash = 0;
        for (int i = 0; i < str.length(); i++) {
            hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
        }
        return hash;
    }

    /**
     * An algorithm produced by Professor Daniel J. Bernstein and shown first
     * to the world on the usenet newsgroup comp.lang.c. It is one of the most
     * efficient hash functions ever published.
     * @param str
     * @return
     */
    public static long DJBHash(String str) {
        long hash = 5381;
        for (int i = 0; i < str.length(); i++) {
            hash = ((hash << 5) + hash) + str.charAt(i);
        }
        return hash;
    }

    /**
     * An algorithm proposed by Donald E. Knuth in The Art Of Computer
     * Programming Volume 3, under the topic of sorting and search chapter 6.4.
     * @param str
     * @return
     */
    public static long DEKHash(String str) {
        long hash = str.length();
        for (int i = 0; i < str.length(); i++) {
            hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
        }
        return hash;
    }

    public static long BPHash(String str) {
        long hash = 0;
        for (int i = 0; i < str.length(); i++) {
            hash = hash << 7 ^ str.charAt(i);
        }
        return hash;
    }

    public static long FNVHash(String str) {
        long fnv_prime = 0x811C9DC5;
        long hash = 0;
        for (int i = 0; i < str.length(); i++) {
            hash *= fnv_prime;
            hash ^= str.charAt(i);
        }
        return hash;
    }

    /**
     * An algorithm produced by me Arash Partow. I took ideas from all of the
     * above hash functions making a hybrid rotative and additive hash function
     * algorithm. There isn't any real mathematical analysis explaining why one
     * should use this hash function instead of the others described above
     * other than the fact that I tired to resemble the design as close as
     * possible to a simple LFSR.
     * @param str
     * @return
     */
    public static long APHash(String str) {
        long hash = 0xAAAAAAAA;
        for (int i = 0; i < str.length(); i++) {
            if ((i & 1) == 0) {
                hash ^= ((hash << 7) ^ str.charAt(i) * (hash >> 3));
            } else {
                hash ^= (~((hash << 11) + str.charAt(i) ^ (hash >> 5)));
            }
        }
        return hash;
    }

}
/**
 * Password generator class.
 * @author megavillain@gmail.com
 */
final class PasswordGenerator {

    public PasswordGenerator() {
        super();
        reset();
    }

    /**
     * Clear all fields.
     */
    public void reset() {
        skeletonKey = null;
        userName = null;
        host = null;
        password = null;
    }

    /**
     * Generates password.
     * @throws Exception
     */
    public void generate() throws IllegalArgumentException {
        if ((skeletonKey == null) || (host == null) || (userName == null) ||
             ("".equals(skeletonKey)) || ("".equals(host)) || ("".equals(userName))  ) {
            throw new IllegalArgumentException("Insufficient data.");
        }
        final long EVEN_MAGIC = 0x78D0A543;
        final long ODD_MAGIC = 0xF8295CE1;
        long evenHash = Hash.PJWHash(userName) ^ Hash.DJBHash(skeletonKey) ^ Hash.SDBMHash(host) ^ EVEN_MAGIC;
        long oddHash = Hash.SDBMHash(new StringBuffer(userName).reverse().toString()) ^
                       Hash.PJWHash(new StringBuffer(skeletonKey).reverse().toString()) ^
                       Hash.DJBHash(new StringBuffer(host).reverse().toString()) ^ ODD_MAGIC;
        final int PASSWORD_LENGTH = (int) (BASE_PASSWORD_LENGTH + abs(((Hash.APHash(host) ^ Hash.FNVHash(userName)) % BASE_PASSWORD_LENGTH)));
        StringBuilder builder = new StringBuilder(PASSWORD_LENGTH);
        for (int i = 0; i < PASSWORD_LENGTH; i++) {
            if ((i % 2) == 0) {
                builder.append(PASSWORD_CHARS.charAt((int) abs(((evenHash ^ (i * EVEN_MAGIC)) % PASSWORD_CHARS.length()))));
            } else {
                builder.append(PASSWORD_CHARS_REVERSED.charAt((int) abs(((oddHash ^ (i * ODD_MAGIC)) % PASSWORD_CHARS_REVERSED.length()))));
            }
        }
        password = builder.toString();
    }

    public void setSkeletonKey(final String value) {
        skeletonKey = value;
    }

    public String getSkeletonKey() {
        return skeletonKey;
    }

    public void setUserName(final String value) {
        userName = value;
    }

    public String getUserName() {
        return userName;
    }

    public void setHost(final String value) {
        host = value;
    }

    public String getHost() {
        return host;
    }

    public String getPassword() { //TODO: fix it
        return password;
    }
    
    private String skeletonKey = null; // user's passphrase
    private String userName = null; // user's name
    private String host = null; // password for what
    private String password = null; // password itself

    private static final int BASE_PASSWORD_LENGTH = 8;
    private static final String PASSWORD_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String PASSWORD_CHARS_REVERSED = new StringBuffer(PASSWORD_CHARS).reverse().toString();
}


/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
	public static void main (String[] args) throws java.lang.Exception
	{
		PasswordGenerator a = new PasswordGenerator();
		a.setUserName("random");
		a.setSkeletonKey("random");
		a.setHost("random");
		a.generate();
		System.out.println(a.getPassword());
	}
}