public class Passwd {

	public static final int ALPHA_MIN 	= 0x01;
	public static final int ALPHA_MAJ	= 0x02;
	public static final int NUMERIC		= 0x04;
	public static final int SPECIALS	= 0x08;
	public static final int ALLS		= ALPHA_MIN + ALPHA_MAJ + NUMERIC + SPECIALS;
	public static final int [] MODES 	= { ALPHA_MIN, ALPHA_MAJ, NUMERIC, SPECIALS };

	public static final int DEFAULT_LENGTH = 8;

	private int length;
	private int mode;
	private int maxs [] = new int [datas.length];
	private int actuals[] = new int [datas.length];
	private boolean has [] = new boolean[datas.length];
	private int max_occurs;

	private static boolean DEBUG;
	static { 
		DEBUG = Boolean.getBoolean("DEBUG"); 
		System.err.println(DEBUG);
	};


	public static final String [] datas = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "0123456789", "=+-$/!" };

	private char getChar(int mode) {
		return datas[mode].charAt((int)(datas[mode].length()*Math.random()));
	}

	public Passwd(int mode) {
		this(mode,DEFAULT_LENGTH);
	}
	
	public Passwd(int mode, int length) {
		this(mode,length,new int [] { length,length,length,length} ,-1);
	}
	
	public Passwd(int mode, int length, int [] maxs, int max_occurs) {
		this.mode 		= mode;
		this.length		= length;
		this.maxs	 	= maxs;
		this.max_occurs		= max_occurs;
		int MODE = mode;
		for (int i = MODES.length - 1 ; i >= 0 ; i--) {
			has[i] = ( MODE - MODES[i] >= 0 ? true : false);
			if ( has[i] ) MODE -= MODES[i];
		}
		if ( DEBUG ) {
			System.err.println("Mode = " + mode);
			System.err.println("Length = " + length);
			System.err.println("Maxs = " + maxs);
			System.err.println("max_occurs = " + max_occurs);
		}
	}
	
	public String getPassword() {
		String passwd = "";
		int c;
		char ch;
		int tmp;
		for (int i = 0 ; i < length ;) {
			c = (int)(Math.random()*datas.length);
			if ( has[c] && Math.pow(2,c) == MODES[c] && actuals[c] <= maxs[c]) {
				ch=getChar(c);
				if ( max_occurs > 1 ) {
					tmp = 0;
					for (int j = 0 ; j < passwd.length() ; j++ )
						if ( passwd.indexOf(ch,j) > 0 ) tmp++;
					if  ( tmp >= max_occurs ) continue;
				}
				passwd+= ch;
				if ( DEBUG ) System.out.println(passwd);
				actuals[c]++;
				i++;
			} 
		}
		return passwd;
	}
	public static void main(String [] a) {
		Passwd passwd = new Passwd(ALLS,10,new int [] {3, 2 ,2 , 3 } , 4);
		if ( DEBUG ) 
			System.err.println("Génération du passwd");
		System.out.println(passwd.getPassword());
	}
}

