/*
	Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
	и других спецификаций для функционирования компактных приложений на языке
	Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

	Copyright © 2016, 2019 Малик Разработчик

	Это свободная программа: вы можете перераспространять ее и/или изменять
	ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
	в каком она была опубликована Фондом свободного программного обеспечения;
	либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

	Эта программа распространяется в надежде, что она будет полезной,
	но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
	или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
	общественной лицензии GNU.

	Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
	вместе с этой программой. Если это не так, см.
	<https://www.gnu.org/licenses/>.
*/


package malik.emulator.midp;

import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import malik.emulator.fileformats.sound.*;
import malik.emulator.io.cloud.*;
import malik.emulator.midp.player.*;

final class SoundCommand extends ConsoleCommand
		implements Runnable, CommandListener, ItemCommandListener, ItemStateListener
{
	private static final class SaveThread extends Thread
	{
		private SoundEncoderGetter sound;
		private String fileName;

		SaveThread(SoundEncoderGetter sound, String fileName)
		{
			super("Сохранение звука…");
			this.sound = sound;
			this.fileName = fileName;
		}

		public void run()
		{
			String fileName = this.fileName;
			SoundEncoderGetter sound = this.sound;
			SoundEncoder encoder;
			FileOutputStream file;
			try
			{
				System.out.println("Сохранение звука в файл " + fileName + "…");
				encoder = sound.getSoundEncoder();
				(file = new FileOutputStream(fileName)).checkOpenError();
				try
				{
					encoder.saveToOutputStream(file);
				}
				finally
				{
					file.close();
				}
				System.out.println("Сохранение звука в файл " + fileName +
						" успешно завершено.");
			}
			catch(IOException e)
			{
				e.printRealStackTrace();
				System.out.println("Сохранение звука в файл " + fileName +
						" завершено с ошибками.");
			}
		}
	}


	private boolean terminated;
	private int soundIndex;
	private SoundEncoderGetter[] allSounds;
	private Player[] allPlayers;
	private Command commandCancel;
	private Command commandBack;
	private Command commandSaveDialog;
	private Command commandSaveToFile;
	private Gauge itemLoadingProgress;
	private StringItem itemCurrentSound;
	private Item itemPrevSound;
	private Item itemNextSound;
	private TextField itemFileNameMID;
	private TextField itemFileNameWAV;
	private Alert screenLoading;
	private Form screenSounds;
	private Form screenSaveMID;
	private Form screenSaveWAV;

	SoundCommand()
	{
		super("звуки");
	}

	public void run(String[] arguments)
	{
		terminated = false;
		getItemLoadingProgress().setValue(0);
		MIDletProxy.getInstance().getEmulatorScreen().setCurrent(getScreenLoading());
		(new Thread(this, "Поиск звуков…")).start();
	}

	public void run()
	{
		int i;
		int memoryLength;
		int soundsCount;
		SoundEncoderGetter[] soundsList;
		Player[] playersList;
		Object[] memory;
		Object current;
		Gauge progress;
		if((progress = itemLoadingProgress) == null)
		{
			return;
		}
		memoryLength = (memory = Memory.getAllObjects()).length;
		soundsCount = 0;
		for(i = 0; i < memoryLength; i++)
		{
			if(terminated)
			{
				return;
			}
			if((current = memory[i]) != null && current instanceof SoundEncoderGetter &&
					current instanceof Player)
			{
				soundsCount++;
			}
			progress.setValue((i << 4) / memoryLength);
		}
		soundsList = new SoundEncoderGetter[soundsCount];
		playersList = new Player[soundsCount];
		soundsCount = 0;
		for(i = 0; i < memoryLength; i++)
		{
			if(terminated)
			{
				return;
			}
			if((current = memory[i]) != null && current instanceof SoundEncoderGetter &&
					current instanceof Player)
			{
				soundsList[soundsCount] = (SoundEncoderGetter) current;
				playersList[soundsCount] = (Player) current;
				soundsCount++;
			}
			progress.setValue((i << 4) / memoryLength + 0x10);
		}
		progress.setValue(0x20);
		soundIndex = 0;
		allSounds = soundsList;
		allPlayers = playersList;
		MIDletProxy.getInstance().getEmulatorScreen().setCurrent(getScreenSounds());
	}

	public void commandAction(Command command, Displayable screen)
	{
		int idx;
		SoundEncoderGetter[] list;
		SoundEncoderGetter current;
		String fileName;
		Display display = MIDletProxy.getInstance().getEmulatorScreen();
		if(screen == screenLoading && command == commandCancel)
		{
			terminated = true;
			allSounds = null;
			allPlayers = null;
			commandCancel = null;
			itemLoadingProgress = null;
			screenLoading = null;
			display.setCurrent(getConsoleScreen());
			return;
		}
		if(screen == screenSounds)
		{
			if(command == commandSaveDialog && (idx = soundIndex) < (list = allSounds).length)
			{
				if((current = list[idx]) instanceof SyntheticPlayer)
				{
					display.setCurrent(getScreenSaveMID());
					return;
				}
				if(current instanceof SampledPlayer)
				{
					display.setCurrent(getScreenSaveWAV());
				}
				return;
			}
			if(command == commandBack)
			{
				allSounds = null;
				allPlayers = null;
				commandCancel = null;
				commandBack = null;
				commandSaveDialog = null;
				commandSaveToFile = null;
				itemLoadingProgress = null;
				itemCurrentSound = null;
				itemPrevSound = null;
				itemNextSound = null;
				itemFileNameMID = null;
				itemFileNameWAV = null;
				screenLoading = null;
				screenSounds = null;
				screenSaveMID = null;
				screenSaveWAV = null;
				display.setCurrent(getConsoleScreen());
			}
			return;
		}
		label0:
		{
			if(screen == screenSaveMID)
			{
				display.setCurrent(getScreenSounds());
				if(command == commandSaveToFile)
				{
					fileName = itemFileNameMID.getString();
					break label0;
				}
				return;
			}
			if(screen == screenSaveWAV)
			{
				display.setCurrent(getScreenSounds());
				if(command == commandSaveToFile)
				{
					fileName = itemFileNameWAV.getString();
					break label0;
				}
			}
			return;
		}
		if((idx = soundIndex) < (list = allSounds).length)
		{
			(new SaveThread(list[idx], fileName)).start();
		}
	}

	public void commandAction(Command command, Item item)
	{
		int len;
		Player[] list;
		Player current;
		if(command == List.SELECT_COMMAND && (len = (list = allPlayers).length) > 0)
		{
			if(item == itemCurrentSound)
			{
				try
				{
					if((current = list[soundIndex]).getState() == Player.STARTED)
					{
						current.stop();
					} else
					{
						current.start();
					}
				}
				catch(MediaException e)
				{
					e.printRealStackTrace();
				}
			}
			else if(item == itemPrevSound)
			{
				soundIndex = (soundIndex + len - 1) % len;
			}
			else if(item == itemNextSound)
			{
				soundIndex = (soundIndex + 1) % len;				
			}
		}
	}

	public void itemStateChanged(Item item)
	{
		String fileName;
		TextField field;
		if(item == (field = itemFileNameMID))
		{
			if((fileName = field.getString()) != null && fileName.length() <= 0)
			{
				screenSaveMID.removeCommand(commandSaveToFile);
				return;
			}
			screenSaveMID.addCommand(commandSaveToFile);
			return;
		}
		if(item == (field = itemFileNameWAV))
		{
			if((fileName = field.getString()) != null && fileName.length() <= 0)
			{
				screenSaveWAV.removeCommand(commandSaveToFile);
				return;
			}
			screenSaveWAV.addCommand(commandSaveToFile);
		}
	}

	private Command getCommandCancel()
	{
		Command result;
		if((result = commandCancel) == null)
		{
			result = commandCancel = new Command("Отмена", Command.CANCEL, 0);
		}
		return result;
	}

	private Command getCommandBack()
	{
		Command result;
		if((result = commandBack) == null)
		{
			result = commandBack = new Command("Назад", Command.BACK, 0);
		}
		return result;
	}

	private Command getCommandSaveDialog()
	{
		Command result;
		if((result = commandSaveDialog) == null)
		{
			result = commandSaveDialog = new Command("Сохранить…", Command.SCREEN, 0);
		}
		return result;
	}

	private Command getCommandSaveToFile()
	{
		Command result;
		if((result = commandSaveToFile) == null)
		{
			result = commandSaveToFile = new Command("Сохранить", Command.OK, 0);
		}
		return result;
	}

	private Gauge getItemLoadingProgress()
	{
		Gauge result;
		if((result = itemLoadingProgress) == null)
		{
			result = itemLoadingProgress = new Gauge(null, false, 0x20, 0);
		}
		return result;
	}

	private Displayable getScreenLoading()
	{
		Alert result;
		if((result = screenLoading) == null)
		{
			result = screenLoading = new Alert("Любите красить пасхальные яйца?", null,
					null, getCommandCancel(), this,
					"Поиск звуков…", null, AlertType.INFO, getItemLoadingProgress());
		}
		return result;
	}

	private Displayable getScreenSounds()
	{
		Item[] items;
		Command[] commands;
		Font font;
		Form result;
		if((result = screenSounds) == null)
		{
			font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
			items = new Item[] {
					itemCurrentSound = new StringItem(Item.LAYOUT_CENTER |
							Item.LAYOUT_NEWLINE_AFTER, -1, -1, null, null,
							List.SELECT_COMMAND, this, "> ||", font, Item.BUTTON),
					itemPrevSound = new StringItem(Item.LAYOUT_CENTER, -1, -1, null, null,
							List.SELECT_COMMAND, this, "< предыдущий", font, Item.BUTTON),
					itemNextSound = new StringItem(Item.LAYOUT_CENTER, -1, -1, null, null,
							List.SELECT_COMMAND, this, "следующий >", font, Item.BUTTON)
			};
			commands = new Command[] {
					getCommandBack(), getCommandSaveDialog()
			};
			result = screenSounds = new Form("Звуки", null,
					commands, this, items, null);
		}
		return result;
	}

	private Displayable getScreenSaveMID()
	{
		Item[] items;
		Command[] commands;
		TextField fileName;
		Form result;
		if((result = screenSaveMID) == null)
		{
			items = new Item[] {
					itemFileNameMID = fileName = new TextField("Имя файла", "/имя.mid", 32,
							Input.ANY)
			};
			commands = new Command[] {
					getCommandSaveToFile(), getCommandBack()
			};
			result = screenSaveMID = new Form("Сохранить", null,
					commands, this, items, this);
			fileName.setPreferredSize(result.getWidth(), -1);
		}
		return result;
	}

	private Displayable getScreenSaveWAV()
	{
		Item[] items;
		Command[] commands;
		TextField fileName;
		Form result;
		if((result = screenSaveWAV) == null)
		{
			items = new Item[] {
					itemFileNameWAV = fileName = new TextField("Имя файла", "/имя.wav", 32,
							Input.ANY)
			};
			commands = new Command[] {
					getCommandSaveToFile(), getCommandBack()
			};
			result = screenSaveWAV = new Form("Сохранить", null,
					commands, this, items, this);
			fileName.setPreferredSize(result.getWidth(), -1);
		}
		return result;
	}
}
