package filemanager;

import javax.microedition.lcdui.*;
import java.io.*;
import com.vmx.*;
import com.one.*;
import com.one.file.Connector;
import com.one.file.TransparentConnector;
import javax.microedition.midlet.MIDletStateChangeException;
import com.one.ContainerStateListener;

public class main implements Runnable, ContainerStateListener // extends MIDlet
{
	public static final String TEXT_VIEW_CLASS = "modules.text.cvsTextView";
	
	public static RootLoader loader;
	public static String currentPath = "", currentFile = "";
	public static String oldPath = "", oldFile = "";
	public static cvsFileSelect FileSelect;
	public static lstKeyConfig keycfg;
	public static diskInfo diskinfo;
	public static cvsMenu menu;
	public static DisplayManager dsp;
	public static PanelManager manager;
	public static cvsWait wait;
	public static MemoryMonitor monitor;
	public static lstColorScheme colors;
	public static lstContainers containers;
	
	public static Accelerometer accelerometer;

	private boolean alreadyStarted = false;
	private Thread closingThread;
	
	public main(RootLoader rl)
	{
		System.out.println("Starting with loader " + rl.getClass().getName() + "...");
		
		loader = rl;
		
		Display d = rl.getDisplay();
		
		dsp = new DisplayManager(d);
		PaintableObject.setRenderer(dsp.getRenderer());
		GraphicAlert.setAlertDisplay(d);
		Renderer.setVibraDisplay(d);
		
		ErrScreen.setRootLoader(rl);
		ErrScreen.setDisplayManager(dsp);

		ProgressBar.setDisplayManager(dsp);

		Connector.setConnectionProvider(loader.getConnectionProvider());

		Container.setListener(this);

//		GraphicFont.createAlphaMap(dsp.numAlphaLevels());
	}

	public void restartApp()
	{
		saveSettings();

		alreadyStarted = false;
		startApp();
	}
	
	public void startApp()
	{
		if(alreadyStarted)
		{
			return;
		}
		
		alreadyStarted = true;

		long prevtime = System.currentTimeMillis();
		
		ModuleRegistry.reset();
		fontConfig.resetAll();

		SplashScreen splash = new SplashScreen();
		splash.setMaxState(30);
		splash.setState(0);
		dsp.setCurrent(splash);

		try
		{
//			byte[][] vendors = new byte[][]
//			{
//				{ 77, 73, 68, 108, 101, 116, 45, 86, 101, 110, 100, 111, 114 },
//				{ 83, 105, 108, 101, 110, 116, 75, 110, 105, 103, 104, 116, 44 },
//				{ 86, 77, 88 },
//				{ 68, 105, 72, 76, 111, 83 }
//			};
//
//			String s = loader.getAppProperty(TextProcessor.byteArrayToString(vendors[0]));
//
//			for(int i = 1; i < vendors.length; i++)
//			{
//				if(s.indexOf(TextProcessor.byteArrayToString(vendors[i])) < 0)
//				{
//					throw new RuntimeException();
//				}
//			}
//
//			splash.nextState();

			startLightControl(true);
			
			loadKernel(splash);

			if(options.firstTime < 2)
			{
				loadShell(splash);
			}
			else
			{
				splash.setState(splash.getMaxState());
			}

			startLightControl(false);

			System.out.println(Integer.toString(splash.getState()) + " of " + Integer.toString(splash.getMaxState()) + " load stages passed in " + (System.currentTimeMillis() - prevtime) + " ms");

			if(!options.launchPasswordHash.equals(options.EMPTY_HASH))
			{
				frmPassword pf = new frmPassword(Locale.getString(null, Locale.PASS_REQUEST_ON_LAUNCH), options.launchPasswordHash);
				dsp.setCurrent(pf);

				if(!pf.modalResult())
				{
					destroyApp();
				}
			}

			startUI();
		}
		catch(Throwable t)
		{
			ErrScreen.showStopMsg(splash.getState(), t);
			ErrScreen.getInstance().setNextDisplayable(null);
		}
	}

