package modules.video; // переведен

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
import com.vmx.*;
import com.one.*;
import com.one.file.*;
import filemanager.MimeType;
import filemanager.images;
import filemanager.main;
import filemanager.options;
import java.util.Enumeration;

/**
 * Проигрыватель видео
 */
public class cvsVideoPlayer extends gkcCanvas implements PlayerListener, Runnable
{
	public static final String SHUFFLE_PLAY_MARK = "±"; // "°";

	private static Player player;
	private VolumeControl volumeControl;
	private VideoControl videoControl;
	private InputStream is;
	private int trans;
	private boolean running;
	private boolean paused;
	private Thread t = null;
	private String currentFile, OnlyFileName;
	private int w, h, w2, h2;
	private AbstractFont infoFont;
	private int ofnw, ofnx, ofnstep, ofndelay; // прокрутка названия
	private static final int OFN_DEF_DELAY = 1;
	private boolean keyFlag = false;
	private boolean wasPaused = false;
	private long duration, time, tstep;
	private int pbx, pby, pbw, pbh; // прогресс
	private PlayList playlist;
	private boolean enableUI = true;
	private boolean overlay;
	private boolean paintflag;
	private boolean update;
	private boolean isshown;

	private int runpanel;

	private static cvsVideoPlayer instance;

	public static void loadInstance()
	{
		if(instance == null)
		{
			instance = new cvsVideoPlayer();
		}
	}

	public static cvsVideoPlayer getInstance()
	{
		loadInstance();
		return instance;
	}

	private Runnable videoRedisplayTask = new Runnable()
	{
		public void run()
		{
			Thread.yield();

			update = true;
			
			repaint();
			serviceRepaints();

			if(videoControl != null)
			{
				videoControl.setVisible(!isshown);
				videoControl.setVisible(isshown);
			}
		}
	};

	/**
	 * Конструктор
	 */
	public cvsVideoPlayer()
	{
		setFullScreenMode(true);

		w = getWidth();
		h = getHeight();

		w2 = w / 2;
		h2 = h / 2;

		infoFont = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_BOLD, AbstractFont.SIZE_SMALL);

		//bgimage = images.createFullUI(w, h);
		
		pbw = w * 9 / 16;
		pbh = infoFont.getHeight() * 3 / 4;
		pbx = (w - pbw) / 2;
		pby = images.uiTopHeight + (h - images.uiTopHeight - images.uiBottomHeight - infoFont.getHeight()) / 2;
		
