package net.argius.filetool;

import java.io.*;

/**
 * ファイル解凍処理。
 */
public final class FileDecompressor {

    /**
     * ファイルを解凍する。
     * 出力先ファイルは、元ファイルの圧縮タイプの拡張子を除去したものになる。
     * @param src 解凍元ファイル
     * @throws IOException 入出力エラーが発生した場合
     */
    public static void decompress(File src) throws IOException {
        String name = src.getName();
        String newName;
        CompressType type = CompressType.getType(src);
        if (type == CompressType.GZIP) {
            newName = name.substring(0, name.length() - 3);
        } else if (type == CompressType.BZIP2) {
            newName = name.substring(0, name.length() - 4);
        } else {
            throw new IllegalArgumentException("can't detect type by suffix");
        }
        File dst = new File(src.getParentFile(), newName);
        decompress(src, dst, type);
    }

    /**
     * ファイルを解凍する。
     * @param src 解凍元ファイル
     * @param dst 出力先ファイル
     * @throws IOException 入出力エラーが発生した場合
     */
    public static void decompress(File src, File dst) throws IOException {
        decompress(src, dst, CompressType.getType(src));
    }

    /**
     * ファイルを解凍する。
     * @param src 解凍元ファイル
     * @param type 圧縮タイプ
     * @throws IOException 入出力エラーが発生した場合
     */
    public static void decompress(File src, CompressType type) throws IOException {
        File dst;
        if (type == CompressType.GZIP) {
            dst = new File(src.getParentFile(), src.getName() + ".gz");
        } else if (type == CompressType.BZIP2) {
            dst = new File(src.getParentFile(), src.getName() + ".bz2");
        } else {
            throw new IllegalArgumentException();
        }
        decompress(src, dst, type);
    }

    /**
     * ファイルを解凍する。
     * @param src 解凍元ファイル
     * @param dst 出力先ファイル
     * @param type 圧縮タイプ
     * @throws IOException 入出力エラーが発生した場合
     */
    public static void decompress(File src, File dst, CompressType type) throws IOException {
        File tmp = Utilities.createTemporaryFile();
        Decompressor decompressor;
        if (type == CompressType.GZIP) {
            decompressor = new GzipDecompressor(new FileInputStream(src));
        } else if (type == CompressType.BZIP2) {
            decompressor = new Bzip2Decompressor(new FileInputStream(src));
        } else {
            throw new IllegalArgumentException();
        }
        try {
            OutputStream os = new FileOutputStream(tmp);
            try {
                decompressor.decompress(os);
            } finally {
                os.close();
            }
        } finally {
            decompressor.close();
        }
        IOUtilities.move(tmp, dst, false);
        dst.setLastModified(src.lastModified());
    }

    /**
     * 使い方の表示。
     */
    private static void printUsage() {
        PrintStream err = System.err;
        err.println("FileDecompressor (argius-filetool)");
        err.println("usage : (command) src [dst]");
        err.println("options: none");
    }

    /**
     * FileDecompressorの実行。
     * @param args パラメータ(see 'usage')
     */
    public static void main(String[] args) {
        if (args.length < 1) {
            printUsage();
            return;
        }
        for (int i = 0; i < args.length; i++) {
            String arg = args[i];
            if (arg.equals("-h") || arg.equals("--help")) {
                printUsage();
                return;
            }
        }
        final String commandNameInfo = "FileDecompressor: ";
        int status;
        try {
            if (args.length >= 2) {
                FileDecompressor.decompress(new File(args[0]), new File(args[1]));
            } else {
                FileDecompressor.decompress(new File(args[0]));
            }
            status = 0;
        } catch (IOException ex) {
            System.out.println(commandNameInfo + ex.getMessage());
            status = 1;
        } catch (Exception ex) {
            String message = ex + Utilities.getFirstStackTrace(ex, DiskUsage.class);
            System.out.println(commandNameInfo + message);
            status = 255;
        }
        if (status > 0) {
            System.exit(status);
        }
    }

}