	protected static void loadKernel(SplashScreen splash) throws IOException
	{
		splash.debugPrint("Loading options");
		options.restoreOptions();

		if(options.firstTime == 2)
		{
			if(loader.useNoEffects())
			{
				options.noEffects = true;
				options.longScrollSpeed = 0;
				options.ditherGradients = false;
				options.alphaGradients = false;
				options.mmThreshold = 0;
				options.cacheCodePages = false;
				options.unloadModules = true;
				ArchiveContainer.virtualizeToRAM = false;
			}

			String filename = loader.getAppProperty("Error-Log");

			if(filename != null)
			{
				filesystem.makeNewDir(filename.substring(0, filename.lastIndexOf('/') + 1));
				ErrScreen.setLogFileName(filename);
			}

			filename = loader.getAppProperty("Temp-Dir");

			if(filename != null)
			{
				filesystem.makeNewDir(filename);
				Connector.setTempFileDir(filename);
			}
		}
		
		splash.nextState();

		splash.debugPrint("Loading images");
		images.loadImages(options.noEffects);
		splash.createBackground();
		splash.nextState();

		splash.debugPrint("Loading codepages");
		StringEncoder.loadCodePages(options.cacheCodePages);
		splash.nextState();
		
		splash.debugPrint("Setting up encodings");
		String s = loader.getAppProperty("Default-Encoding");

		if(s != null)
		{
			StringEncoder.ENC_DEFAULT = StringEncoder.findEncoding(s);
		}
		splash.nextState();

		if(options.firstTime == 2)
		{
			s = loader.getAppProperty("Archive-Encoding");

			if(s != null)
			{
				StringEncoder.ENC_ARCHIVE = StringEncoder.findEncoding(s);
			}
			
			options.textEnc = StringEncoder.ENC_DEFAULT;
			options.arcEnc = StringEncoder.ENC_ARCHIVE;
		}
		else
		{
			StringEncoder.ENC_ARCHIVE = options.arcEnc;
		}
		splash.nextState();

		splash.debugPrint("Loading passwords");
		options.loadPasswords();
		splash.nextState();

		splash.debugPrint("Parsing color scheme list");
		ColorScheme.readSchemeList();
		splash.nextState();

		splash.debugPrint("Loading color scheme");
		if(options.colorScheme != ColorScheme.SCHEME_CUSTOM)
		{
			try
			{
				ColorScheme.loadColorScheme(options.colorScheme);
			}
			catch(Exception e)
			{
				ErrScreen.showErrMsg(67, e);
			}
		}
		splash.nextState();

		splash.debugPrint("Parsing keymap list");
		gkcCanvas.readKeyMapList();
		splash.nextState();

		splash.debugPrint("Loading keymap");
		options.keyMap = gkcCanvas.setKeyMap(options.keyMap, options.screenTransform);
		splash.nextState();

		// Загружаем список языков и язык
		splash.debugPrint("Parsing locale list");
		Locale.readLocaleList();
		splash.nextState();

		if(options.language.length() == 0)
		{
			s = System.getProperty("microedition.locale");
			//System.out.println("Default locale is " + s);

			if(s != null)
			{
				s = s.toLowerCase();

				for(int i = 0; i < Locale.locales.length; i++)
				{
					if(s.startsWith(Locale.locales[i].toLowerCase()))
					{
						options.language = Locale.locales[i];
						break;
					}
				}
			}
		}
		splash.nextState();

		splash.debugPrint("Loading locale");
		try
		{
			Locale.loadLocale(options.language);
		}
		catch(Exception e)
		{
			ErrScreen.showErrMsg(69, e);
			options.language = "en";

			try
			{
				Locale.loadLocale("en");
			}
			catch(Exception e1)
			{
				ErrScreen.showErrMsg(70, e1);
			}
		}
		splash.nextState();

		//TemplateManager.loadTemplates();
		//splash.nextState();

		//MimeType.loadTypes();
		//splash.nextState();

		Renderer.setVibraDuration(options.keyVibraDuration);
	}

