package de.hsadmin.core.util.dns;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;

public class DNSResourceRecord {

	public String m_strDomainName;
	public int m_iType;
	public int m_iClass;
	public Date m_dtExpire = new Date();
	public int m_cbData;
	public byte [] m_abData = null;

	// these fields are interpreted differently depending on m_iType
	// (can you say union?)
	public long m_lData;
	public long m_lData1;
	public long m_lData2;
	public long m_lData3;
	public long m_lData4;
	public long m_lData5;

	public String m_strData;
	public String m_strData1;

	public boolean readRecord(DataInputStream dis, byte [] abData) {
		try {
			m_strDomainName = DNSQuery.ReadLabelList(dis, abData);
			m_iType = dis.readShort();
			m_iClass = dis.readShort();
			
			// time from DNS is in seconds, need milliseconds
			long lSecondsToLive = dis.readInt();
			
			Date dtNow = new Date();

			m_dtExpire.setTime(dtNow.getTime() + (lSecondsToLive * 1000L));

			m_cbData = dis.readShort();

			m_abData = null;

			switch (m_iType) {
			case DNSQuery.TYPE_A: {
				m_lData = dis.readInt();
			} break;

			case DNSQuery.TYPE_MX: {
				m_lData = dis.readShort();
				m_strData = DNSQuery.ReadLabelList(dis, abData);
			} break;

			case DNSQuery.TYPE_NS: 
			case DNSQuery.TYPE_MD: 
			case DNSQuery.TYPE_MF: 
			case DNSQuery.TYPE_CNAME: 
			case DNSQuery.TYPE_MB: 
			case DNSQuery.TYPE_MG: 
			case DNSQuery.TYPE_MR: 
			case DNSQuery.TYPE_PTR: {
				m_strData = DNSQuery.ReadLabelList(dis, abData);
			} break;

			case DNSQuery.TYPE_SOA: {
				// !!!LATER!!! I had a real problem getting this code to work.
				// I think the spec I had was old RFC 883
				m_strData = DNSQuery.ReadLabelList(dis, abData);
				m_strData1 = DNSQuery.ReadLabelList(dis, abData);

				// SERIAL
				m_lData = dis.readUnsignedShort();
				// REFRESH
				m_lData1 = dis.readInt() & 0xffffffff;
				// RETRY
				m_lData2 = dis.readInt() & 0xffffffff;
				// EXPIRE
				m_lData3 = dis.readInt() & 0xffffffff;
				// MINIMUM
				m_lData4 = dis.readUnsignedShort();
				// UNKNOWN
				m_lData5 = dis.readInt() & 0xffffffff;
			} break;

			case DNSQuery.TYPE_MINFO:
			case DNSQuery.TYPE_HINFO: {
				m_strData = DNSQuery.ReadLabelList(dis, abData);
				m_strData1 = DNSQuery.ReadLabelList(dis, abData);
			} break;

			default: {
				m_abData = new byte[m_cbData];
				dis.read(m_abData);
			} break;
			}
		} catch (IOException ioe) {
			System.err.println("exception: " + ioe.getMessage());
		}

		return true;
	}

	public String getMXServer() {
		if (m_iType != DNSQuery.TYPE_MX) {
			return new String();
		}

		return new String(m_strData);
	}

	public int getMXPref() {
		if (m_iType != DNSQuery.TYPE_MX) {
			return -1;
		}

		return (int)m_lData;
	}

	public void dumpRecord(PrintStream ps) {
		ps.println("Domain: " + m_strDomainName);
		ps.println("Type: " + DNSQuery.GetTypeDesc(m_iType));
		ps.println("Class: " + DNSQuery.GetClassDesc(m_iClass));
		
		ps.println("Expires: " + m_dtExpire.toString());

		switch (m_iType) {
		case DNSQuery.TYPE_A: {
			ps.println("IP Address: " + Long.toHexString(m_lData));
		} break;

		case DNSQuery.TYPE_MX: {
			ps.println("MX Server: " + m_strData);
			ps.println("MX Pref: " + Long.toString(m_lData));
		} break;

		case DNSQuery.TYPE_NS: 
		case DNSQuery.TYPE_MD: 
		case DNSQuery.TYPE_MF: 
		case DNSQuery.TYPE_CNAME: 
		case DNSQuery.TYPE_MB: 
		case DNSQuery.TYPE_MG: 
		case DNSQuery.TYPE_MR: 
		case DNSQuery.TYPE_PTR: {
			ps.println("Domain: " + m_strData);
		} break;

		case DNSQuery.TYPE_HINFO: {
			ps.println("CPU: " + m_strData);
			ps.println("OS: " + m_strData1);
		} break;

		case DNSQuery.TYPE_SOA: {
			ps.println("MNAME: " + m_strData);
			ps.println("RNAME: " + m_strData1);
			ps.println("SERIAL: " + Long.toString(m_lData));
			ps.println("REFRESH: " + Long.toString(m_lData1));
			ps.println("RETRY: " + Long.toString(m_lData2));
			ps.println("EXPIRE: " + Long.toString(m_lData3));
			ps.println("MINIMUM: " + Long.toString(m_lData4));
			ps.println("UNKNOWN: " + Long.toString(m_lData4));
		} break;

		default: {
			ps.println("Data: " + new String(m_abData));
			dumpBytes(ps, m_abData);
		}
		}
	}

	private void dumpBytes(PrintStream ps, byte [] ab) {
		int i;
		String strTemp;

		for (i = 0; i < ab.length; i++) {
			strTemp = Integer.toHexString(ab[i]);
			if (strTemp.length() < 2) {
				strTemp = "0" + strTemp;
			}

			ps.print(strTemp + " ");

			if (i > 0 && ((i % 8) == 0 || i == ab.length-1)) {
				ps.println();
			}
		}
	}

}
