package com.interpress_project.modernshare.ipcommon;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Vector;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import com.interpress_project.modernshare.ipcommon.fastMD5.util.MD5;

public class SystemUtilImpl {
	private Vector<String> vResult = null;

	/**
	 * SystemUtilImpl
	 */
	public SystemUtilImpl() {
	}

	/**
	 * url2hashname
	 * 
	 * @param url String
	 * @return String
	 */
	public String url2hashname(String url) {
		String foldername = MD5.asHex(url.getBytes());
		foldername += ".d";
		return foldername;
	}

	/**
	 * calcHash
	 * 
	 * @param src
	 * @return
	 */
	public String calcHash(String src) {
		return MD5.asHex(src.getBytes());
	}

	/**
	 * calcHash
	 * 
	 * @param file
	 * @return
	 */
	public String calcHash(File file) {
		SystemBase sb = SystemBase.getInstance();

		byte[] bytes = null;
		try {
			bytes = MD5.getHash(file);
		}
		catch (IOException ex) {
			sb.getLogger().error("ファイルのハッシュ値取得に失敗しました。", ex);
			return null;
		}
		return new String(bytes);
	}

	/**
	 * createHashedPassword
	 * 
	 * @param password
	 * @return
	 */
	public String createHashedPassword(String password) {
		long l = 0x3411;

		if (password.equals("")) {
			password = "masterkey";
		}
		byte[] bPassword = password.getBytes();
		for (int i = 0; i < bPassword.length; i++) {
			l += (l * bPassword[i]);
		}
		return calcHash(String.valueOf(l));
	}

	/**
	 * strReplace
	 * 
	 * @param aInput String
	 * @param aOldPattern String
	 * @param aNewPattern String
	 * @return String
	 */
	public static String strReplace(final String aInput, final String aOldPattern, final String aNewPattern) {

		if (aOldPattern.equals("")) {
			throw new IllegalArgumentException("Old pattern must have content.");
		}

		final StringBuffer result = new StringBuffer();
		int startIdx = 0;
		int idxOld = 0;
		while ((idxOld = aInput.indexOf(aOldPattern, startIdx)) >= 0) {
			result.append(aInput.substring(startIdx, idxOld));
			result.append(aNewPattern);

			startIdx = idxOld + aOldPattern.length();
		}
		result.append(aInput.substring(startIdx));
		return result.toString();
	}

	/**
	 * generateFileName
	 * 
	 * @param filename
	 * @return
	 */
	public String generateFileName(String filename) {
		File file = new File(filename);
		URI uri = file.toURI();
		String path = uri.getRawPath();
		path = path.replace('\\', '_');
		path = path.replace('/', '_');
		path = path.replace(':', '_');
		path = path.replace('?', '_');
		path = path.replace('<', '_');
		path = path.replace('>', '_');
		path = path.replace('"', '_');
		if (file.isDirectory()) {
			path += ".d";
		}
		return path;
	}

	/**
	 * generateFileNameFromURL
	 * 
	 * @param strurl String
	 * @return URI
	 */
	public static String generateFileNameFromURL(String strurl) {
		String fileName = "";
		try {
			URL url = new URL(strurl);
			String proto = url.getProtocol();
			fileName += proto;
			fileName += ".";

			String host = url.getHost();
			fileName += host;

			int port = url.getPort();
			if (port != -1) {
				fileName += ".";
				fileName += port;
			}

			String file = url.getFile();
			if (file != null) {
				fileName += ".";
				fileName += file;
			}

			String ref = url.getRef();
			if (ref != null) {
				fileName += ".";
				fileName += ref;
			}
			fileName = fileName.replace('/', '_');
			fileName = fileName.replace('|', '_');
			fileName = fileName.replace(':', '_');
			fileName = fileName.replace(',', '_');
			fileName = fileName.replace('?', '_');
			fileName = fileName.replace('>', '_');
			fileName = fileName.replace('<', '_');
			fileName = fileName.replace('"', '_');
		}
		catch (MalformedURLException ex) {
			ex.printStackTrace();
			return null;
		}
		return fileName;
	}

	/**
	 * createSecretKeySpec
	 * 
	 * @param seed String
	 * @return SecretKeySpec
	 */
	private SecretKeySpec createSecretKeySpec(String seed) {
		String _ts = seed + seed + seed;
		int h = _ts.hashCode();
		long l = h * h;
		_ts = String.valueOf(l);
		SecretKeySpec sksSpec = new SecretKeySpec(_ts.getBytes(), "RC4");
		return sksSpec;
	}