	protected static void loadShell(SplashScreen splash) throws IOException
	{
		splash.debugPrint("Parsing module list");
		ModuleRegistry.readModuleList();
		splash.nextState();

		splash.debugPrint("Parsing type list");
		ModuleRegistry.readTypeList();
		splash.nextState();

		splash.debugPrint("Parsing group list");
		ModuleRegistry.readGroupList();
		splash.nextState();

		splash.debugPrint("Parsing options list");
		ModuleRegistry.readOptionStoreList();
		splash.nextState();

		splash.debugPrint("Loading options for modules");
		ModuleRegistry.restoreModuleOptions();
		splash.nextState();

		splash.debugPrint("Loading fonts");
		fontConfig.loadFonts(splash);
		splash.nextState();

		splash.debugPrint("Loading module icons");
		ModuleRegistry.loadIcons(splash, options.noEffects);
		splash.nextState();

		splash.debugPrint("Loading system icons");
		images.loadIcons(splash, options.noEffects);
		splash.nextState();

		//System.out.println("Rescaling icons from " + images.origIconWidth + "x" + images.origIconHeight + " to " + images.iconWidth + "x" + images.iconHeight);

//		options.loadBookMarks();
//		splash.nextState();
//
//		options.loadFavorites();
//		splash.nextState();

//		keycfg = new lstKeyConfig();
//		splash.nextState();

		splash.debugPrint("Initializing wait screen");
		wait = new cvsWait();
		splash.nextState();

		splash.debugPrint("Initializing menu");
		menu = new cvsMenu();
		splash.nextState();

		splash.debugPrint("Initializing file list");
		FileSelect = new cvsFileSelect();
		splash.nextState();

		splash.debugPrint("Initializing panel manager");
		manager = new PanelManager(dsp, 10);
		splash.nextState();

		if(options.rememberPath)
		{
			manager.restorePanels();
		}
		splash.nextState();

		splash.debugPrint("Initializing memory monitor");
		monitor = new MemoryMonitor();
		monitor.setDelay(options.mmDelay);
		monitor.setThreshold(options.mmThreshold);
		monitor.setOffscreenUpdate(true);
		splash.nextState();

//		Palette.loadPalette();
//		splash.nextState();
//
//		Palette.loadUnifiedPalette();
//		splash.nextState();

		splash.debugPrint("Initializing accelerometer");
		accelerometer = loader.getAccelerometer();

		if(accelerometer == null)
		{
			accelerometer = new Accelerometer()
			{
				public int getValue(int channel)
				{
					return 0;
				}

				public int getDelta(int channel, int threshold)
				{
					return 0;
				}
			};
		}
		splash.nextState();

		splash.debugPrint("Initializing progress bar");
		ProgressBar.setDisplayable(createLocalizedProgressScreen());
		splash.nextState();
		
		ImageProcessor.releaseCachedImages();

		gkcCanvas.PTX = AuxClass.parseInt(loader.getAppProperty("Pointer-Translate-X"), 0);
		gkcCanvas.PTY = AuxClass.parseInt(loader.getAppProperty("Pointer-Translate-Y"), 0);

		float fdh = AbstractFont.getDefaultFont().getHeight();

		gkcCanvas.PCW = (int)(fdh * AuxClass.parseFloat(loader.getAppProperty("Pointer-Cell-Width"), 1.0f));
		gkcCanvas.PCH = (int)(fdh * AuxClass.parseFloat(loader.getAppProperty("Pointer-Cell-Height"), 1.0f));
		gkcCanvas.PSF = (int)(fdh * AuxClass.parseFloat(loader.getAppProperty("Pointer-Soft-Height"), 1.0f));

		splash.nextState();

//		if(AuxClass.classExists("javax.microedition.content.Registry"))
//		{
//			createRequestListener();
//		}
//
//		splash.nextState();
	}
	
	/**
	 * Запуск интерфейса
	 */
	public static void startUI()
	{
		images.splashBack = null;
		
		if(options.firstTime == 2)
		{
			dsp.setCurrent(new frmInitialSetup());
		}
		else if(options.firstTime == 1)
		{
			dsp.setCurrent(new frmEULA());
		}
		else
		{
			manager.showPanel(manager.currentPanel());
		}
	}

	/**
	 * Запустить постоянную подсветку (если можно).
	 * @param flag - если посдветка горит не всегда, то она горит, если здесь true
	 */
	public static void startLightControl(boolean flag)
	{
		LightControl.startLightControl(options.lightControlMode == 1 || (options.lightControlMode == 2 && flag));
	}

	/**
	 * Создать обработчик запросов CHAPI
	 */
	public static void createRequestListener()
	{
//		try
//		{
//			ContentHandlerServer server = Registry.getServer(UniFM.class.getName());
//
//			RequestListener listener = new RequestListener()
//			{
//				public void invocationRequestNotify(ContentHandlerServer handler)
//				{
//					Invocation inv = handler.getRequest(false);
//
//					if(inv != null)
//					{
//						String url = inv.getURL();
//
//						if(url.startsWith("file:///"))
//						{
//							main.FileSelect.executeFile(url.substring(8));
//							handler.finish(inv, Invocation.OK);
//						}
//						else
//						{
//							handler.finish(inv, Invocation.ERROR);
//						}
//					}
//				}
//			};
//
//			server.setListener(listener);
//		}
//		catch(ContentHandlerException che)
//		{
//		}
//		catch(Throwable t)
//		{
//			t.printStackTrace();
//		}
	}

	/**
	 * Создать экран прогресса, использующий текущую локаль.
	 */
	protected static Object createLocalizedProgressScreen()
	{
		GraphicAlert al = new GraphicAlert(Locale.getString(null, Locale.WAIT), Locale.getString(null, Locale.WAIT_PLEASE), null, AlertType.WARNING);
		al.setTimeout(Alert.FOREVER);
		al.setIndicator(true);

		return al;
	}

