/*
 * Copyright (c) 2005- Shinji Kashihara.
 * All rights reserved. This program are made available under
 * the terms of the Eclipse Public License v1.0 which accompanies
 * this distribution, and is available at epl-v10.html.
 */
package jp.sourceforge.mergedoc.pleiades.resource;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;

import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;

/**
 * ファイル・ユーティリティーです。
 * <p>
 * @author cypher256
 */
public class Files {

	/** リソース・ルート */
	public static final File resourceRoot;

	// ルートの取得
	static {
		String markResource = "/.marker";
		URL url = Files.class.getResource(markResource);
		if (url == null) {

			// 注）ロガーはログ設定前に初期化されてしまうため使用しない
			String msg = "クラスパス上にファイルが見つかりません。" + markResource;
			Exception e = new FileNotFoundException(msg);
			System.err.println(msg + " " + e);
			throw new IllegalStateException(msg, e);
		}
		String path = new File(url.getPath()).getParent();
		String unicodePath = decodeURL(path);
		resourceRoot = new File(unicodePath);
	}

	/**
	 * インスタンス化できません。
	 */
	private Files() {
	}

	/**
	 * application/x-www-form-urlencoded 文字列をデコードします。
	 * <ul>
	 * <li>例）%e3%81%82 -> あ
	 * <li>プラス記号 (+) は空白に戻しません。
	 * <ul>
	 * @param urlPath デコード前のパス
	 * @return デコード後のパス
	 */
	public static String decodeURL(String urlPath) {
		if (urlPath.contains("\t")) {
			throw new IllegalArgumentException("引数に \\t を含めることはできません。");
		}
		try {
			String s = urlPath.replace('+', '\t');
			s = URLDecoder.decode(s, "UTF-8");
			s = s.replace('\t', '+');
			return s;
		} catch (UnsupportedEncodingException e) {
			throw new IllegalStateException(e);
		}
	}

	/**
	 * リソース・ルートからの相対パスを指定し、File オブジェクトを取得します。
	 * リソース・ルートとはクラスパス上の .marker が存在するディレクトリーで、
	 * 以下のディレクトリーを指します。
	 * <p>
	 * plugins/jp.sourceforge.mergedoc.pleiades/conf
	 * <p>
	 * @param resourcePath リソース・パス文字列
	 * @return リソース File オブジェクト
	 */
	public static File getFile(String resourcePath) {
		return new File(resourceRoot, resourcePath);
	}

	/**
	 * 指定したフォルダーからファイルへの相対パス文字列を取得します。
	 * <p>
	 * @param folder フォルダー
	 * @param file ファイル
	 * @return 相対パス文字列
	 */
	public static String relativePath(File folder, File file) {
		try {
			String folderPath = folder.getCanonicalPath();
			String filePath = file.getCanonicalPath();
			return filePath.replace(folderPath, "");

		} catch (IOException e) {
			throw new IllegalArgumentException(folder + ", " + file, e);
		}
	}

	/**
	 * 指定したパスをバージョン管理外の名前にします。<br>
	 * 例）aaa/bbb.txt → aaa/.bbb.txt
	 * <p>
	 * @param path パスn
	 * @return バージョン管理外にした名前
	 */
	public static String toVcIgnoreName(String path) {
		return path.contains("/") ? path.replaceFirst("(.*/)(.*)", "$1.$2") : "." + path;
	}

	/**
	 * ディレクトリーのファイル・フィルターを作成します。
	 * @return ファイル・フィルター
	 */
	public static FileFilter createDirectoryFilter() {
		return DirectoryFileFilter.INSTANCE;
	}

	/**
	 * ファイルのファイル・フィルターを作成します。
	 * @return ファイル・フィルター
	 */
	public static FileFilter createFileFilter() {
		return FileFileFilter.FILE;
	}

	/**
	 * 接尾辞を指定してファイル・フィルターを作成します。
	 * @param suffix 接尾辞
	 * @return ファイル・フィルター
	 */
	public static FileFilter createSuffixFilter(String suffix) {
		return new SuffixFileFilter(suffix);
	}
}
