package com.ejie.aa21b.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 * Helper class to get mimetype
 * 
 *  
 */
@SuppressWarnings("nls")
public final class MimeTypes {

	private MimeTypes() {
		// not called
	}

	public static String getContentType(byte[] data) {
		return getContentType(data, null);
	}

	public static String getContentType(byte[] data, String name) {
		if (data == null) {
			return null;
		}
		byte[] header = new byte[11];
		System.arraycopy(data, 0, header, 0,
				Math.min(data.length, header.length));
		int c1 = header[0] & 0xff;
		int c2 = header[1] & 0xff;
		int c3 = header[2] & 0xff;
		int c4 = header[3] & 0xff;
		int c5 = header[4] & 0xff;
		int c6 = header[5] & 0xff;
		int c7 = header[6] & 0xff;
		int c8 = header[7] & 0xff;
		int c9 = header[8] & 0xff;
		int c10 = header[9] & 0xff;
		int c11 = header[10] & 0xff;

		if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
			return "application/java-vm";
		}

		if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && c5 == 0xA1
				&& c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
			// if the name is set then check if it can be validated by name,
			// because it could be a xls or powerpoint
			String contentType = guessContentTypeFromName(name);
			if (contentType != null) {
				return contentType;
			}
			return "doc";// "application/msword";
		}
		if (c1 == 0x25 && c2 == 0x50 && c3 == 0x44 && c4 == 0x46 && c5 == 0x2d
				&& c6 == 0x31 && c7 == 0x2e) {
			return "pdf";// "application/pdf";
		}

		if (c1 == 0x38 && c2 == 0x42 && c3 == 0x50 && c4 == 0x53 && c5 == 0x00
				&& c6 == 0x01) {
			return "image/photoshop";
		}

		if (c1 == 0x25 && c2 == 0x21 && c3 == 0x50 && c4 == 0x53) {
			return "application/postscript";
		}

		if (c1 == 0xff && c2 == 0xfb && c3 == 0x30) {
			return "audio/mp3";
		}

		if (c1 == 0x49 && c2 == 0x44 && c3 == 0x33) {
			return "audio/mp3";
		}

		if (c1 == 0xAC && c2 == 0xED) {
			// next two bytes are version number, currently 0x00 0x05
			return "application/x-java-serialized-object";
		}

		if (c1 == '<') {
			if (c2 == '!'
					|| ((c2 == 'h'
							&& (c3 == 't' && c4 == 'm' && c5 == 'l' || c3 == 'e'
									&& c4 == 'a' && c5 == 'd') || (c2 == 'b'
							&& c3 == 'o' && c4 == 'd' && c5 == 'y')))
					|| ((c2 == 'H'
							&& (c3 == 'T' && c4 == 'M' && c5 == 'L' || c3 == 'E'
									&& c4 == 'A' && c5 == 'D') || (c2 == 'B'
							&& c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
				return "text/html";
			}

			if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
				return "application/xml";
			}
		}

		// big and little endian UTF-16 encodings, with byte order mark
		if (c1 == 0xfe && c2 == 0xff) {
			if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && c7 == 0
					&& c8 == 'x') {
				return "application/xml";
			}
		}

		if (c1 == 0xff && c2 == 0xfe) {
			if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && c7 == 'x'
					&& c8 == 0) {
				return "application/xml";
			}
		}

		if (c1 == 'B' && c2 == 'M') {
			return "image/bmp";
		}

		if (c1 == 0x49 && c2 == 0x49 && c3 == 0x2a && c4 == 0x00) {
			return "image/tiff";
		}

		if (c1 == 0x4D && c2 == 0x4D && c3 == 0x00 && c4 == 0x2a) {
			return "image/tiff";
		}

		if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
			return "image/gif";
		}

		if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
			return "image/x-bitmap";
		}

		if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && c5 == 'M'
				&& c6 == '2') {
			return "image/x-pixmap";
		}

		if (c1 == 137 && c2 == 80 && c3 == 78 && c4 == 71 && c5 == 13
				&& c6 == 10 && c7 == 26 && c8 == 10) {
			return "image/png";
		}

		if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
			if (c4 == 0xE0) {
				return "image/jpeg";
			}

			/**
			 * File format used by digital cameras to store images. Exif Format
			 * can be read by any application supporting JPEG. Exif Spec can be
			 * found at:
			 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
			 */
			if ((c4 == 0xE1)
					&& (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 == 'f' && c11 == 0)) {
				return "image/jpeg";
			}

			if (c4 == 0xEE) {
				return "image/jpg";
			}
		}

		/**
		 * According to http://www.opendesign.com/files/guestdownloads/
		 * OpenDesign_Specification_for_.dwg_files.pdf first 6 bytes are of type
		 * "AC1018" (for example) and the next 5 bytes are 0x00.
		 */
		if ((c1 == 0x41 && c2 == 0x43)
				&& (c7 == 0x00 && c8 == 0x00 && c9 == 0x00 && c10 == 0x00 && c11 == 0x00)) {
			return "application/acad";
		}

		if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
			return "audio/basic"; // .au
			// format,
			// big
			// endian
		}

		if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
			return "audio/basic"; // .au
			// format,
			// little
			// endian
		}

		if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
			/*
			 * I don't know if this is official but evidence suggests that .wav
			 * files start with "RIFF" - brown
			 */
			return "audio/x-wav";
		}

		if (c1 == 'P' && c2 == 'K') {
			// its application/zip but this could be a open office thing if name
			// is given
			String contentType = guessContentTypeFromName(name);
			if (contentType != null) {
				return contentType;
			}
			return "docx";// "application/zip";
		}
		return guessContentTypeFromName(name);
	}

	private static final Map<String, String> mimeTypes = new HashMap<String, String>();

	public static String guessContentTypeFromName(String name) {
		if (name == null)
			return null;

		int lastIndex = name.lastIndexOf('.');
		if (lastIndex != -1) {
			String extention = name.substring(lastIndex + 1).toLowerCase();
			if (mimeTypes.size() == 0) {
				HashMap<String, String> tempMap = new HashMap<String, String>();
				InputStream is = MimeTypes.class
						.getResourceAsStream("mime.types.properties");
				try {
					Properties properties = new Properties();
					properties.load(is);
					for (Object key : properties.keySet()) {
						String property = properties.getProperty((String) key);
						StringTokenizer st = new StringTokenizer(property, " ");
						while (st.hasMoreTokens()) {
							tempMap.put(st.nextToken(), (String) key);
						}
					}
				} catch (IOException e) {
					// Debug.error(e);
				} finally {
					try {
						is.close();
					} catch (IOException e) {
						// Debug.error(e);
					}
				}
				synchronized (mimeTypes) {
					mimeTypes.putAll(tempMap);
				}
			}
			return mimeTypes.get(extention);
		}
		return null;
	}
}