package jp.sf.amateras.rdiffbackup.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;

import jp.sf.amateras.rdiffbackup.dto.ChangeDto;
import jp.sf.amateras.rdiffbackup.form.HistoryForm;
import jp.sf.amateras.rdiffbackup.util.PathUtil;
import jp.sf.amateras.rdiffbackup.util.RDiffBackup;
import jp.sf.amateras.rdiffbackup.util.ZipCompresser;

import org.seasar.struts.annotation.ActionForm;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.util.ResponseUtil;

/**
 * 指定されたディレクトリまたはファイルのバックアップ履歴を表示するアクションです。
 *
 * @author Naoki Takezoe
 */
public class HistoryAction {

	///////////////////////////////////////////////////////////////
	// 表示用プロパティ
	///////////////////////////////////////////////////////////////

	/**
	 * 履歴のタイムスタンプの一覧
	 */
	public List<String> historyList;

	/**
	 * 履歴の数
	 */
	public Integer historyCount;

	/**
	 * バックアップのルートディレクトリ
	 */
	public String root;

	/**
	 * 履歴表示を行うファイルまたはディレクトリのパス
	 */
	public String path;

	/**
	 * 履歴のタイムスタンプ
	 */
	public String date;

	/**
	 * 指定されたタイムスタンプの履歴の変更情報
	 */
	public List<ChangeDto> changeList;

	///////////////////////////////////////////////////////////////
	// DI用プロパティ
	///////////////////////////////////////////////////////////////

	/**
	 * アクションフォーム
	 */
	@Resource
	@ActionForm
	protected HistoryForm historyForm;

	///////////////////////////////////////////////////////////////
	// 実行メソッド
	///////////////////////////////////////////////////////////////

	/**
	 * 履歴のタイムスタンプ一覧を表示します。
	 *
	 * @return "index.jsp"
	 */
	@Execute(validator=true, input="/error.jsp")
	public String index(){
		// セキュリティチェック
		PathUtil.checkRoot(historyForm.root);
		PathUtil.checkPath(historyForm.path);

		this.root = historyForm.root;
		this.path = historyForm.path;

		// 処理対象のパスを作成
		String path = PathUtil.buildPath(this.root, this.path);

		// 履歴を取得
		this.historyList = RDiffBackup.list(path);
		this.historyCount = historyList.size();

		return "index.jsp";
	}

	/**
	 * 指定されたタイムスタンプの履歴の変更内容を表示します。
	 *
	 * @return "changes.jsp"
	 */
	@Execute(validator=true, input="/error.jsp")
	public String changes(){
		// セキュリティチェック
		PathUtil.checkRoot(historyForm.root);
		PathUtil.checkPath(historyForm.path);

		this.root = historyForm.root;
		this.path = historyForm.path;
		this.date = historyForm.date;

		// 処理対象のパスを作成
		String path = PathUtil.buildPath(this.root, this.path);

		this.changeList = RDiffBackup.changes(path, this.date);

		return "changes.jsp";
	}

	/**
	 * 履歴から指定されたタイムスタンプのファイルもしくはディレクトリをリストアしてダウンロードします。
	 * ディレクトリの場合はZIPファイルにアーカイブしたものをダウンロードします。
	 *
	 * @return null
	 */
	@Execute(validator=true, input="/error.jsp")
	public String download(){
		// セキュリティチェック
		PathUtil.checkRoot(historyForm.root);
		PathUtil.checkPath(historyForm.path);

		// 処理対象のパスを作成
		if(historyForm.path != null && historyForm.path.equals(".")){
			historyForm.path = null;
		}
		String path = PathUtil.buildPath(historyForm.root, historyForm.path);

		// ダウンロード処理
		File tmpDir = RDiffBackup.restore(path, historyForm.date);
		try {
			String fileName = PathUtil.getFileName(path);
			File file = new File(tmpDir, fileName);
			if(file.isFile()){
				// ファイルの場合は単体でダウンロード
				ResponseUtil.download(fileName, new FileInputStream(file));
			} else {
				// ディレクトリの場合はZIPにまとめてダウンロード
				ZipCompresser compresser = new ZipCompresser(file);
				compresser.archive();

				ResponseUtil.download(PathUtil.getDownloadFileName(fileName + ".zip"),
						new FileInputStream(new File(tmpDir, fileName + ".zip")));
			}

		} catch(IOException ex){
			throw new RuntimeException(ex);
		} finally {
			RDiffBackup.removeTemporaryDirectory();
		}

		return null;
	}

}
