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

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
{

	/**
	 * Constant value of End of File
	 */
	protected static final int EOF = -1;
	
	/**
	 * Extracted File Lists
	 */
	private ArrayList mFileList = new ArrayList();
	
	
	/**
	 * A file chooser to save property files.
	 */
	private JFileChooser mFileChooser;

	/**
	 * Constructs an object.
	 *
	 */
	public SGArchiveFileExtractor()
	{
		this.init();
	}
	
	private void init()
	{
		JFileChooser chooser = new SGFileChooser();
		this.mFileChooser = chooser;

		// set the file extension filter
		SGExtensionFileFilter ff = new SGExtensionFileFilter();
		ff.setDescription( ARCHIVE_FILE_DESCRIPTION );
		ff.addExtension( ARCHIVE_FILE_EXTENSION );
		chooser.setFileFilter(ff);

		// 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;
			}
		}

		String fileName = path + FILE_SEPARATOR + DEFAULT_ARCHIVE_FILE_NAME + "." + ARCHIVE_FILE_EXTENSION;
		chooser.setSelectedFile( new File( fileName ) );
		
	}



	/**
	 * 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 SGDrawingWindow wnd )
	{
		JFileChooser chooser = this.mFileChooser;

		// show open dialog
		final int ret = chooser.showOpenDialog(wnd);

		File file = null;
		if( ret == JFileChooser.APPROVE_OPTION )
		{
			file = chooser.getSelectedFile();
		}

		return file;
	}


	/**
	 * 
	 * @return
	 */
	public File getSelectedFile()
	{
		if( this.mFileChooser==null )
		{
			return null;
		}
		else
		{
			return this.mFileChooser.getSelectedFile();
		}
	}


	/**
	 * 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 )
		{
			name = "";
		}

		// set current directory
		this.mFileChooser.setCurrentDirectory( new File(dir) );

		// create the full path name
		String path = dir + FILE_SEPARATOR + name;
		File f = new File(path);

		// set selected file
		this.mFileChooser.setSelectedFile(f);

		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;
	}
	
}

