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

import java.awt.Component;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipOutputStream;

import javax.swing.JFileChooser;

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;


/**
 * Create an archive file.
 */
public class SGArchiveFileCreator
	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;
	
	
	/**
	 * Constructs an object.
	 *
	 */
	public SGArchiveFileCreator()
	{
		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;
			}
		}
		
		mCurrentFilePath = path;
		mCurrentFileName = DEFAULT_ARCHIVE_FILE_NAME + "." + ARCHIVE_FILE_EXTENSION;		
	}



	/**
	 * Create a property file.
	 */
	public int create( final SGDrawingWindow wnd, final String rootdir, final File file )
	{
		// get file list
		ArrayList flist = getTargetFileList( rootdir );
		if (flist.size() == 0)
			return -2;
		// export to the Zip file
		ZipOutputStream zos = null;
		try
		{
			zos = new ZipOutputStream( new FileOutputStream(file) );
			return this.create( wnd, rootdir, flist, zos );
		}
		catch( Exception ex )
		{
			return -1;
		}
		finally
		{
			if( zos!=null )
			{
				try
				{
					zos.close();
				}
				catch( IOException ex )
				{
				}
			}
		}
	}


	/**
	 * Create a archive file.
	 */
	public int create( final SGDrawingWindow wnd, final String rootdir, final String pathName )
	{
		// get file list
		ArrayList flist = getTargetFileList( rootdir );
		if (flist.size() == 0)
			return -2;
		// export to the Zip file
		ZipOutputStream zos = null;
		try
		{
			zos = new ZipOutputStream( new FileOutputStream(pathName) );
			return this.create( wnd, rootdir, flist, zos );
		}
		catch( Exception ex )
		{
			return -1;
		}
		finally
		{
			if( zos!=null )
			{
				try
				{
					zos.close();
				}
				catch( IOException ex )
				{
				}
			}
		}
	}


	//
	private int create( final SGDrawingWindow wnd, final String rootdir, final ArrayList flist, final ZipOutputStream zos )
	{
		final File root = new File(rootdir);
		if(! root.isDirectory() ) return -1;
		final String rootname = root.getAbsolutePath() + File.separator;
		try {
			for(int ii=0; ii<flist.size(); ii++){
				File file = (File)flist.get(ii);
				String targetname = file.getAbsolutePath();
				if(!targetname.startsWith(rootname))
					continue; // this file not exist in rootdir
				String entryname = targetname.substring( rootname.length() );
				if( file.isFile() ){
					addTargetFile( zos, file, entryname );
				}
			}
			zos.close();
		}
		catch( FileNotFoundException ex ) {
			ex.printStackTrace();
			return -1;
		}
		catch( ZipException ex ) {
			ex.printStackTrace();
			return -1;			
		}
		catch( IOException ex ) {
			ex.printStackTrace();
			return -1;			
		}
		return OK_OPTION;
	}


	/**
	 * Create a dataset archvie file.
	 */
	public int create( final SGDrawingWindow wnd, final String rootdir )
	{
		// show a file chooser and get selected file
		File file = this.getArchiveFileFromFileChooser( wnd );
		if( file==null )
		{
			return CANCEL_OPTION;
		}

		return this.create( wnd, rootdir, file );
	}


	/**
	 * 
	 * @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(mCurrentFilePath) );

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

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

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

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

		return file;
	}


	/**
	 * 
	 * @return
	 */
	public File getSelectedFile()
	{
		return new File( mCurrentFilePath, 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 )
		{
			mCurrentFileName = name;
		}
		mCurrentFilePath = dir;
		
		// create the full path name
		String path = mCurrentFilePath + FILE_SEPARATOR + mCurrentFileName;
		File f = new File(path);

		return f;
	}

	
	/**
	 * Get the target file list
	 */
	private static ArrayList getTargetFileList(final String dirname)
	{
		ArrayList list = new ArrayList();
		File dir = new File(dirname);
		if(!dir.isDirectory())	return list;
		File [] files = dir.listFiles();
		for(int ii=0; ii<files.length; ii++){
			if (files[ii].isFile())
				list.add(files[ii]);
			else if(files[ii].isDirectory()){
				ArrayList sublist = getTargetFileList(dirname + 
						File.separator + files[ii].getName());
				list.addAll(sublist);
			}
		}
		return list;
	}
	
	/**
	 * Add the target files to archive file.
	 * @param zos : archive file output stream 
	 * @param file : target file
	 * @throws FileNotFoundException
	 * @throws ZipException
	 * @throws IOException
	 */
 	private static void addTargetFile(final ZipOutputStream zos, final File file, final String entryname )
 		throws FileNotFoundException, ZipException,IOException
	{
 		try {
 			BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ) );

 			ZipEntry target = new ZipEntry( entryname );
 			zos.putNextEntry( target );  // start writing target file

 			/* buffering is automatic, maybe, this buffer size does not effect. */
			byte buf[] = new byte[1024];
			int count;
			while( ( count = bis.read( buf, 0, 1024 ) ) != EOF ) {
				zos.write( buf, 0, count );
			}

			bis.close();
			zos.closeEntry();  // end of writing target file
 		}
 		catch( FileNotFoundException e ){
 			throw e;
 		}
 		catch( ZipException e ){
 			throw e;
 		}
 		catch( IOException e ){
 			throw e;
 		}
	}

}

