import java.util.*;
import java.io.*;
import java.net.InetAddress;

class AgoraUserBase
{
    private Hashtable lookupLogin = new Hashtable();
	private ChunkVolume userVolume = null;
	private ChunkFile userFile = null;
	private ChunkFile memberDir = null;
	private ChunkFile loginDir = null;
	private ChunkFile nickDir = null;
	private ChunkFile ipDir = null;
	private ChunkFile anonIdDir = null;
	private ChunkFile logIdDir = null;

    public AgoraUserBase() {
		try { userVolume = new ChunkVolume("Users"); }
		catch (IOException e) {};
		userFile = new ChunkFile(userVolume,"");
		ChunkFile memDir = new ChunkFile(userFile,"Members");
		loginDir = new ChunkFile(memDir,"Login");
		memDir.mkdir();
		ipDir = new ChunkFile(memDir,"IPAddress");
		ipDir.mknumdir();
		memberDir = new ChunkFile(memDir,"Id");
		memberDir.mknumdir();
		anonIdDir = new ChunkFile(memDir,"AnonymousId");
		anonIdDir.mknumdir();
		logIdDir = new ChunkFile(memDir,"LogId");
		logIdDir.mknumdir();
    }

	public String getLoginFromIP(InetAddress ip) {
		byte[] rawIp = ip.getAddress();
		int ipValue = (rawIp[0] & 0xFF) << 24 | (rawIp[1] & 0xFF) << 16 | 
			(rawIp[2] & 0xFF) << 8 | (rawIp[3] & 0xFF);
		ChunkFile found = new ChunkFile (ipDir, ipValue);
		if (found.exists()) {
			return (new ChunkFile (found, "login").GetString());
		}
		else return (null);
	}

	public void setIPForLogin(String login, InetAddress ip) {
		byte[] rawIp = ip.getAddress();
		int ipValue = (rawIp[0] & 0xFF) << 24 | (rawIp[1] & 0xFF) << 16 | 
			(rawIp[2] & 0xFF) << 8 | (rawIp[3] & 0xFF);
		ChunkFile found = new ChunkFile (loginDir, login);
		if (found.exists()) {
			int ipOld = new ChunkFile (found, "ip").GetInteger();
			if (ipOld == -1 || ipOld != ipValue) {
				ChunkFile oldIp = new ChunkFile (ipDir, ipOld);
				if (ipOld != -1 && oldIp.exists()) {
					oldIp.renameTo(new Integer(ipValue).toString());
				}
				else {
					ChunkFile newIp = new ChunkFile(ipDir, ipValue);
					if (newIp.exists()) 
						new ChunkFile (newIp,"ip").delete();
					new ChunkFile (found, "ip").SetInteger(ipValue);
					newIp.link(found);
				}
			}
		}
	}

	public ChunkFile memberDirectory (int id)
	{
		return new ChunkFile(memberDir,id);
	}

	public ChunkFile memberAttribute (AgoraUser theUser, String attribute)
	{
		return (memberAttribute(theUser.getId(), attribute));
	}

	public ChunkFile memberAttribute (int id, String attribute)
	{
		return new ChunkFile(memberDirectory(id),attribute);
	}

    protected int getNewId() {
		int retVal = Integer.parseInt(memberDir.uniquedir().getName());
		return (retVal);
    }

    public int addUser (int where, String inLogin) {
		String login = inLogin.toLowerCase();
        if (where == -1) {
            where = getNewId();
            if (where == -1)
                return (where);

            ChunkFile userDir = new ChunkFile (memberDir,where);
			int anonymous;
			do {
				anonymous = (int) (Math.random() * Integer.MAX_VALUE);
			} while (new ChunkFile (anonIdDir,anonymous).exists());
				
			int logId;
			do {
				logId = (int) (Math.random() * Integer.MAX_VALUE);
			} while (new ChunkFile (logIdDir,logId).exists());

			memberAttribute (where, "id").SetInteger(where);
			memberAttribute (where, "login").SetString(login);
			memberAttribute (where, "logId").SetInteger(logId);
			memberAttribute (where, "anonymous").SetInteger(anonymous);
			memberAttribute (where, "created").SetLong(new Date().getTime());
				
			new ChunkFile (loginDir,login).link(userDir);
			new ChunkFile (anonIdDir,anonymous).link(userDir);
			new ChunkFile (logIdDir,logId).link(userDir);
        }
        lookupLogin.put(login, new Integer (where));
        return (where);
    }

    public int getUserFromLogin (String login) {
        if (login != null) {
            Integer id = (Integer) lookupLogin.get(login.toLowerCase());
			if (id == null) {	
				ChunkFile userDir = new ChunkFile(loginDir,login);
				if (userDir.exists()) {
					return (addUser(new ChunkFile(userDir,"id").GetInteger(),login));
				}
				else return (-1);
			}
            else return (id.intValue());
        }
        else return (-1);
    }
}
