package filemanager; // переведен

import com.one.AbstractFont;
import com.one.Application;
import com.one.ErrScreen;
import com.one.ExtGraphics;
import com.one.ModuleRegistry;
import com.one.Operation;
import com.one.PlayList;
import com.one.StringPattern;
import com.one.file.Connector;
import com.one.file.TransparentConnector;
import com.one.vector.AuxMath;
import com.vmx.AuxClass;
import com.vmx.Locale;
import com.vmx.gkcCanvas;
import com.vmx.keyConfig;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;
import modules.text.cvsTextView;

public class cvsFileSelect extends gkcCanvas implements Runnable, CommandListener
{
//	protected static final FileItem PARENT_DIR = new FileItem("..", images.getIcon(images.iUp));
//	protected static final FileItem FAVOURITES = new FileItem(Locale.getString(this, Locale.FAVOURITES), images.getIcon(
	
	/** Данные списка */
	private String title;
	private Vector items;

	/** Фильтры */
	private StringPattern tmpfilter;
	
	/** Вспомогательные данные */
	private int scrStart, scrSel, scrLen;
	private int w, h, allh, fileH, header, footer;
	private int skw, firew; // место, отводимое под надписи над софт - кнопками и джойстиком
	private boolean fsmode; // полноэкранный режим
	private AbstractFont mf, mfro, mfhn, mfrh, fd;
	//private FontWidthCache fcd; // кэши ширины шрифтов %)
	private int fdh;
	private boolean lskp = false, rskp = false, firep = false; // для мигания
	//boolean markMode = false;
	private int markCount = 0;
	private int keyHeld = 0;
	private boolean keyReleaseAllowed = false;
	private boolean hotKeyMode = false;
	private boolean isshown;
	private List modlist;
	private List favmodlist;
	private List oplist;
	private int fireIcon;
	
	private int ofnw, ofnx, ofnstep, ofndelay; // прокрутка длинных имен
	private int OFN_DEF_DELAY;
	private Thread t;
	protected LineEffect lfx;

	protected final Object waiter = new Object();

	private Image background, cursor;
	private Image offscreen;
	private ExtGraphics offgraphics;
	private boolean repaints;
	
	/**
	 * Запуск рескана каталога через cvsWait
	 */
	public void showWait()
	{
		cvsWait.start(this);
	}
	
	/**
	 * Запуск рескана каталога через cvsWait, после рескана надо выбрать
	 * файл selectAfter
	 */
	public void showWait(String selectAfter)
	{
		cvsWait.start(this, selectAfter);
	}
	
	/**
	 * Показ буфера обмена
	 */
	public void showBuffer()
	{
		if(!"buf:/".equals(main.currentPath))
		{
			main.oldPath = main.currentPath;
			main.oldFile = ((FileItem)items.elementAt(scrSel)).getName();
		}
		
		main.currentPath = "buf:/";
		showWait();
	}

	private Command cmdOpen = new Command(Locale.getString(this, Locale.OPEN_CMD), Command.ITEM, 1);
	private Command cmdAssign = new Command(Locale.getString(this, Locale.ASSIGN_CMD), Command.OK, 2);
	private Command cmdReset = new Command(Locale.getString(this, Locale.RESET_CMD), Command.OK, 3);
	private Command cmdFavModules = new Command(Locale.getString(this, Locale.MENU_FAV_MODULES), Command.OK, 4);
	private Command cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 5);
	private Command cmdCancel = new Command(Locale.getString(this, Locale.CANCEL_CMD), Command.BACK, 5);
	
	/**
	 * Конструктор
	 */
	public cvsFileSelect()
	{
		setFullScreenMode(true);

		int fsize = options.largeFontInList ? AbstractFont.SIZE_MEDIUM : AbstractFont.SIZE_SMALL;
		
		mf = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_PLAIN, fsize);
		mfro = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_BOLD, fsize);
		mfhn = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_ITALIC, fsize);
		mfrh = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_BOLD | AbstractFont.STYLE_ITALIC, fsize);

		fd = AbstractFont.getDefaultFont();
		//fcd = FontWidthCache.getCache(fd);
		fdh = fd.getHeight();
		
		title = "";
		items = new Vector();

		tmpfilter = new StringPattern("~*.tmp", true);

		fsmode = false;
		repaints = true;
		updateLayout();

		modlist = new List(Locale.getString(this, Locale.MODULES_CMD), Choice.IMPLICIT);
		favmodlist = new List(Locale.getString(this, Locale.MENU_FAV_MODULES), Choice.IMPLICIT);
		oplist = new List(Locale.getString(this, Locale.MENU_OPERATIONS), Choice.IMPLICIT);

		updateModuleList();

		modlist.addCommand(cmdOpen);

		modlist.setSelectCommand(cmdOpen);
		modlist.removeCommand(List.SELECT_COMMAND);

		modlist.addCommand(cmdAssign);
		modlist.addCommand(cmdReset);
		modlist.addCommand(cmdFavModules);
		modlist.addCommand(cmdCancel);
		
		modlist.setCommandListener(this);

		favmodlist.addCommand(cmdAssign);

		favmodlist.setSelectCommand(cmdAssign);
		favmodlist.removeCommand(List.SELECT_COMMAND);

		favmodlist.addCommand(cmdReset);
		favmodlist.addCommand(cmdBack);

		favmodlist.setCommandListener(this);

		oplist.addCommand(cmdCancel);
		oplist.setCommandListener(this);

		findFireIcon();
	}

	public void updateLayout()
	{
		setFullScreenMode(true);
		
		w = getWidth();
		h = allh = getHeight();

		fileH = Math.max(images.iconHeight, mf.getHeight());

		offscreen = Image.createImage(w, allh);
		offgraphics = new ExtGraphics(offscreen.getGraphics());

		initFSMode(fsmode);

		lfx = new LineEffect(1, 1, w - 2, allh - 2);
	}

