package org.opengion.fukurou.model;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;

import org.opengion.fukurou.util.HybsFileFilter;

/**
 * ローカルサーバのファイル操作クラス
 * 
 * FileOperationFactoryでデフォルトとして設定されており、
 * ローカルサーバでのファイル操作を行います。
 * ※java.io.Fileと同等のファイル操作になります。
 * 
 * @og.group ファイル操作
 * 
 * @og.rev 5.10.8.0 (2019/02/01) 新規作成
 * @author oota
 * @sinse JDK7.0
 */
public class DefaultFileOperation extends AbstractFileOperation {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "7.0.1.9 (2019/02/04)" ;
	private static final long serialVersionUID = 701920190204L ;

	// ファイル操作用
	private final File file;

	/**
	 * コンストラクタ
	 * 
	 * 引数のパスから、java.io.Fileインスタンスを生成します。
	 * @param inPath ファイルパス
	 * 
	 */
	public DefaultFileOperation(String inPath) {
		file = new File(inPath);
	}
	
	/**
	 * コンストラクタ
	 * 
	 * 引数のパスから、java.io.Fileインスタンスを生成します。
	 * FileOperationFactoryからの呼び出し用で、
	 * このクラスではbuketは使用しません。
	 * @param buket バケット
	 * @param inPath ファイルパス 
	 */
	public DefaultFileOperation(String buket, String inPath) {
		this(inPath);
	}

	/**
	 * InputStreamのデータを書き込みます。
	 * 
	 * @param is 書き込みデータのInputStream
	 * @throws IOException
	 */
	@Override
	public void write(final InputStream is) throws IOException {
		// InpustStreamを対象パスに出力
		Files.copy(is, Paths.get(file.getPath()), StandardCopyOption.REPLACE_EXISTING);
	}

	/**
	 * データを読み込み、InputStreamとして、返します。
	 * 
	 * @return 読み込みデータのInputStream
	 * @throws FileNotFoundException
	 */
	@Override
	public InputStream read() throws FileNotFoundException {
		return new FileInputStream(file.getPath());
	}

	/**
	 * ファイルを削除します。
	 * 
	 * @return 成否フラグ
	 */
	@Override
	public boolean delete() {
		return file.delete();
	}

	/**
	 * ファイルを指定先に、コピーします。
	 * 
	 * @param afPath コピー先
	 * @return 成否フラグ
	 */
	@Override
	public boolean copy(String afPath) {
		boolean flgRtn = false;

		try {
			// 指定パスのファイルを、指定先にコピー from;jdk7
			Files.copy(Paths.get(file.getPath()), Paths.get(afPath), StandardCopyOption.REPLACE_EXISTING);
			flgRtn = true;
		} catch (IOException ie) {
			// スルーしてfalseを返す
		}

		return flgRtn;
	}

	/**
	 * ファイルを指定先に、移動します。
	 * 
	 * @param afPath 移動先
	 * @return 成否フラグ
	 */
	@Override
	public boolean move(String afPath) {
		boolean flgRtn = false;

		try {
			// 指定パスのファイルを、指定先に移動 from:jdk7
			Files.move(Paths.get(file.getPath()), Paths.get(afPath), StandardCopyOption.REPLACE_EXISTING);
			flgRtn = true;
		} catch (IOException ie) {
			// スルーしてfalseを返す
		}
		return flgRtn;
	}

	/**
	 * 設定パスを取得します。
	 * 
	 * @return 設定パス
	 */
	@Override
	public String getPath() {
		return file.getPath();
	}

	/**
	 * 絶対パスを取得します。
	 * 
	 * @return 絶対パス
	 */
	@Override
	public String getAbsolutePath() {
		return file.getAbsolutePath();
	}

	/**
	 * 名称を取得します。
	 * 
	 * @return 名称
	 */
	@Override
	public String getName() {
		return file.getName();
	}

	/**
	 * 親のパスを取得します。
	 * 
	 * @return 親のパス
	 */
	@Override
	public String getParent() {
		return file.getParent();
	}

	/**
	 * ファイルサイズを返します
	 * 
	 * @return ファイルサイズ
	 */
	@Override
	public long length() {
		return file.length();
	}

	/**
	 * 最終更新時刻を取得します。
	 * 
	 * @return 最終更新時刻
	 */
	@Override
	public long lastModified() {
		return file.lastModified();
	}

	/**
	 * ファイルの場合は、trueを返します。
	 * 
	 * @return ファイルフラグ
	 */
	@Override
	public boolean isFile() {
		return file.isFile();
	}

	/**
	 * ディレクトリの場合は、trueを返します。
	 * 
	 * @return ディレクトリフラグ
	 */
	@Override
	public boolean isDirectory() {
		return file.isDirectory();
	}

	/**
	 * 存在する場合は、trueを返します。
	 * 
	 * @return 存在フラグ
	 */
	@Override
	public boolean exists() {
		return file.exists();
	}

	/**
	 * パスのファイルとディレクトリ一覧を取得します。
	 * 
	 * @return ファイルとティレクトリ一覧
	 */
	@Override
//	public FileOperation[] listFiles() {
	public File[] listFiles() {
		return listFiles(new HybsFileFilter());
	}