	/**
	 * Показать Alert с сообщением.
	 *
	 * "Фишка" здесь в том, что значок выбирается
	 * исходя из переданного AlertType.
	 *
	 * @param title заголовок сообщения
	 * @param text текст сообщения
	 * @param type тип сообщения
	 * @param timeout как долго его держать на экране
	 * @param parent что ставить на экран после
	 */
	public static void showMessage(String title, String text, AlertType type, int timeout, Object parent)
	{
		GraphicAlert al = new GraphicAlert(title, text, images.getAlertIcon(type), type);
		al.addCommand(new Command(Locale.getString(null, Locale.OK_CMD), Command.OK, 0));
		al.setTimeout(timeout);

		dsp.setCurrent(al, parent != null ? parent : dsp.getCurrent());
	}

	/**
	 * Показать редактор цветовой схемы.
	 * Если он еще не загружен, загрузить его.
	 *
	 * @param parent что ставить на экран после
	 */
	public static void showColorSchemeEditor(Object parent)
	{
		if(colors == null)
		{
			colors = new lstColorScheme();
		}

		colors.updateList();

		colors.parent = parent;
		dsp.setCurrent(colors);
	}

	/**
	 * Показать список контейнеров.
	 * Если он еще не загружен, загрузить его.
	 *
	 * @param parent что ставить на экран после
	 */
	public static void showContainerList(Object parent)
	{
		if(containers == null)
		{
			containers = new lstContainers();
		}

		containers.updateList();

		containers.parent = parent;
		dsp.setCurrent(containers);
	}

	/**
	 * С контейнером что-то случилось.
	 * Обновляем список файлов и список контейнеров.
	 */
	public void containerStateChanged(Container caller)
	{
		if(caller instanceof ArchiveContainer)
		{
			FileSelect.list(((ArchiveContainer)caller).getBaseConnection().getName());
			containers.updateList();
		}
	}

	public static void showKeyConfig()
	{
		if(keycfg == null)
		{
			keycfg = new lstKeyConfig();
		}

		keycfg.show();
	}

//	public static void setScreenTransform(int transform)
//	{
//		Renderer rn = PaintableObject.getRenderer();
//
//		if(rn.getTransform() == transform)
//		{
//			return;
//		}
//
//		rn.setEnabled(false);
//
//		rn.setTransform(transform);
//		images.loadImages(images.isTransformLandscape(transform));
//		gkcCanvas.setKeyMap(options.keyMap, transform);
//
//		FileSelect.updateLayout();
//
//		rn.setEnabled(true);
//	}
	
	/**
	 * Приостановить выполнение приложения - вызывается JRE
	 */
	public void pauseApp()
	{
		loader.notifyPaused();
	}

	/**
	 * Уничтожить приложение - вызывается самим приложением
	 */
	public static void destroyApp()
	{
		try
		{
			loader.destroyApp(false);
		}
		catch(MIDletStateChangeException _)
		{
		}
	}
	
	/**
	 * Уничтожить приложение - вызывается JRE
	 */
	public void destroyApp(boolean unconditional) throws MIDletStateChangeException
	{
		saveSettings();

		if(unconditional)
		{
			// Завершиться как положено нам не дадут,
			// так что лучше и не пытаться

			loader.notifyDestroyed();
		}
		else
		{
			if(closingThread == null)
			{
				if(TransparentConnector.hasOpenContainers())
				{
					closingThread = new Thread(this);
					closingThread.start();
				}
				else
				{
					loader.notifyDestroyed();
				}
			}

			throw new MIDletStateChangeException();
		}
	}

	public static void saveSettings()
	{
		System.out.print("Saving settings...");

		options.saveOptions();
		options.savePasswords();
		options.saveFavorites();
		options.saveBookMarks();

		ModuleRegistry.saveModuleOptions();

		TemplateManager.saveTemplates();
		MimeType.saveTypes();

		if(manager != null)
		{
			manager.storePanel(manager.currentPanel());
			manager.savePanels();
		}

		System.out.println(" done");
	}

	public void run()
	{
		System.out.print("Closing containers...");

		try
		{
			TransparentConnector.closeContainers();
		}
		catch(IOException e)
		{
			ErrScreen.showErrMsg(136, e);
		}

		System.out.println(" done");

		closingThread = null;

		loader.notifyDestroyed();
	}
	
//	private static void out(String s)
//	{
//		System.out.println("[main] " + s);
//	}
}