//	public void updateGradients()
//	{
//		Graphics g;
//
//		if(options.ditherGradients)
//		{
//			if(!options.alphaGradients || (images.isColorOpaque(ColorScheme.colors[ColorScheme.back1]) && images.isColorOpaque(ColorScheme.colors[ColorScheme.back2])))
//			{
//				background = Image.createImage(w, allh);
//				g = background.getGraphics();
//				images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, w, allh, true, false);
//			}
//			else
//			{
//				background = null;
//			}
//
//			if(!options.alphaGradients || (images.isColorOpaque(ColorScheme.colors[ColorScheme.selback1]) && images.isColorOpaque(ColorScheme.colors[ColorScheme.selback2])))
//			{
//				cursor = Image.createImage(w - 3, fileH);
//				g = cursor.getGraphics();
//				images.drawHGradient(g, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 0, 0, w - 3, fileH, true, false);
//			}
//			else
//			{
//				cursor = null;
//			}
//		}
//		else
//		{
//			background = null;
//			cursor = null;
//		}
//	}

	public void updateModuleList()
	{
		modlist.deleteAll();

		Enumeration modules = ModuleRegistry.listModules();
		String module;

		while(modules.hasMoreElements())
		{
			module = (String)modules.nextElement();
			modlist.append(ModuleRegistry.getModuleName(module), ModuleRegistry.getIcon(module));
		}

		oplist.deleteAll();

		modules = ModuleRegistry.listOperations();

		while(modules.hasMoreElements())
		{
			module = (String)modules.nextElement();
			oplist.append(ModuleRegistry.getModuleName(module), ModuleRegistry.getIcon(module));
		}
	}
	
	/**
	 * Получить все элементы списка
	 */
	public Enumeration elements()
	{
		return items.elements();
	}
	
	/**
	 * Получить один элемент из списка
	 */
	public FileItem getFileItem(int index)
	{
		return (FileItem)items.elementAt(index);
	}
	
	public int getSelectedIndex()
	{
		return scrSel;
	}
	
	public int getMarkCount()
	{
		return markCount;
	}
	
	/**
	 * Функция обновления списка - по возможности после обновления
	 * выберется файл/папка/диск selectAfter
	 */
	public void list(String selectAfter)
	{
		repaints = false;
		markCount = -1;
		
		if(main.currentPath.length() == 0)
		{
			listDrives(selectAfter);
		}
		else if(main.currentPath.equals("fav:/"))
		{
			listFavorites(selectAfter);
		}
		else if(main.currentPath.equals("null:/"))
		{
			listBucket();
		}
		else if(main.currentPath.equals("buf:/"))
		{
			listBuffer();
		}
		else
		{
			int index;
			
			while(!listFiles(selectAfter))
			{
				main.currentPath = main.currentPath.substring(0, main.currentPath.length() - 1);
				index = main.currentPath.lastIndexOf('/');
				
				if(index >= 0)
				{
					main.currentPath = main.currentPath.substring(0, index);
				}
				else
				{
					main.currentPath = "";
				}
				
				if(main.currentPath.length() > 0)
				{
					main.currentPath += '/';
				}
				else
				{
					listDrives(selectAfter);
					break;
				}
			}
		}

		repaints = true;
		
		lskp = rskp = firep = false;
		select(scrSel);

		synchronized(waiter)
		{
			waiter.notifyAll();
		}
	}
	
	/** Удаление из списка файла #x */
	public void delete(int x)
	{
		if(x < 1 || x >= items.size())
		{
			return;
		}
		
		items.removeElementAt(x);
		
		select(scrSel);
	}
	
	/** 
	 * Функция обновления списка дисков
	 */
	public void listDrives(String selectAfter)
	{
		title = Locale.getString(this, Locale.SELECT_DRIVE);
		
		items.removeAllElements();
		
		scrStart = 0;
		scrSel = 0;
		
		Enumeration roots = filesystem.listRoots();
		String s;
		
		if(roots != null)
		{
			while(roots.hasMoreElements())
			{
				s = (String)roots.nextElement();
				items.addElement(new FileItem(s, images.getIcon(images.iDisk)));
				
				if(s.equals(selectAfter))
				{
					scrSel = items.size() - 1;
				}
			}
		}
		
		if(false) // Buffer.getSize() > 0)
		{
			items.addElement(new FileItem(Locale.getString(this, Locale.BIT_BUCKET), images.getIcon(images.iFavorites)));

			if("null:/".equals(selectAfter) || Locale.getString(this, Locale.BIT_BUCKET).equals(selectAfter))
			{
				scrSel = items.size() - 1;
			}
		}
		else
		{
			items.addElement(new FileItem(Locale.getString(this, Locale.FAVOURITE), images.getIcon(images.iFavorites)));

			if("fav:/".equals(selectAfter) || Locale.getString(this, Locale.FAVOURITE).equals(selectAfter))
			{
				scrSel = items.size() - 1;
			}
		}
	}
	
	/** 
	 * Функция обновления списка файлов
	 */
	public boolean listFiles(String selectAfter)
	{
		Enumeration files = filesystem.list(main.currentPath, options.showHidden);
		String filename;
		
		if(files == null)
		{
			return false;
		}
		
		title = fd.getLastPartOfString(main.currentPath, "..", w - images.iconWidth - 6 - fd.stringWidth(AuxClass.getCurrentTime()), true); // Integer.toString(panels.length)) - 3);
		
		items.removeAllElements();
		
		items.addElement(new FileItem("..", images.getIcon(images.iUp)));

		if(main.currentPath.equals(Connector.getTempFileDir()))
		{
			while(files.hasMoreElements())
			{
				items.addElement(new FileItem(main.currentPath, (String)files.nextElement(), false));
			}
		}
		else
		{
			while(files.hasMoreElements())
			{
				filename = (String)files.nextElement();

				if(!(tmpfilter.matchesWith(filename) && Connector.isTempFileUsed(main.currentPath + filename)))
				{
					items.addElement(new FileItem(main.currentPath, filename, false));
				}
			}
		}

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

		scrStart = 0;
		scrSel = 1;

		if(selectAfter != null && selectAfter.length() > 0)
		{
			for(int i = 1; i < items.size(); i++)
			{
				if(((FileItem)items.elementAt(i)).getDisplayName().equals(selectAfter))
				{
					scrSel = i;
					break;
				}
			}
		}
		
		return true;
	}
	
	/** 
	 * Функция обновления списка "Избранное"
	 */
	public void listFavorites(String selectAfter)
	{
		Enumeration files = options.getFavorites();
		
		title = Locale.getString(this, Locale.FAVOURITE);
		
		items.removeAllElements();
		
		scrStart = 0;
		scrSel = 1;
		
		items.addElement(new FileItem("..", images.getIcon(images.iUp)));
		
		while(files.hasMoreElements())
		{
			items.addElement(new FileItem((String)files.nextElement(), options.fullNamesInFav));
		}
		
		if(options.listSortBy > 0)
		{
			FileItem.sortFileList(items, options.listSortBy, options.listSortIgnoreCase, !options.listSortReverseOrder, 1, items.size() - 1);
		}
		
		if(selectAfter != null && selectAfter.length() > 0)
		{
			for(int i = 1; i < items.size(); i++)
			{
				if(((FileItem)items.elementAt(i)).getDisplayName().equals(selectAfter))
				{
					scrSel = i;
					break;
				}
			}
		}
	}

	public void listBucket()
	{
		title = Locale.getString(this, Locale.BIT_BUCKET);

		items.removeAllElements();

		scrStart = 0;
		scrSel = 1;

		items.addElement(new FileItem("..", images.getIcon(images.iUp)));
	}
	
	public void listBuffer()
	{
		Enumeration files = Buffer.getBuffer();
		
		title = Locale.getString(this, Locale.BUFFER);
		
		items.removeAllElements();
		
		scrStart = 0;
		scrSel = 1;
		
		items.addElement(new FileItem("..", images.getIcon(images.iUp)));
		
		while(files.hasMoreElements())
		{
			items.addElement(new FileItem((String)files.nextElement(), options.fullNamesInBuf));
		}
		
		/*
		if(options.listSortBy > 0)
		{
			FileItem.sortFileList(items, options.listSortBy, true, 1, items.size() - 1);
		}
		*/
	}
	
	/**
	 * Обновить тип файла #i
	 */
	public void updateFileType(int i)
	{
		if(i < 1 || i >= items.size() || main.currentPath.length() == 0)
		{
			return;
		}
		
		((FileItem)items.elementAt(i)).updateFileType();
	}
	
	/**
	 * Обновить имя (в списке) файла #i.
	 * Тип здесь обновляется автоматически.
	 */
	public void updateFileName(String newname, int i)
	{
		if(i < 1 || i >= items.size() || main.currentPath.length() == 0)
		{
			return;
		}

		boolean flag = false;

		if("fav:/".equals(main.currentPath))
		{
			flag = options.fullNamesInFav;
		}
		else if("buf:/".equals(main.currentPath))
		{
			flag = options.fullNamesInBuf;
		}

		items.setElementAt(new FileItem(main.currentPath, newname, flag), i);
		main.currentFile = newname;
		select(scrSel);
	}
	
	/**
	 * Инициализация режима выделения
	 */
	public void startMarkMode()
	{
		for(Enumeration e = items.elements(); e.hasMoreElements(); ((FileItem)e.nextElement()).setMarked(false));
		markCount = 0;
	}
	
	/**
	 * Пометить выбранный
	 */
	public void markSelected()
	{
		if(main.currentPath.length() > 0)
		{
			if(markCount < 0)
			{
				startMarkMode();
			}
			
			if(scrSel > 0)
			{
				FileItem item = (FileItem)items.elementAt(scrSel);
				
				if(item.isMarked())
				{
					item.setMarked(false);
					markCount--;
				}
				else
				{
					item.setMarked(true);
					markCount++;
				}
			}
			
			// когда снимаем выделение с последнего файла,
			// выключаем режим выделения
			if(markCount == 0)
			{
				markCount = -1;
			}
			else
			{
				select(scrSel + 1);
			}
			
			repaint();
		}
	}
	
	/**
	 * Пометить все
	 */
	public void markAll()
	{
		if(main.currentPath.length() > 0)
		{
			if(markCount < 0)
			{
				startMarkMode();
			}
			
			for(Enumeration e = items.elements(); e.hasMoreElements(); ((FileItem)e.nextElement()).setMarked(true));
			markCount = items.size() - 1;
			
			repaint();
		}
	}
	
	/**
	 * Сбросить все отметки.
	 * При этом автоматически выключается режим выделения.
	 */
	public void demarkAll()
	{
		if(markCount >= 0)
		{
			for(Enumeration e = items.elements(); e.hasMoreElements(); ((FileItem)e.nextElement()).setMarked(false));
			markCount = -1;
			
			repaint();
		}
	}
	
	/**
	 * Перемещение по дереву каталогов вверх, переключение на меню
	 * выбора дисков или Избранное, или выход из программы наффик
	 */
	public void upDir()
	{
		if(main.currentPath.length() == 0)
		{
			if(options.exitFromDriveList)
			{
				main.destroyApp();
			}
			
			return;
		}
		
		int sindex, pindex;
		String str = null;
		
		if(main.currentPath.equals("fav:/"))
		{
			str = "fav:/";
			main.currentPath = "";
		}
		else if(main.currentPath.equals("buf:/"))
		{
			str = main.oldFile;
			main.currentPath = main.oldPath;
		}
		else
		{
			str = main.currentPath.substring(0, main.currentPath.length() - 1);
			sindex = str.lastIndexOf('/') + 1;

			if(sindex > 0)
			{
				str = main.currentPath.substring(sindex);
				pindex = str.lastIndexOf('.') + 1;

				if(pindex > 0 && ModuleRegistry.getAction(str.substring(pindex, str.length() - 1)) == ModuleRegistry.ACTION_EXPLORE)
				{
					str = str.substring(0, str.length() - 1);
				}

				main.currentPath = main.currentPath.substring(0, sindex);
			}
			else
			{
				str = main.currentPath;
				main.currentPath = "";
			}
		}
		
		showWait(str);
	}
	
	/**
	 * Выбор текущего файла из списка.
	 * Просмотр файла запускается в текущей панели.
	 */
	public void selectFile()
	{
		prevpath = main.currentPath;

		if(main.currentFile.equals(".."))
		{
			// если выбрано .. или Назад переходим по папке вверх
			upDir();
			return;
		}

		FileItem item = (FileItem)items.elementAt(scrSel);

		main.currentPath = item.getPath();
		main.currentFile = item.getName();
		
		if(main.currentPath.length() == 0)
		{
			if(main.currentFile.equals(Locale.getString(this, Locale.FAVOURITE)))
			{
				main.currentFile = "fav:/";
			}
			else if(main.currentFile.equals(Locale.getString(this, Locale.BIT_BUCKET)))
			{
				main.currentFile = "null:/";
			}
			else
			{
				int index = main.currentFile.lastIndexOf('/') + 1;
				
				if(index > 0)
				{
					main.currentFile = main.currentFile.substring(0, index);
				}
				else
				{
					main.currentFile += '/';
				}
			}
		}

		if(main.currentFile.charAt(main.currentFile.length() - 1) == '/')
		{
			// если выбранный файл директория то входим в нее
			main.currentPath = main.currentPath + main.currentFile;
			showWait();
		}
		else
		{
			// А что, вообще-то, с такими файлами делают?
			int action = ModuleRegistry.getAction(AuxClass.getFileExtension(main.currentFile));

			if(action == ModuleRegistry.ACTION_EXPLORE)
			{
				// Открываем файл как папку (архив)
				main.currentPath = main.currentPath + main.currentFile + "/";
				showWait();
			}
			else
			{
				// Открываем файл как именно файл
				executeFile(main.currentPath + main.currentFile);
			}
		}
	}

	/**
	 * Запустить посмотр файла filename.
	 * При этом формируется список из файлов, для которых используется тот же модуль.
	 */
	public void executeFile(String filename)
	{
		PlayList playlist = new PlayList(filesystem.listFilesOfType(filename, null, options.showHidden));

		playlist.selectElement(filename);
		playlist.waitForElementFound();

		executeFile(playlist, null, main.manager.currentPanel());
	}

	/**
	 * Запустить просмотр текущего файла из списка filelist, используя модуль module.
	 * Если вместо модуля передать null, модуль определяется автоматически по расширению.
	 */
	public void executeFile(PlayList filelist, String module, int panel)
	{
		String filename = filelist.getCurrentElement();
		String ext = AuxClass.getFileExtension(filename);

		if(panel == main.manager.currentPanel())
		{
			select(filename);
		}

		// А что, вообще-то, с такими файлами делают?
		int action = ModuleRegistry.getAction(module != null ? module : ext);

		if(action == ModuleRegistry.ACTION_OPEN)
		{
			if(module == null)
			{
				module = ModuleRegistry.getModule(ext);
			}

			try
			{
				((Application)ModuleRegistry.getModuleInstance(module)).openFile(filename, filelist);
			}
			catch(Exception e)
			{
				ErrScreen.showErrMsg(122, e);
			}

			main.manager.setPanelName(panel, ModuleRegistry.getModuleName(module));
		}
		else if(options.openNotSupported && AuxClass.classExists(main.TEXT_VIEW_CLASS))
		{
			cvsTextView.getInstance().openFile(filename);
		}
		else
		{
			//main.showMessage(Locale.getString(this, Locale.ERROR), Locale.getString(this, Locale.FORMAT_NOT_SUPP), AlertType.WARNING, 3000, this);
			showModuleList();
		}
	}

	public void commandAction(Command c, Displayable dp)
	{
		if(dp == modlist)
		{
			if(c == cmdFavModules)
			{
				showFavModList();
			}
			else
			{
				main.dsp.setCurrent(this);

				if(c == cmdOpen || c == List.SELECT_COMMAND)
				{
					String module = ModuleRegistry.getModule(modlist.getSelectedIndex());

					if(ModuleRegistry.getAction(module) == ModuleRegistry.ACTION_OPEN)
					{
						executeFile(new PlayList(main.currentPath + main.currentFile), module, main.manager.currentPanel());
					}
					else
					{
						associateAndSelect(module, false);
					}
				}
				else if(c == cmdAssign)
				{
					associateAndSelect(ModuleRegistry.getModule(modlist.getSelectedIndex()), true);
				}
				else if(c == cmdReset)
				{
					associateAndSelect(null, true);
				}
			}
		}
		else if(dp == oplist)
		{
			main.dsp.setCurrent(this);

			if(c == List.SELECT_COMMAND)
			{
				((Operation)ModuleRegistry.getModuleInstance(ModuleRegistry.getOperation(oplist.getSelectedIndex()))).start();
			}
		}
		else if(dp == favmodlist)
		{
			int index = favmodlist.getSelectedIndex();

			if(c == cmdAssign || c == List.SELECT_COMMAND)
			{
				options.favmodules[index] = ModuleRegistry.getModule(modlist.getSelectedIndex());
				favmodlist.set(index, ModuleRegistry.getModuleName(options.favmodules[index]), ModuleRegistry.getIcon(options.favmodules[index]));
			}
			else if(c == cmdReset)
			{
				options.favmodules[index] = "";
				favmodlist.set(index, Locale.getString(this, Locale.FAV_MOD_NUMS + index), null);
			}
			else
			{
				main.dsp.setCurrent(modlist);
			}
		}
	}

	/**
	 * Связать файл, заданный main.currentPath и main.currentFile
	 * с модулем module и выбрать его через selectFile().
	 */
	public void associateAndSelect(String module, boolean all)
	{
		int index = main.currentFile.lastIndexOf('.') + 1;
		String ext;

		if(index > 0)
		{
			ext = main.currentFile.substring(index);
		}
		else
		{
			ext = main.currentPath + main.currentFile;
		}

		String prev = ModuleRegistry.associate(ext, module, all);

		if(all)
		{
			Enumeration files = items.elements();

			while(files.hasMoreElements())
			{
				((FileItem)files.nextElement()).invalidate();
			}
		}

		try
		{
			TransparentConnector.closeContainer(main.currentPath + main.currentFile);
		}
		catch(IOException x)
		{
			x.printStackTrace();
		}

		if(module != null)
		{
			synchronized(waiter)
			{
				selectFile();

				if(!all)
				{
					try
					{
						waiter.wait();
					}
					catch(InterruptedException ie)
					{
					}

					ModuleRegistry.associate(ext, prev, all);
				}
			}
		}
	}

	public void showModuleList()
	{
		main.dsp.setCurrent(modlist);
	}

	public void showOperationList()
	{
		main.dsp.setCurrent(oplist);
	}

	public void showFavModList()
	{
		favmodlist.deleteAll();
		String module;

		for(int i = 0; i < options.favmodules.length; i++)
		{
			module = options.favmodules[i];

			if(module.length() > 0)
			{
				favmodlist.append(ModuleRegistry.getModuleName(module), ModuleRegistry.getIcon(module));
			}
			else
			{
				favmodlist.append(Locale.getString(this, Locale.FAV_MOD_NUMS + i), null);
			}
		}

		main.dsp.setCurrent(favmodlist);
	}
	
	/**
     * Показать меню
     */
	public void showMenu()
	{
		setMenuType(main.menu);

		main.menu.parent = this;
		main.dsp.setCurrent(main.menu);
	}

	public void setMenuType(cvsMenu menu)
	{
//		int menuType;
//
//		if(main.currentPath.length() > 0)
//		{
//			if(main.currentPath.equals("fav:/"))
//			{
//				menuType = cvsMenu.MENU_FAVORITES_SELECTED;
//			}
//			else if(main.currentPath.equals("null:/"))
//			{
//				menuType = cvsMenu.MENU_BUCKET_SELECTED;
//			}
//			else if(main.currentPath.equals("buf:/"))
//			{
//				menuType = cvsMenu.MENU_BUFFER_SELECTED;
//			}
//			else if(TransparentConnector.isPathInContainer(main.currentPath))
//			{
//				menuType = cvsMenu.MENU_INSIDE_ARCHIVE;
//			}
//			else
//			{
//				if("..".equals(main.currentFile))
//				{
//					menuType = cvsMenu.MENU_DOTDOT_SELECTED;
//				}
//				else
//				{
//					if(filesystem.isDir(main.currentPath + main.currentFile))
//					{
//						menuType = cvsMenu.MENU_FOLDER_SELECTED;
//					}
//					else
//					{
//						menuType = cvsMenu.MENU_FILE_SELECTED;
//					}
//				}
//			}
//		}
//		else // if (!Locale.getString(this, Locale.FAVOURITE).equals (main.currentFile)) // выбран диск
//		{
//			menuType = cvsMenu.MENU_DISK_SELECTED;
//		}
//		//else menuType = cvsMenu.MENU_FAVORITES_SELECTED;

		menu.setType(cvsMenu.MENU_GENERIC);
	}

	/**
	 * Выбрать элемент, заданный полным именем.
	 */
	public void select(String filename)
	{
		FileItem item;

		for(int i = 0; i < items.size(); i++)
		{
			item = (FileItem)items.elementAt(i);

			if(item.getFullName().equals(filename))
			{
				select(i);
				break;
			}
		}
	}
	
	/**
     * Выбрать файл #index
     */
	public void select(int index)
	{
		scrSel = index;
		
		if(scrSel >= items.size())
		{
			scrSel = items.size() - 1;
		}
		
		scrStart = scrSel - scrLen / 2;
		
		if(scrStart + scrLen >= items.size())
		{
			scrStart = items.size() - scrLen;
		}
		
		if(scrStart < 0)
		{
			scrStart = 0;
		}
		
		FileItem item = (FileItem)items.elementAt(scrSel);
		main.currentFile = item.getName();
		
		if(item.isReadOnly())
		{
			if(item.isHidden())
			{
				ofnw = mfrh.stringWidth(item.getDisplayName());
			}
			else
			{
				ofnw = mfro.stringWidth(item.getDisplayName());
			}
		}
		else
		{
			if(item.isHidden())
			{
				ofnw = mfhn.stringWidth(item.getDisplayName());
			}
			else
			{
				ofnw = mf.stringWidth(item.getDisplayName());
			}
		}
		
		ofnx = images.iconWidth + 2;
		ofndelay = OFN_DEF_DELAY;
		
		if(ofnw > w - images.iconWidth - 5)
		{
			//ofnstep = -(ofnw / main.currentFile.length());
			ofnstep = -1;
		}
		else
		{
			ofnstep = 0;
		}
		
		repaint();
	}

	public void changeFSMode()
	{
		initFSMode(!fsmode);
	}
	
	/**
     * Функция переключения между собственными полноэкранным
     * и неполноэкранным режимами
     */
	public void initFSMode(boolean mode)
	{
		fsmode = mode;
		
		if(fsmode)
		{
			header = footer = 0;
		}
		else
		{
			header = Math.max(images.iconHeight + 2, fdh + 2);
			footer = header;
		}
		
		h = allh - header - footer;
		
		scrLen = h / fileH;
		
		if(items.size() > 0)
		{
			select(scrSel);
		}
	}

	public void findFireIcon()
	{
		fireIcon = images.iSelect;

		int action = keyConfig.getAction(KEY_FIRE);
		boolean notfound = true;

		for(int i = 0; i < cvsMenu.menu.length && notfound; i++)
		{
			for(int j = 1; j < cvsMenu.menu[i].length && notfound; j += 2)
			{
				if(cvsMenu.menu[i][j] == action)
				{
					fireIcon = cvsMenu.menu[i][j + 1];
					notfound = false;
				}
			}
		}
	}
	
	/**
     * Функция отрисовки
     */
	public void paint(ExtGraphics g)
	{
		if(repaints)
		{
			AbstractFont f;
			int i, fh, p, icon;

			offgraphics.setFont(fd);
			offgraphics.setClip(0, 0, w, allh);

			if(background != null)
			{
				offgraphics.drawImage(background, 0, 0, Graphics.LEFT | Graphics.TOP);
			}
			else
			{
				images.drawVGradient(offgraphics, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, w, allh, options.ditherGradients);
			}

			boolean inBuffer = "buf:/".equals(main.currentPath);

			if(!fsmode) // рисуем интерфейс
			{
				offgraphics.setColor(ColorScheme.colors[ColorScheme.mdborder]);
				offgraphics.drawLine(0, header - 1, w, header - 1);
				offgraphics.drawLine(0, allh - footer, w, allh - footer);

				icon = images.iFolder;

				if(title.endsWith(":/"))
				{
					icon = images.iDisk;
				}
				else if(title.equals(Locale.getString(this, Locale.SELECT_DRIVE)))
				{
					icon = images.iSieFM;
				}
				else if(title.equals(Locale.getString(this, Locale.FAVOURITE)))
				{
					icon = images.iFavorites;
				}
				else if(title.equals(Locale.getString(this, Locale.BUFFER)))
				{
					icon = images.iClipboard;
				}

				images.drawIcon(offgraphics, icon, 1, (header - images.iconHeight) / 2);

				// заглавие
				offgraphics.setColor(ColorScheme.colors[ColorScheme.fore]);
				offgraphics.drawString(title, images.iconWidth + 3, (header - fdh) / 2, Graphics.LEFT | Graphics.TOP);

				offgraphics.setColor(ColorScheme.colors[ColorScheme.altfore]);

				if(options.alterClockPos)
				{
					firew = fd.stringWidth(AuxClass.getCurrentTime()) * 4 / 3;
					skw = (w - firew) / 2;
				}
				else
				{
					firew = images.iconWidth * 3 / 2;
					skw = (w - firew) / 2;

					if(options.clockMode)
					{
						// время
						offgraphics.drawString(AuxClass.getCurrentTime(), w - 1, (header - fdh) / 2, Graphics.RIGHT | Graphics.TOP);
					}
					else
					{
						// номер панели
						offgraphics.drawString("-" + Integer.toString(main.manager.currentPanel() + 1) + "-", w - 1, (header - fdh) / 2, Graphics.RIGHT | Graphics.TOP);
					}
				}

				// подписи к LSK, RSK и джойстику
				int lskstr = keyConfig.getAction(KEY_LSK),
					rskstr = keyConfig.getAction(KEY_RSK);

				if(options.exitFromDriveList && main.currentPath.length() == 0)
				{
					if(lskstr == Locale.BACK_CMD)
					{
						lskstr = Locale.EXIT_CMD;
					}

					if(rskstr == Locale.BACK_CMD)
					{
						rskstr = Locale.EXIT_CMD;
					}
				}

				if(lskp)
				{
					images.drawHGradient(offgraphics, ColorScheme.colors[ColorScheme.skselback1], ColorScheme.colors[ColorScheme.skselback2], 0, allh - footer + 1, skw, footer - 1, options.ditherGradients);
					offgraphics.setColor(ColorScheme.colors[ColorScheme.skselfore]);
				}
				else
				{
					offgraphics.setColor(ColorScheme.colors[ColorScheme.skfore]);
				}

				offgraphics.setClip(0, allh - footer + 1, skw, footer - 1);

				if(lskstr >= 0)
				{
					offgraphics.drawString(Locale.getString(this, lskstr), skw / 2, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP);
				}

				offgraphics.setClip(0, 0, w, allh);

				if(rskp)
				{
					images.drawHGradient(offgraphics, ColorScheme.colors[ColorScheme.skselback2], ColorScheme.colors[ColorScheme.skselback1], w - skw, allh - footer + 1, skw, footer - 1, options.ditherGradients);
					offgraphics.setColor(ColorScheme.colors[ColorScheme.skselfore]);
				}
				else
				{
					offgraphics.setColor(ColorScheme.colors[ColorScheme.skfore]);
				}

				offgraphics.setClip(w - skw, allh - footer + 1, skw, footer - 1);

				if(rskstr >= 0)
				{
					offgraphics.drawString(Locale.getString(this, rskstr), w - skw / 2 - 1, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP);
				}

				offgraphics.setClip(0, 0, w, allh);

				if(firep)
				{
					offgraphics.setColor(ColorScheme.colors[ColorScheme.skselback2]);
					offgraphics.fillRect((w - firew) / 2, allh - footer + 1, firew, footer - 1);
				}

				if(options.alterClockPos)
				{
					offgraphics.setColor(firep ? ColorScheme.colors[ColorScheme.selfore] : ColorScheme.colors[ColorScheme.altfore]);

					if(options.clockMode)
					{
						// время
						offgraphics.drawString(AuxClass.getCurrentTime(), w / 2, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP);
					}
					else
					{
						// номер панели
						offgraphics.drawString("-" + Integer.toString(main.manager.currentPanel() + 1) + "-", w / 2, allh - footer + (footer - fdh) / 2, Graphics.HCENTER | Graphics.TOP);
					}
				}
				else
				{
					images.drawIcon(offgraphics, fireIcon, (w - images.iconWidth) / 2, allh - footer + (footer - images.iconHeight) / 2);
				}
			}

			offgraphics.translate(0, header);

			FileItem item;

			for(i = scrStart, p = 0; i < items.size() && i < scrStart + scrLen + 1; i++, p++)
			{
				item = (FileItem)items.elementAt(i);

				offgraphics.setClip(0, 0, w - 3, h);

				if(i == scrSel)
				{
					if(options.frameCursor)
					{
						offgraphics.setColor(ColorScheme.colors[ColorScheme.selback1]);
						offgraphics.drawRect(0, p * fileH, w - 4, fileH);
					}
					else if(cursor != null)
					{
						offgraphics.drawImage(cursor, 0, p * fileH, Graphics.LEFT | Graphics.TOP);
					}
					else
					{
						images.drawHGradient(offgraphics, ColorScheme.colors[ColorScheme.selback1], ColorScheme.colors[ColorScheme.selback2], 0, p * fileH, w - 3, fileH, options.ditherGradients);
					}

					offgraphics.setColor(ColorScheme.colors[ColorScheme.selfore]);
				}
				else
				{
					if(markCount >= 0 && item.isMarked())
					{
						offgraphics.setColor(ColorScheme.colors[ColorScheme.hlfore]);
					}
					else
					{
						offgraphics.setColor(ColorScheme.colors[ColorScheme.fore]);
					}
				}

				if(markCount >= 0 && item.isMarked())
				{
					images.drawIcon(offgraphics, images.iMark, 1, p * fileH);
				}
				else if(item.getIcon() != null)
				{
					offgraphics.drawImage(item.getIcon(), 1 + (images.iconWidth - item.getIcon().getWidth()) / 2, p * fileH + (fileH - item.getIcon().getHeight()) / 2, Graphics.LEFT | Graphics.TOP);
				}

				if(inBuffer && i > 0 && Buffer.isMoved(item.getFullName()))
				{
					images.drawIcon(offgraphics, images.iMoveIt, 1, p * fileH);
				}

				if(item.isReadOnly())
				{
					if(item.isHidden())
					{
						fh = mfrh.getHeight();
						offgraphics.setFont(mfrh);
					}
					else
					{
						fh = mfro.getHeight();
						offgraphics.setFont(mfro);
					}
				}
				else
				{
					if(item.isHidden())
					{
						fh = mfhn.getHeight();
						offgraphics.setFont(mfhn);
					}
					else
					{
						fh = mf.getHeight();
						offgraphics.setFont(mf);
					}
				}

				offgraphics.setClip(images.iconWidth + 2, 0, w - images.iconWidth - 5, h);

				if(i == scrSel)
				{
					offgraphics.drawString(item.getDisplayName(), ofnx, p * fileH + fileH / 2 - fh / 2, Graphics.LEFT | Graphics.TOP);
				}
				else
				{
					offgraphics.drawString(item.getDisplayName(), images.iconWidth + 2, p * fileH + fileH / 2 - fh / 2, Graphics.LEFT | Graphics.TOP);
				}
			}

			offgraphics.setClip(w - 3, 0, 3, h);
			offgraphics.setColor(ColorScheme.colors[ColorScheme.sbline]);

			offgraphics.drawLine(w - 2, 0, w - 2, h);

			int sbstart, sbsize;

			if(items.size() > 0)
			{
				sbstart = h * scrStart / items.size();
				sbsize = h * scrLen / items.size();

				if(sbsize > h)
				{
					sbsize = h;
				}
			}
			else
			{
				sbstart = 0;
				sbsize = h;
			}

			offgraphics.setColor(ColorScheme.colors[ColorScheme.sbfore]);

			offgraphics.drawLine(w - 3, sbstart, w - 3, sbstart + sbsize);
			offgraphics.drawLine(w - 1, sbstart, w - 1, sbstart + sbsize);
			offgraphics.drawLine(w - 2, sbstart - 1, w - 2, sbstart + sbsize + 1);

			offgraphics.translate(0, -header);
		}

		g.drawImage(offscreen, 0, 0, Graphics.LEFT | Graphics.TOP);
	}

	public void enableRepaint(boolean value)
	{
		repaints = value;
	}
	
	public void run()
	{
		try
		{
			long lfxsleep = lfx.getDelay();

			long ofnsleep = (int)(8000f / options.longScrollSpeed / Math.min(w, allh));
			OFN_DEF_DELAY = (int)(600 / ofnsleep);

			if(options.noEffects)
			{
				lfxsleep = ofnsleep;
			}

			long target = AuxMath.gcd((int)lfxsleep, (int)ofnsleep);
			long sleep;

			if(target < AuxClass.MIN_THREAD_SLEEP)
			{
				target = AuxClass.MIN_THREAD_SLEEP;
			}

			long current;
			long ofnprev = System.currentTimeMillis();
			long lfxprev = System.currentTimeMillis();

			boolean flag = false;

			while(isshown)
			{
				current = System.currentTimeMillis();

				while(current - ofnprev >= ofnsleep)
				{
					ofnprev += ofnsleep;

					if(ofnstep != 0)
					{
						if(ofndelay > 0)
						{
							ofndelay--;
						}
						else
						{
							ofnx += ofnstep;
						}

						if(ofnstep > 0)
						{
							if(ofnx > images.iconWidth + 2)
							{
								ofnx = images.iconWidth + 2;
								ofnstep = -ofnstep;
								ofndelay = OFN_DEF_DELAY;
							}
						}
						else
						{
							if(ofnx < w - 5 - ofnw)
							{
								ofnx = w - 5 - ofnw;
								ofnstep = -ofnstep;
								ofndelay = OFN_DEF_DELAY;
							}
						}

						flag = true;
					}
				}

				while(current - lfxprev >= lfxsleep)
				{
					lfxprev += lfxsleep;
					lfx.moveLines();

					flag = true;
				}

				if(flag)
				{
					repaint();
					//serviceRepaints();

					flag = false;
				}

				sleep = target - (current - Math.min(ofnprev, lfxprev));

				if(sleep > 0)
				{
					Thread.sleep(sleep);
				}
			}
		}
		catch(InterruptedException ie)
		{
		}

		t = null;
	}
	
	public void showNotify()
	{
		if(t != null && t.isAlive())
		{
			try
			{
				//t.interrupt();
				t.join();
			}
			catch(Exception e)
			{
			}
		}
		
		isshown = true;

		//updateGradients();

		if(options.longScrollSpeed > 0)
		{
			(t = new Thread(this, "FileSelect/Repaint")).start();
		}

		keyReleaseAllowed = false;
	}
	
	public void hideNotify()
	{
		isshown = false;
	}

	public void toggleHotKeyMode()
	{
		hotKeyMode = !hotKeyMode;
	}
	
	/**
     * Обработчик нажатий клавиш
     */
	public void keyPressed(int keyCode)
	{
		keyCode = remapKey(keyCode);

		keyReleaseAllowed = true;

		if(isKeyNum(keyCode))
		{
			return;
		}

		if(!fsmode && !options.noEffects)
		{
			if(keyCode == KEY_FIRE)
			{
				firep = true;
				repaint();
				return;
			}
			else if(keyCode == KEY_LSK)
			{
				lskp = true;
				repaint();
				return;
			}
			else if(keyCode == KEY_RSK)
			{
				rskp = true;
				repaint();
				return;
			}
		}

		int action = keyConfig.getAction(keyCode);

		if(action >= 0)
		{
			main.menu.parent = this;
			main.menu.listen.menuAction(action);
		}
	}
	
	public void numKeyPressed(int keyCode)
	{
		int action = keyConfig.getAction(keyCode);
		
		if(action >= 0)
		{
			main.menu.parent = this;
			main.menu.listen.menuAction(action);
		}
	}
	
	public void directKeyPressed(int action)
	{
		if(action == Locale.NEXT_LINE_CMD)
		{
			if(++scrSel >= items.size())
			{
				scrSel = 0;
			}
		}
		else if(action == Locale.PREV_LINE_CMD)
		{
			if(--scrSel < 0)
			{
				scrSel = items.size() - 1;
			}
		}
		else if(action == Locale.NEXT_SCREEN_CMD)
		{
			if(scrSel == items.size() - 1)
			{
				scrSel = main.currentPath.length() == 0 ? 0 : 1;
			}
			else
			{
				scrSel += scrLen;
				
				if(scrSel > items.size() - 1)
				{
					scrSel = items.size() - 1;
				}
			}
		}
		else if(action == Locale.PREV_SCREEN_CMD)
		{
			if(main.currentPath.length() == 0 ? scrSel == 0 : scrSel == 1)
			{
				scrSel = items.size() - 1;
			}
			else
			{
				scrSel -= scrLen;
				
				if(scrSel < 1)
				{
					scrSel = main.currentPath.length() == 0 ? 0 : 1;
				}
			}
		}
		else if(action == Locale.GOTO_START_CMD)
		{
			scrSel = main.currentPath.length() == 0 ? 0 : 1;
		}
		else if(action == Locale.GOTO_END_CMD)
		{
			scrSel = items.size() - 1;
		}
		else
		{
			return;
		}
		
		select(scrSel);
	}
	
	/**
     * Выделение по нажатию кнопы "огонь", т.е джойстика
     */
	public void fireSelectAction()
	{
		if(markCount < 0)
		{
			selectFile();
		}
		else // если идёт процесс выделения
		{
			markSelected();
			repaint();
		}
	}
	
	public String prevpath;
	
	/**
     * Обработчик отпусканий клавиш
     */
	public void keyReleased(int keyCode)
	{
		keyCode = remapKey(keyCode);

		if(!keyReleaseAllowed)
		{
			return;
		}

		if(hotKeyMode)
		{
			keyCode |= KEY_HOT;
			hotKeyMode = false;
		}
		
		if(keyHeld < 3 && isKeyNum(keyCode))
		{
			numKeyPressed(keyCode);
		}
		else if(!fsmode && !options.noEffects)
		{
			int action = -1;
			
			if(keyCode == KEY_LSK && lskp)
			{
				action = keyConfig.getAction(KEY_LSK);
				lskp = false;
			}
			else if(keyCode == KEY_RSK && rskp)
			{
				action = keyConfig.getAction(KEY_RSK);
				rskp = false;
			}
			else if(keyCode == KEY_FIRE && firep)
			{
				action = keyConfig.getAction(KEY_FIRE);
				firep = false;
			}
			
			if(action >= 0)
			{
				main.menu.parent = this;
				main.menu.listen.menuAction(action);
			}
		}
		
		keyHeld = 0;
	}
	
	/**
     * Обработчик повторений клавиш
     */
     
	public void keyRepeated(int keyCode)
	{
		keyCode = remapKey(keyCode);
		
		if(isKeyNum(keyCode))
		{
			if(++keyHeld == 3)
			{
				keyHeld = 0;
				keyReleaseAllowed = false;
				
				numKeyPressed(keyCode | KEY_HELD);
			}
		}
		else
		{
			keyPressed(keyCode);
		}
	}
	
	/**
     * Получить последние n символов (для титула)
     */
	private String getLastPartOfString(AbstractFont font, String path, int maxw)
	{
		if(font.stringWidth(path) <= maxw)
		{
			return path;
		}
		else
		{
			int index = 0;
			String res;

			do
			{
				res = ".." + path.substring(++index).trim();
			}
			while(font.stringWidth(res) > maxw);
			
			return res;
		}
	}
	
//	private static void out(String s)
//	{
//		System.out.println("[cvsFileSelect] " + s);
//	}
}