	/**
	 * crypt
	 * 
	 * @param accountName String
	 * @param password String
	 * @return String
	 */
	public String crypt(String seed, String target) {
		String result = null;
		try {
			SecretKeySpec sksSpec = createSecretKeySpec(seed);
			byte[] encrypted = null;
			Cipher cipher = null;
			cipher = Cipher.getInstance("RC4");
			cipher.init(Cipher.ENCRYPT_MODE, sksSpec);
			encrypted = cipher.doFinal(target.getBytes());
			result = ByteToHexStr(encrypted);
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}

	/**
	 * decrypt
	 * 
	 * @param accountName String
	 * @param encrypted String
	 * @return String
	 */
	public String decrypt(String seed, String target) {
		String result = null;
		try {
			byte[] bytes = HexStrToByte(target);
			SecretKeySpec sksSpec = createSecretKeySpec(seed);
			Cipher cipher = Cipher.getInstance("RC4");
			cipher.init(Cipher.DECRYPT_MODE, sksSpec);
			byte[] decrypted = cipher.doFinal(bytes);
			result = new String(decrypted);
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}

	/**
	 * ByteToHexStr バイト配列を16進数の文字列に変換する。
	 * 
	 * @param bytes バイト配列
	 * @return 16進数の文字列
	 */
	public String ByteToHexStr(byte[] bytes) {
		StringBuffer strbuf = new StringBuffer(bytes.length * 2);
		for (int index = 0; index < bytes.length; index++) {
			int bt = bytes[index] & 0xff;
			if (bt < 0x10) {
				strbuf.append("0");
			}
			strbuf.append(Long.toString(bt, 16));
		}
		return strbuf.toString();
	}

	/**
	 * HexStrToByte 16進数の文字列をバイト配列に変換する。
	 * 
	 * @param hex 16進数の文字列
	 * @return バイト配列
	 */
	public byte[] HexStrToByte(String hex) {
		byte[] bytes = new byte[hex.length() / 2];
		for (int index = 0; index < bytes.length; index++) {
			bytes[index] = (byte) Integer.parseInt(hex.substring(index * 2, (index + 1) * 2), 16);
		}
		return bytes;
	}

	/**
	 * removeDirectory
	 * @param fIn
	 */
	public void removeDirectory(File fIn) {
		int i;
		File f;
		String[] as;

		if (fIn.isDirectory()) {
			as = fIn.list(); // ....Get its file names
			for (i = 0; i < as.length; i++) { // ......For every file name
				f = new File(fIn, as[i]); // ........Create file obj
				removeDirectory(f); // ..........and process it.
			}
			fIn.delete();
			return;
		}
		fIn.delete();
	}

	/**
	 * executeCommand
	 * 
	 * @param commandLine String
	 * @param vResult Vector
	 * @return int
	 */
	public int executeCommand(String commandLine, Vector<String> vResult) {
		int retcode = 0;
		this.vResult = vResult;

		try {
			Runtime rt = Runtime.getRuntime();
			Process proc = rt.exec(commandLine);
			// any error message?
			StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");

			// any output?
			StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), null);

			// kick them off
			errorGobbler.start();
			outputGobbler.start();

			// any error???
			retcode = proc.waitFor();
		}
		catch (Throwable t) {
			t.printStackTrace();
		}
		return retcode;
	}

	class StreamGobbler extends Thread {
		InputStream is;
		String type;
		OutputStream os;

		/**
		 * StreamGobbler
		 * 
		 * @param is InputStream
		 * @param type String
		 */
		StreamGobbler(InputStream is, String type) {
			this(is, type, null);
		}

		/**
		 * StreamGobbler
		 * 
		 * @param is InputStream
		 * @param type String
		 * @param redirect OutputStream
		 */
		StreamGobbler(InputStream is, String type, OutputStream redirect) {
			this.is = is;
			this.type = type;
			this.os = redirect;
		}

		/**
		 * run
		 */
		public void run() {
			try {
				PrintWriter pw = null;
				if (os != null) {
					pw = new PrintWriter(os);
				}

				InputStreamReader isr = new InputStreamReader(is);
				BufferedReader br = new BufferedReader(isr);
				String line = null;
				while ((line = br.readLine()) != null) {
					if (pw != null) {
						pw.println(line);
					}
					if (type == null) {
						vResult.add(line);
					}
					else {
						System.out.println(type + ">" + line);
					}
				}
				if (pw != null) {
					pw.flush();
				}
			}
			catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
	}
}
