/*
 * 作成日: 2005/03/26
 *
 * TODO この生成されたファイルのテンプレートを変更するには次へジャンプ:
 * ウィンドウ - 設定 - Java - コード・スタイル - コード・テンプレート
 */
package igapyon.eclipse.installer;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;

/**
 * @author iga
 * 
 * TODO この生成された型コメントのテンプレートを変更するには次へジャンプ: ウィンドウ - 設定 - Java - コード・スタイル -
 * コード・テンプレート
 */
public class CopyThread extends Thread {
    boolean isSuccessEnd = false;

    String[] MODULE_LIST = null;

    Display display = null;

    ProgressShowShell progresspanel = null;

    String targetDirectory = null;

    public CopyThread(String[] MODULE_LIST, Display display,
            ProgressShowShell progresspanel, String targetDirectory) {
        this.MODULE_LIST = MODULE_LIST;
        this.display = display;
        this.progresspanel = progresspanel;
        this.targetDirectory = targetDirectory;
        this.display.asyncExec(new AsyncExec());
    }

    public boolean isSuccessEnd() {
        return isSuccessEnd;
    }

    class AsyncExec implements Runnable {

        public void run() {
            try {
                // すべてのファイルを解凍します。
                for (int index = 0; index < MODULE_LIST.length; index++) {
                    progresspanel.setTargetArchiveName(MODULE_LIST[index]);

                    progresspanel.setDirectoryName("processing file["
                            + MODULE_LIST[index] + "].");
                    extractFileAll(MODULE_LIST[index], targetDirectory);
                }
                isSuccessEnd = true;
            } catch (IOException ex) {
                MessageBox msgboxError = new MessageBox(progresspanel.sShell,
                        SWT.OK | SWT.ICON_ERROR);
                msgboxError.setText(EcilpseInstallerTI.PRODUCT_NAME);
                msgboxError.setMessage("処理は異常終了しました\n" + ex.toString());
                msgboxError.open();

                ex.printStackTrace();
            } finally {
                progresspanel.sShell.close();
            }
        }

        /**
         * 与えられたZIPファイルを指定ディレクトリに解凍します。
         * 
         * @param strJarFileName
         * @param strTargetBaseDirectoryName
         * @throws IOException
         */
        public final void extractFileAll(String strJarFileName,
                String strTargetBaseDirectoryName) throws IOException {
            File fileInputJar = new File(strJarFileName);
            if (fileInputJar.exists() == false) {
                throw new FileNotFoundException("入力ファイル["
                        + fileInputJar.getAbsolutePath()
                        + "]が見つかりません.処理を中断します.");
            }

            String strFileSeparator = System.getProperty("file.separator");

            ZipInputStream zipinStream = new ZipInputStream(
                    new BufferedInputStream(new FileInputStream(fileInputJar)));
            for (int iCurrent = 0;; iCurrent++) {
                ZipEntry entry = zipinStream.getNextEntry();
                if (entry == null) {
                    break;
                }

                if (!progresspanel.sShell.isDisposed()) {
                    display.readAndDispatch();
                }

                if (entry.isDirectory()) {
                    String strNewDirectory = strTargetBaseDirectoryName
                            + strFileSeparator + entry.getName();
                    File fileDirectory = new File(strNewDirectory);
                    if (fileDirectory.exists() == false) {
                        System.out.println("new directory:"
                                + fileDirectory.getAbsolutePath());
                        if (fileDirectory.mkdirs() == false) {
                            System.err.println("fail to create new directory:"
                                    + fileDirectory.getAbsolutePath());
                        }
                    }
                    progresspanel.setDirectoryName(fileDirectory
                            .getAbsolutePath());
                } else {
                    String strNewFile = strTargetBaseDirectoryName
                            + strFileSeparator + entry.getName();
                    File fileExtract = new File(strNewFile);
                    if (fileExtract.exists()) {
                        if (fileExtract.canWrite() == false) {
                            System.out.println("can't overwrite exist file:"
                                    + fileExtract.getAbsolutePath());
                            continue;
                        }
                    }
                    System.out.println("Processing file ["
                            + fileExtract.getName() + "]");
                    progresspanel.setProgress(iCurrent);
                    progresspanel.setFileName(fileExtract.getAbsolutePath());
                    if (iCurrent >= 100) {
                        iCurrent = 0;
                    }

                    extractFile(zipinStream, fileExtract, entry.getTime());
                }
            }
        }

        /**
         * 与えられた入力ストリームをファイル宛に書出します。 <br>
         * なお、このメソッド中ではクローズは行いません。これはZIP入力ストリームの仕様によるものです。
         * 
         * @param inStream
         *            ZIP入力ストリームが与えられます。
         * @param fileExtract
         * @throws FileNotFoundException
         * @throws IOException
         */
        private void extractFile(InputStream inStream, File fileExtract,
                long lastModified) throws FileNotFoundException, IOException {
            OutputStream outStream = null;

            File directory = new File(fileExtract.getAbsoluteFile().getParent());
            if (directory.exists() == false) {
                System.out.println("ディレクトリ [" + directory.getAbsolutePath()
                        + "] が無いので新規作成します.");
                directory.mkdirs();
            }

            try {
                outStream = new BufferedOutputStream(new FileOutputStream(
                        fileExtract));
                byte[] byteRead = new byte[8192];
                for (;;) {
                    int iReadLen = inStream.read(byteRead);
                    if (iReadLen < 0) {
                        break;
                    }
                    outStream.write(byteRead, 0, iReadLen);
                }
                outStream.flush();
            } finally {
                if (outStream != null) {
                    outStream.close();
                    outStream = null;
                }
            }
            fileExtract.setLastModified(lastModified);
        }
    }
}