	/**
	 * パスのファイルとディレクトリ一覧を取得して、
	 * 引数でフィルターを行います。
	 * 
	 * @param filter フィルター
	 * @return	ファイルとディレクトリ一覧
	 */
	@Override
//	public FileOperation[] listFiles(FileOperationFileFilter filter) {
	public File[] listFiles(FileFilter filter) {
		// 存在チェック
		if (!exists()) {
			return new FileOperationInfo[0];
		}

		// カノニカルファイル取得
		File trg = null;
		try {
			trg = file.getCanonicalFile();
		} catch (IOException ie) {
			return new FileOperationInfo[0];
		}

		// 直下のファイルとディレクトリ情報の取得
		File[] files = trg.listFiles();

		// 取得情報をリストに格納
		List<FileOperationInfo> fileList = new ArrayList<FileOperationInfo>();
		for (File file : files) {
			FileOperationInfo info = new FileOperationInfo();

			info.setPath(file.getPath());
			info.setName(file.getName());
			info.setParent(file.getParent());
			info.setLastModifiedValue(file.lastModified());
			info.setCanWrite(file.canWrite());
			info.setCanRead(file.canRead());
			info.setHidden(file.isHidden());

			if (file.isFile()) {
				// ファイル情報
				info.setFile(true);
				info.setSize(file.length());
			} else if (file.isDirectory()) {
				// ディレクトリ情報
				info.setDirectory(true);
			}

			fileList.add(info);
		}

		// フィルタ処理
//		FileOperation[] rtnArray = filter(fileList, filter);
		File[] rtnArray = filter(fileList, filter);

		return rtnArray;
	}

	/**
	 * ディレクトリを作成します。
	 * 
	 * ※１つのディレクトリのみ作成します。
	 * (クラウドストレージにはディレクトリの概念が無いため、
	 * 作成は行わず、trueを返します)
	 * 
	 * @return 成否フラグ
	 */
	@Override
	public boolean mkdir() {
		return file.mkdir();
	}

	/**
	 * ディレクトリを作成します。
	 * 
	 * ※複数のディレクトリを作成します。
	 * (クラウドストレージにはディレクトリの概念が無いため、
	 * 作成は行わず、trueを返します)
	 * 
	 * @return 成否フラグ
	 */
	@Override
	public boolean mkdirs() {
		return file.mkdirs();
	}

	/**
	 * 指定のファイル情報のファイル名に変更します。
	 * 
	 * @param dest 変更後のファイル情報
	 * @return 成否フラグ
	 */
	@Override
	public boolean renameTo(FileOperation dest) {
		return file.renameTo(new File(dest.getPath()));
	}

	/**
	 * 親のディレクトリを返します。
	 * 
	 * @return 親のディレクトリ
	 */
	@Override
	public FileOperation getParentFile() {
		return new DefaultFileOperation(getParent());
	}

	/**
	 * 書き込み可能フラグ
	 * 
	 * ※クラウドストレージの場合は、
	 * 必ずtrueを返します。
	 * 
	 * @return 書き込み可能フラグ
	 */
	@Override
	public boolean canWrite() {
		return file.canWrite();
	}

	/**
	 * 読み取り可能フラグ
	 * 
	 * ※クラウドストレージの場合は、
	 * 必ずtrueを返します。
	 * 
	 * @return 読み取り可能フラグ
	 */
	@Override
	public boolean canRead() {
		return file.canRead();
	}

	/**
	 * 隠しファイルフラグ
	 * 
	 * ※クラウドストレージの場合は、
	 * 必ずfalseを返します。
	 * 
	 * @return 隠しファイルフラグ
	 */
	@Override
	public boolean isHidden() {
		return file.isHidden();
	}

	/**
	 * 新規ファイル作成
	 * 
	 * 既にファイルが存在しない場合のみ、
	 * 空のファイルを作成します。
	 *
	 * @return 成否フラグ
	 * @throws IOException
	 */
	@Override
	public boolean createNewFile() throws IOException {
		return file.createNewFile();
	}

	/**
	 * 最終更新時刻の更新
	 * 
	 * 最終更新時刻の更新を行います。
	 * ※クラウドストレージの場合は、
	 * 最終更新時刻の更新を行えません。
	 * 
	 * @param time 更新する最終更新時刻
	 * @return 成否フラグ
	 */
	@Override
	public boolean setLastModified(long time) {
		return file.setLastModified(time);
	}

	/**
	 * カノニカルファイル情報を取得します。
	 * 
	 * ※ローカルサーバのみ通常ファイルと、
	 * カノニカルファイルで異なります。
	 * 
	 * @return カノニカルファイル情報
	 * @throws IOException
	 */
	@Override
	public FileOperation getCanonicalFile() throws IOException {
		File path = file.getCanonicalFile();
		return new DefaultFileOperation(path.getPath());
	}

	/**
	 * toStringでは、パスを返します。
	 * 
	 * @return パス
	 */
	@Override
	public String toString() {
		return getPath();
	}

	/**
	 * テスト用メソッドです
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		// listTest();
		// methodTest();
	}
	/* テスト用
	// リストテスト用
	public static void listTest() {
		String path = "";
		FileOperation file = new DefaultFileOperation(path);
		
		try {
			// フィルタを行う場合
			// 以下の場合は、bで始まるファイルと、全てのディレクトリ（指定パスの直下)が取得されます。
			// HybsFileOperationFileFilter filter = new HybsFileOperationFileFilter();
			HybsFileFilter filter = new HybsFileFilter(true);
			filter.startsWith("b");
			
			FileOperation[] list = file.getCanonicalFile().listFiles(filter);
			
			System.out.println(list.length);
			for(FileOperation f: list) {
				System.out.println(f.getPath());
			}
		}catch(Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	// メソッドテスト用
	public static void methodTest() {
		String path = "H:/tmp/test/newfile.txt";
		FileOperation file = new DefaultFileOperation(path);
		
		String afPath = "H:/tmp/test/af.txt";
		FileOperation af = new DefaultFileOperation(afPath);
		
		try {
			boolean rtn =
			//file.renameTo(af);
			file.createNewFile();
			//file.mkdirs();
			//file.getCanonicalFile().exists();
			System.out.println(rtn);
		}catch(Exception e) {
			System.out.println(e.getMessage());
		}
	}
	//*/
}
