package filemanager;

import com.one.Operation;
import com.vmx.Locale;
import javax.microedition.lcdui.*;
import java.util.*;

/**
 * Буфер обмена.
 */
public class Buffer
{
	/**
	 * Поток, управляющий операциями.
	 * При создании запускает операцию в отдельном потоке,
	 * создает и выводит на экран сообщение "Подождите...",
	 * ждет, пока тот поток завершится, и, наконец,
	 * показывает сообщение об ошибках или их отсутствии.
	 * Предоставляет средства для сворачивания / отмены операции.
	 */
	protected static class OperationHandler implements Runnable, CommandListener
	{
		protected Operation operation;
		protected Thread thread;
		protected GraphicAlert alert;
		
		public OperationHandler(Operation operation)
		{
			this.operation = operation;
			
			alert = new GraphicAlert(Locale.getString(this, Locale.WAIT), Locale.getString(this, Locale.WAIT_PLEASE), images.getAlertIcon(AlertType.INFO), AlertType.INFO);
			alert.setIndicator(true);
			operation.setProgressCallback(alert);
			
			//alert.addCommand(new Command(Locale.getString(this, Locale.MINIMIZE_CMD), Command.OK, 1));
			alert.addCommand(new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.CANCEL, 2));
			alert.setCommandListener(this);
			
			main.dsp.setCurrent(alert);
			
			thread = new Thread(operation, "OperationHandler/Operation");
			thread.start();
		}
		
		public void display()
		{
			main.dsp.setCurrent(alert);
		}
		
		public void run()
		{
			if(thread.isAlive())
			{
				try
				{
					thread.join();
				}
				catch(InterruptedException ie)
				{
				}
			}
			
			main.dsp.setCurrent(new alMessage(operation.getErrors()));
			Buffer.disposeOperationHandler();
			
			if(operation.getClearFlag())
			{
				Buffer.clear();
			}
		}
		
		public void commandAction(Command c, Displayable dp)
		{
			if(c.getCommandType() == Command.OK)
			{
				main.FileSelect.showWait(main.currentFile);
			}
			else
			{
				operation.stop();
			}
		}
	}

	protected static Vector buf = new Vector();
	protected static Hashtable moveit = new Hashtable();
	protected static OperationHandler handler = null;
	
	/**
	 * Добавить в буфер.
	 */
	public static void add(String file, boolean move)
	{
		add(file, move, false);
	}
	
	/**
     * Добавить в буфер.
     * Если flatten = true, то структура файлов
     * из добавляемых папок разворачивается.
     */
	protected static void add(String file, boolean move, boolean flatten)
	{
		if(flatten && filesystem.isDir(file))
		{
			Enumeration files = filesystem.listNoArchives(file, options.showHidden);
			
			while(files.hasMoreElements())
			{
				add(file + (String)files.nextElement(), move, true);
			}
		}
		else
		{
			buf.removeElement(file);
			buf.addElement(file);

			moveit.remove(file);
			moveit.put(file, new Boolean(move));
		}
	}
	
	/**
     * Удалить из буфера.
     */
	public static void remove(String file)
	{
		buf.removeElement(file);
		moveit.remove(file);
	}
	
	/**
     * Удалить из буфера.
     */
	public static void remove(int index)
	{
		remove((String)buf.elementAt(index));

//		Enumeration files = moveit.keys();
//
//		for(int i = 0; i < index && files.hasMoreElements(); i++, files.nextElement());
//
//		if(files.hasMoreElements())
//		{
//			moveit.remove(files.nextElement());
//		}
	}
	
	/**
     * Очистить буфер.
     */
	public static void clear()
	{
		buf.removeAllElements();
		moveit.clear();
	}
	
	/**
	 * Развернуть файловую структуру в буфере,
	 * чтобы там остались только файлы.
	 */
	public static void flattenBuffer()
	{
		Vector vtemp = buf;
		buf = new Vector();

		Hashtable htemp = moveit;
		moveit = new Hashtable();
		
		Enumeration files = vtemp.elements(); // htemp.keys();
		String s;
		
		while(files.hasMoreElements())
		{
			s = (String)files.nextElement();
			add(s, ((Boolean)htemp.get(s)).booleanValue(), true);
		}
	}

	/**
	 * Сортировать файлы в буфере.
	 */
	public static void sortBuffer()
	{
		Vector items = new Vector();

		Enumeration files = buf.elements();

		while(files.hasMoreElements())
		{
			items.addElement(new FileItem((String)files.nextElement(), false));
		}

		if(options.listSortBy > 0)
		{
			FileItem.sortFileList(items, options.listSortBy, options.listSortIgnoreCase, !options.listSortReverseOrder, 1, items.size() - 1);
		}

		buf.removeAllElements();

		files = items.elements();

		while(files.hasMoreElements())
		{
			buf.addElement(((FileItem)files.nextElement()).getFullName());
		}
	}
	
	/**
     * Вернуть буфер как Enumeration строк.
     */
	public static Enumeration getBuffer()
	{
		return buf.elements(); // moveit.keys();
	}
	
	/**
	 * Вернуть количество файлов в буфере.
	 */
	public static int getSize()
	{
		return buf.size(); // moveit.size();
	}
	
	/**
	 * Требуется ли переместить файл file,
	 * или просто скопировать.
	 */
	public static boolean isMoved(String file)
	{
		Boolean move = (Boolean)moveit.get(file);
		
		if(move != null)
		{
			return move.booleanValue();
		}
		
		return false;
	}
	
	/**
	 * Сотворить что-нибудь (с файлами в буфере).
	 * Если же в фоне уже выполняется какая-либо операция, она разворачивается.
	 */
	public static void startOperation(Operation operation)
	{
		if(handler != null)
		{
			throw new IllegalStateException();
		}
		
		handler = new OperationHandler(operation);
		(new Thread(handler, "Buffer/OperationHandler")).start();
	}
	
	/**
	 * Текущий OperationHandler более не нужен.
	 * Вызывается самим OperationHandler'ом.
	 * Попутно буфер очищается.
	 */
	public static void disposeOperationHandler()
	{
		if(handler != null)
		{
			handler = null;
		}
	}
	
	/**
	 * Проверить, не выполняется ли уже (в фоне) какая-либо операция.
	 */
	public static boolean isOperationRunning()
	{
		return handler != null;
	}
	
	/**
	 * Развернуть выполняемую (в фоне) операцию.
	 * Если такой операции нет, ничего не происходит.
	 * Возвращается true, если операция действительно была развернута.
	 */
	public static boolean displayCurrentOperation()
	{
		if(handler != null)
		{
			handler.display();
			return true;
		}
		else
		{
			return false;
		}
	}
}