		runpanel = -1;
	}

	/**
	 * Обновление данных в соответствии с состоянием плеера
	 */
	public void playerUpdate(Player player, String event, Object data)
	{
		//System.out.println ("EVENT =" + event);

		if(event.equals(PlayerListener.VOLUME_CHANGED))
		{
			if(volumeControl != null)
			{
				VideoOptions.volume = volumeControl.getLevel();
				//System.out.println ( "Volume =" + VideoOptions.volume );
			}

			repaint();
		}
		else if(event.equals(PlayerListener.END_OF_MEDIA))
		{
			nextClip();
		}
	}

	public void setPlayList(PlayList newlist)
	{
		playlist = newlist;
	}
	
	public void setPlayList(Enumeration newlist)
	{
		playlist = new PlayList(newlist);
	}
	
	protected void initScroll()
	{
		// только имя файла для прокрутки
		OnlyFileName = currentFile.substring(currentFile.lastIndexOf('/') + 1);
		
		ofnw = infoFont.stringWidth(OnlyFileName);
		ofnx = images.uiTopHSpace;
		ofndelay = OFN_DEF_DELAY;
		
		if(ofnw > w - images.uiTopHSpace * 2)
		{
			ofnstep = -(ofnw / OnlyFileName.length());
		}
		else
		{
			ofnstep = 0;
		}
	}
	
	protected void initDuration()
	{
		duration = player.getDuration();
		tstep = duration / 100;
	}
	
	protected void initPanels()
	{
		if(runpanel < 0)
		{
			runpanel = main.manager.currentPanel();
		}
		
		main.manager.setCurrent(this, runpanel);
		main.manager.updateAssociation(runpanel, playlist.getCurrentElement());
	}
	
	protected void initPlayList(String file)
	{
		currentFile = file;

		if(playlist == null)
		{
			playlist = new PlayList(file);
		}

		playlist.selectElement(file);
	}
	
	/**
	 * Играть файл videoFile
	 */
	public void playVideo(String videoFile)
	{
		destroyPlayer();
		
		initPanels();
		
		player = null;
		running = true;
		
		initPlayList(videoFile);
		
		initScroll();
		
		try
		{
			player = Manager.createPlayer("file:///" + videoFile);
			player.realize();
			player.prefetch();

			player.addPlayerListener(this);
			player.setLoopCount(1);
			
			initDuration();
			
			videoControl = (VideoControl)player.getControl("VideoControl");
			setDisplay(true);
			
			volumeControl = (VolumeControl)player.getControl("VolumeControl");

			if(volumeControl != null)
			{
				volumeControl.setLevel(VideoOptions.volume);
				volumeControl.setMute(VideoOptions.muted);
			}
		}
		catch(Exception e)
		{
			try
			{
				playVideoFromStream(Connector.openInputStream("file:///" + videoFile), videoFile.substring(videoFile.lastIndexOf('/') + 1));
				return;
			}
			catch(IOException ioe)
			{
				ErrScreen.showErrMsg(16, ioe);
			}
		}
		
		if(t == null)
		{
			t = new Thread(this, "VideoPlayer/Update");
			t.start();
		}
	}

	public void playVideoFromStream(InputStream is, String videoFile)
	{
		destroyPlayer();
		
		initPanels();
		
		player = null;
		running = true;
		
		initPlayList(videoFile);
		
		initScroll();
		
		try
		{
			this.is = is;

			try
			{
				player = Manager.createPlayer(is, MimeType.getType(videoFile));
				player.realize();
				player.prefetch();
			}
			catch(Exception stupidEmulatorException)
			{
				player = Manager.createPlayer(is, "video/3gpp");
				player.realize();
				player.prefetch();
			}

			player.addPlayerListener(this);
			player.setLoopCount(1);
			
			initDuration();
			
			videoControl = (VideoControl)player.getControl("VideoControl");
			setDisplay(true);
			
			volumeControl = (VolumeControl)player.getControl("VolumeControl");

			if(volumeControl != null)
			{
				volumeControl.setLevel(VideoOptions.volume);
				volumeControl.setMute(VideoOptions.muted);
			}
		}
		catch(Exception e)
		{
			ErrScreen.showErrMsg(16, e);
		}
		
		if(t == null)
		{
			t = new Thread(this, "VideoPlayer/Update");
			t.start();
		}
	}

	public void hideNotify()
	{
		if(videoControl != null)
		{
			try
			{
				videoControl.setVisible(false);
			}
			catch(Exception e)
			{
			}
		}

		isshown = false;
	}

	public void showNotify()
	{
		if(videoControl != null)
		{
			try
			{
				videoControl.setVisible(true);
			}
			catch(Exception e)
			{
			}
		}

		isshown = true;
		update = true;
	}
	
	/**
	 * Функция отрисовки
	 */
	public void paint(ExtGraphics g)
	{
		boolean needupdate = update;
		update = false;

		//System.out.println("[" + AuxClass.timeToString(-1, true) + "]");

		//boolean playing = player != null && player.getState() == Player.STARTED;
		
		if(!needupdate && !overlay)
		{
			if(player == null || player.getState() != Player.STARTED)
			{
				return;
			}

//			paintflag = !paintflag;
//
//			if(!paintflag)
//			{
//				return;
//			}
		}

		if(!enableUI)
		{
			g.setClip(0, 0, w, h);

			if(needupdate)
			{
				g.setColor(0xFF000000);
				g.fillRect(0, 0, w, h);
			}
			
			return;
		}

		// Бэкграунд
		if(images.playerUI != null)
		{
			if(!needupdate && player != null)
			{
				g.setClip(0, 0, w, images.uiTopHeight);
				g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP);
				
				g.setClip(0, h - images.uiBottomHeight, w, images.uiBottomHeight);
				g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP);

				g.setClip(0, 0, w, h);
			}
			else
			{
				g.setClip(0, 0, w, h);
				g.drawImage(images.playerUI, 0, 0, Graphics.LEFT | Graphics.TOP);
			}
		}
		
		if(images.buttons != null)
		{
			// Кнопка PLAY
			g.drawRegion(images.buttons, 0, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP);

			// Кнопка STOP
			g.drawRegion(images.buttons, images.btnWidth * 2, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, w - images.btnWidth - images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP);
		}

		g.setColor(images.cPlayFore2);
		
		int y = h - images.uiBottomHeight / 2;
		
		if(VideoOptions.volume == 0) // вывод значка громкости
		{
			images.drawIcon(g, images.iMute, w2 - images.iconWidth, y - images.iconHeight / 2);
			g.fillRect(w2 + 4, y + 4, 10, 1);
		}
		else
		{
			if(!VideoOptions.muted)
			{
				images.drawIcon(g, images.iNoMute, w2 - images.iconWidth, y - images.iconHeight / 2);
			}
			else
			{
				images.drawIcon(g, images.iMute, w2 - images.iconWidth, y - images.iconHeight / 2);
			}
			
			for(int i = 0; i < VideoOptions.volume; i += 25)
			{
				g.fillRect(w2 + 4, y + 3 - (i / 25) * 3, 10, 2);
			}
		}
		
		g.setFont(infoFont);
		g.setColor(images.cPlayFore1); //0x800000);

		if(VideoOptions.shufflePlay)
		{
			g.drawString(SHUFFLE_PLAY_MARK, w - 1, images.uiTopHeight, Graphics.RIGHT | Graphics.TOP);
		}
		
		if(player != null)
		{
			if(player.getState() == Player.STARTED && images.buttons != null)
			{
				g.drawRegion(images.buttons, images.btnWidth, 0, images.btnWidth, images.btnHeight, Sprite.TRANS_NONE, images.uiBottomHOffset, h - images.uiBottomHeight + images.uiBottomVOffset, Graphics.LEFT | Graphics.TOP);
			}
			else
			{
				if(duration > 0 && time >= 0 && VideoOptions.showPlayProgress)
				{
					g.drawRect(pbx, pby, pbw, pbh);
					g.fillRect(pbx + 2, pby + 2, (int)((pbw - 3) * time / duration), pbh - 3);
				}
				else
				{
					g.drawString(AuxClass.mediaTimeToString(time), w2, pby, Graphics.TOP | Graphics.HCENTER);
				}
			}
		}
				
		g.setColor(images.cPlayTitle); // 0xFFFFFF);
		g.setClip(images.uiTopHSpace, images.uiTopVSpace, w - images.uiTopHSpace * 2, images.uiTopHeight - images.uiTopVSpace);

		if(OnlyFileName != null)
		{
			g.drawString(OnlyFileName, ofnx, images.uiTopVSpace, Graphics.LEFT | Graphics.TOP);
		}
		
		g.setClip(0, images.uiTopHeight, w, h - images.uiTopHeight - images.uiBottomHeight);
	}
	
	/**
	 * Установить параметры места для отображения видео
	 */
	private void setDisplay(boolean init)
	{
		if(videoControl == null)
		{
			return;
		}

		int dw, dh, maxh, y;
		
		maxh = h; // enableUI ? h - images.uiTopHeight - images.uiBottomHeight : h;
		y = 0; // enableUI ? images.uiTopHeight : 0;

		double aspect = (double)w / (double)maxh;
		
		int vw = videoControl.getSourceWidth();
		int vh = videoControl.getSourceHeight();

		boolean rotate = false;
		trans = Sprite.TRANS_NONE;

		switch(VideoOptions.rotateMode)
		{
			case 1:
				rotate = true;
				trans = Sprite.TRANS_ROT90;
				break;

			case 2:
				rotate = false;
				trans = Sprite.TRANS_ROT180;
				break;

			case 3:
				rotate = true;
				trans = Sprite.TRANS_ROT270;
				break;

			case 4:
				if(vw > vh)
				{
					rotate = true;
					trans = Sprite.TRANS_ROT90;
				}
				break;

			case 5:
				if(vw > vh)
				{
					rotate = true;
					trans = Sprite.TRANS_ROT270;
				}
				break;
		}

		if(init)
		{
			overlay = true;

			try
			{
				videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO | (trans << 4) | (1 << 8), getRenderer());
			}
			catch(Exception e)
			{
				try
				{
					videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO | (trans << 4), getRenderer());
					overlay = false;
				}
				catch(Exception e1)
				{
					try
					{
						videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO | (1 << 8), getRenderer());
					}
					catch(Exception e2)
					{
						videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, getRenderer());
						overlay = false;
					}

					rotate = false;
					trans = Sprite.TRANS_NONE;
				}
			}
		}
		
		if(true) // VideoOptions.scaleImages)
		{
			double pictureAspect = (double)vw / (double)vh;

			if(rotate)
			{
				if(pictureAspect > (1 / aspect))
				{
					dw = maxh;
					dh = (int)(maxh / pictureAspect);
				}
				else
				{
					dw = (int)(w * pictureAspect);
					dh = w;
				}
			}
			else
			{
				if(pictureAspect > aspect)
				{
					dw = w;
					dh = (int)(w / pictureAspect);
				}
				else
				{
					dw = (int)(maxh * pictureAspect);
					dh = maxh;
				}
			}
		}

		//System.out.println("Video rescaled from " + vw + "x" + vh + " to " + dw + "x" + dh);

		if(rotate)
		{
			dw ^= dh;
			dh ^= dw;
			dw ^= dh;
		}

		videoControl.setDisplayLocation((w - dw) / 2, y + (maxh - dh) / 2);
		
		try
		{
			videoControl.setDisplaySize(dw, dh);
		}
		catch(Exception e)
		{
			//ErrScreen.showErrMsg(62, e);
		}
		
		videoControl.setVisible(isshown);
	}

	private void replayVideo()
	{
		long prevtime = player.getMediaTime();

		main.FileSelect.executeFile(playlist, null, runpanel);

		try
		{
			playerPause();
			player.setMediaTime(prevtime);
			playerStart();
		}
		catch(MediaException me)
		{
		}
	}
	
	/**
	 * Функция потока
	 */
	public void run()
	{
		if(wasPaused)
		{
			paused = true;
		}
		else
		{
			playerStart();
		}

		long prevtime = System.currentTimeMillis();
		boolean repaints;
			
		while(running) // цикл
		{
			repaints = false;

			if(System.currentTimeMillis() - prevtime > 300)
			{
				prevtime = System.currentTimeMillis();

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

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

				if(VideoOptions.useAccelerometer)
				{
					final int delta = main.accelerometer.getDelta(0, 1200);

					if(delta != 0)
					{
						Runnable runnable = new Runnable()
						{
							public void run()
							{
								if(delta > 0)
								{
									nextClip();
								}
								else if(delta < 0)
								{
									prevClip();
								}
							}
						};

						(new Thread(runnable, "VideoPlayer/AccelEvent")).start();
					}
				}

				repaints = enableUI;
			}

			if(repaints || keyFlag)
			{
				repaint();
				//serviceRepaints();
			}

			try
			{
				Thread.sleep(60);
			}
			catch(InterruptedException ie)
			{
			}
		}
	}
	
	/**
	 * Обработчик нажатия кнопок
	 *
	 * @param key int
	 */
	public void keyPressed(int key)
	{
		key = rotateKey(translateKey(remapKey(key)), trans);

		if(key == KEY_RSK) // красная - выход
		{
			destroyPlayer();
			wasPaused = false;
			
			// Возврат
			//main.manager.setCurrent(main.FileSelect, runpanel);
			main.manager.ret();

			playlist.cancelSearch();
			playlist = null;

			runpanel = -1;

			if(options.unloadModules)
			{
				instance = null;
			}
		}
		else if(key == KEY_CANCEL) // назад или красная - сворачиваемся
		{
			main.manager.minimizePanel();
		}
		else if(player != null)
		{
			if(key == KEY_LSK || key == KEY_FIRE) // левая софт или зеленая - пауза/воспроизведение
			{
				if(player.getState() == Player.STARTED)
				{
					playerPause();
					wasPaused = true;
				}
				else if(player.getState() == Player.PREFETCHED)
				{
					playerStart();
					wasPaused = false;
				}
			}
			else if(key == KEY_UP) // Volume up
			{
				if(!VideoOptions.muted)
				{
					VideoOptions.volume += 5;

					if(VideoOptions.volume > 100)
					{
						VideoOptions.volume = 100;
					}

					if(volumeControl != null)
					{
						volumeControl.setLevel(VideoOptions.volume);
					}
				}
			}
			else if(key == KEY_DOWN) // Volume down
			{
				if(!VideoOptions.muted)
				{
					VideoOptions.volume -= 5;

					if(VideoOptions.volume < 0)
					{
						VideoOptions.volume = 0;
					}

					if(volumeControl != null)
					{
						volumeControl.setLevel(VideoOptions.volume);
					}
				}
			}
			else if(key == KEY_DIAL) // Mute
			{
				VideoOptions.muted = !VideoOptions.muted;

				if(volumeControl != null)
				{
					volumeControl.setMute(VideoOptions.muted);
				}
			}
			else if(key == KEY_NUM0)
			{
				VideoOptions.shufflePlay = !VideoOptions.shufflePlay;
				(new Thread(videoRedisplayTask, "VideoPlayer/VideoRedisplay")).start();
			}
			else if(key == KEY_POUND)
			{
				enableUI = !enableUI;
				(new Thread(videoRedisplayTask, "VideoPlayer/VideoRedisplay")).start();
			}
			else if(key == KEY_STAR)
			{
				if(true) // rotation)
				{
					if(++VideoOptions.rotateMode > 3)
					{
						VideoOptions.rotateMode = 0;
					}

					replayVideo();
				}
			}
		}
	}
	
	public void keyReleased(int key)
	{
		key = rotateKey(translateKey(remapKey(key)), trans);

		if(keyFlag)
		{
			try
			{
				player.setMediaTime(time);
			}
			catch(MediaException me)
			{
			}

			if(!wasPaused)
			{
				playerStart();
			}

			keyFlag = false;
		}
		else
		{
			if(key == KEY_RIGHT) // следующий звук
			{
				nextClip();
			}
			else if(key == KEY_LEFT) // предыдущий звук
			{
				prevClip();
			}
		}
	}
	
	public void keyRepeated(int keyCode)
	{
		int key = rotateKey(translateKey(remapKey(keyCode)), trans);

		if(key == KEY_RIGHT) // перемотка вперед
		{
			if(!keyFlag)
			{
				if(!wasPaused)
				{
					playerPause();
				}

				keyFlag = true;
			}

			time += tstep;

			if(time > duration)
			{
				time = duration;
			}
		}
		else if(key == KEY_LEFT) // перемотка назад
		{
			if(!keyFlag)
			{
				playerPause();
				keyFlag = true;
			}

			time -= tstep;

			if(time < 0)
			{
				time = 0;
			}
		}
		else
		{
			keyPressed(keyCode);
		}
	}
	
	/**
	 * Уничтожение плеера с предварительным остановом
	 */
	private void destroyPlayer()
	{
		OnlyFileName = Locale.getString(this, Locale.WAIT_PLEASE);
		ofnw = 0;
		ofnx = images.uiTopHSpace;
		ofnstep = 0;

		time = 0;

		running = false;
		
		if(t != null)
		{
			if(t.isAlive())
			{
				try
				{
					t.join();
				}
				catch(InterruptedException ie)
				{
				}
			}
			
			t = null;
		}
		
		if(player != null)
		{
			try
			{
				player.stop();
				player.close();
			}
			catch(Exception e)
			{
				//System.out.println("Cannot stop and exit player");
				//ErrScreen.showErrMsg(100, e);
			}
			
			player = null;
		}

		if(is != null)
		{
			try
			{
				is.close();
			}
			catch(Exception e)
			{
			}

			is = null;
		}

		main.startLightControl(false);
	}
	
	/**
	 * Пауза плеера
	 */
	private void playerPause()
	{
		if(player == null)
		{
			return;
		}
		
		try
		{
			time = player.getMediaTime();
			player.stop();
			paused = true;
			repaint();
		}
		catch(Exception e)
		{
			//System.out.println ("Cannot pause player");
			//e.printStackTrace ();
		}

		main.startLightControl(false);
	}
	
	/**
	 * Запуск плеера
	 */
	private void playerStart()
	{
		if(player == null)
		{
			return;
		}
		
		try
		{
			player.start();

			if(player.getState() == Player.STARTED)
			{
				paused = false;
				repaint();

				main.startLightControl(true);
			}
		}
		catch(Exception e)
		{
			ErrScreen.showErrMsg(63, e);
		}
	}
	
	/**
	 * Перейти к следующему видеофайлу
	 */
	private void nextClip()
	{
		destroyPlayer();
		
		playlist.nextElement(VideoOptions.shufflePlay && !paused);
		main.FileSelect.executeFile(playlist, null, runpanel);
	}
	
	/**
	 * Перейти к предыдущему видеофайлу
	 */
	private void prevClip()
	{
		destroyPlayer();
		
		playlist.prevElement(VideoOptions.shufflePlay && !paused);
		main.FileSelect.executeFile(playlist, null, runpanel);
	}
	
	/**
	 * Скроллинг текста TEXT (кол-во символов COUNT)
	 *
	 * @param text String
	 * @param count int
	 * @return String
	 */
	/*
	private String scrollText(String text, int count)
	{
		String tmp = text;
		int len = text.length();
		int scr = len - count;
		if(len > count)
		{
			tmp = text.substring(scrollPos, scrollPos + count);
			if(scrolldirection)
				scrollPos--;
			else
				scrollPos++;
			if(scrollPos > scr)
			{
				scrollPos--;
				scrolldirection = !scrolldirection;
			}
			else if(scrollPos < 0)
			{
				scrollPos = 0;
				scrolldirection = !scrolldirection;
			}
		}
		return tmp;
	}
	*/
	
//	private static void out(String s)
//	{
//		System.out.println("[cvsVideoPlayer] " + s);
//	}
}