
package jp.riken.brain.ni.samuraigraph.application;

import java.awt.Component;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import jp.riken.brain.ni.samuraigraph.base.SGDrawingWindow;
import jp.riken.brain.ni.samuraigraph.base.SGExtensionFileFilter;
import jp.riken.brain.ni.samuraigraph.base.SGFileChooser;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;


/**
 * Extract an archive file.
 */
public class SGArchiveFileExtractor
	implements SGIConstants, SGIArchiveFileConstants
{
	
	/**
	 * Current file path and name
	 */
	private String mCurrentFilePath;
	private String mCurrentFileName;
	
	/**
	 * Constant value of End of File
	 */
	protected static final int EOF = -1;
	
	/**
	 * Extracted File Lists
	 */
	private ArrayList mFileList = new ArrayList();
	

	/**
	 * Constructs an object.
	 *
	 */
	public SGArchiveFileExtractor()
	{
		this.init();
	}
	
	private void init()
	{
		// set default directory name and file name of the property file
		String path = USER_HOME;
		String md = MY_DOCUMENTS; // for windows
		File home = new File( path );
		String[] fList = home.list();
		if( fList==null )
		{
			throw new Error();
		}
		// for windows
		for( int ii=0; ii<fList.length; ii++ )
		{
			if( fList[ii].endsWith(md) )
			{
				path += FILE_SEPARATOR + md;
				break;
			}
		}
		
		this.mCurrentFilePath = path;
		this.mCurrentFileName = DEFAULT_ARCHIVE_FILE_NAME + "." + ARCHIVE_FILE_EXTENSION;
	}



	/**
	 * extract an archive file.
	 */
	public int extract( final SGDrawingWindow wnd, final String destDirName, final File file )
	{
		return this.extract( wnd, destDirName, file.getPath() );
	}

	
	/*
	 * Extract a zip archive file.
	 * 
	 */
	public int extract( final SGDrawingWindow wnd, final String destDirName, final String pathName )
	{
		// extract zip archive
		int res = -1;
		try {
			res = this.extract( destDirName, pathName );
		}
		catch ( IOException  ex ) {
			return -2;
		}
		return res;
	}


	/**
	 * Create a dataset archvie file.
	 */
	public int extract( final SGDrawingWindow wnd, final String destDirName )
	{
		// show a file chooser and get selected file
		File file = this.getArchiveFileFromFileChooser( wnd );
		if( file==null )
		{
			return -1;
		}
		// extract zip archive
		int res = -1;
		try {
			res = this.extract( destDirName, file.getPath() );
		}
		catch ( IOException  ex ) {
			String mes = ex.toString();
			JOptionPane.showMessageDialog(wnd, mes);
		}
		return res;
	}

	
	private int extract( final String destDirName, final String zfileName )
		throws IOException
	{
		this.mFileList.clear();
		File destDir = new File(destDirName);
		if(!destDir.isDirectory()) {
			throw new IOException("Couldn't access dir " + destDir);
		}
		ZipFile zfile = new ZipFile(zfileName);
		Enumeration entries = zfile.entries();
		while( entries.hasMoreElements() ) {
			ZipEntry ze = (ZipEntry)entries.nextElement();
			File f = new File(destDir.getAbsolutePath() + FILE_SEPARATOR + ze.getName());
			if (ze.isDirectory()){
				if( !f.exists() && !f.mkdirs() )
					throw new IOException("Couldn't create dir " + f);
				this.mFileList.add(f);
			} else {
				BufferedInputStream is = null;
				BufferedOutputStream os = null;
				try {
					is = new BufferedInputStream( zfile.getInputStream(ze) );
					File dest = f.getParentFile();
					if( !dest.exists() && !dest.mkdirs() )
						throw new IOException("Couldn't create dir " + dest);
					os = new BufferedOutputStream( new FileOutputStream(f) );
					int b = EOF;
					while(( b = is.read()) != EOF )
						os.write(b);
					is.close();
					os.close();
					this.mFileList.add(f);
				}
				finally {
					if( is != null )
						is.close();
					if( os != null )
						is.close();
				}
			}
		}
		return 0;
	}
	
		   
	/**
	 * 
	 * @param wnd
	 * @return
	 */
	private File getArchiveFileFromFileChooser( final Component parent )
	{
		JFileChooser chooser = new SGFileChooser();

		// set the file extension filter
		SGExtensionFileFilter ff = new SGExtensionFileFilter();
		ff.setDescription( ARCHIVE_FILE_DESCRIPTION );
		ff.addExtension( ARCHIVE_FILE_EXTENSION );
		chooser.setFileFilter(ff);
		
		// set current directory
		chooser.setCurrentDirectory( new File(this.mCurrentFilePath) );

		// create the full path name
		String path = this.mCurrentFilePath + FILE_SEPARATOR + this.mCurrentFileName;
		File f = new File(path);

		// set selected file
		chooser.setSelectedFile(f);

		// show save dialog
		final int ret = chooser.showOpenDialog(parent);

		File file = null;
		if( ret == JFileChooser.APPROVE_OPTION )
		{
			file = chooser.getSelectedFile();
			this.mCurrentFilePath = file.getParent();
			this.mCurrentFileName = file.getName();
		}

		return file;
	}


	/**
	 * 
	 * @return
	 */
	public File getSelectedFile()
	{
		return new File( this.mCurrentFilePath, this.mCurrentFileName);
	}


	/**
	 * Set the file name to the file chooser.
	 * @param dir - directory name
	 * @param name - file name
	 * @return a File object
	 */
	public File setFile( final String dir, String name )
	{
		if( name!=null )
		{
			this.mCurrentFileName = name;
		}
		this.mCurrentFilePath = dir;
		
		// create the full path name
		String path = this.mCurrentFilePath + FILE_SEPARATOR + this.mCurrentFileName;
		File f = new File(path);

		return f;
	}

	public ArrayList getExtractedFileList()
	{
		return this.mFileList;
	}

	public boolean deleteExtractedFiles()
	{
		ArrayList dirlist = new ArrayList();
		for(int ii=0; ii<this.mFileList.size(); ii++){
			File f = (File)this.mFileList.get(ii);
			if(f.isDirectory())
				dirlist.add(f);
			f.delete();
		}
		for(int ii=dirlist.size()-1; ii>=0; ii--){
			File f = (File)dirlist.get(ii);
			f.delete();
		}
		this.mFileList.clear();
		return true;
	}
	
}

