package modules.mascot;

//#if MascotV3 == "true"

import com.mascotcapsule.micro3d.v3.*;
import com.one.AbstractFont;
import com.one.ExtGraphics;
import com.one.PlayList;
import com.one.SlidingNumber;
import com.one.file.Connector;
import com.one.file.FileConnection;
import com.vmx.AuxClass;
import com.vmx.Locale;
import com.vmx.gkcCanvas;
import filemanager.images;
import filemanager.main;
import filemanager.options;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import javax.microedition.lcdui.*;

/**
 *
 * @author aNNiMON
 */
public class Lib_mcv3 extends gkcCanvas implements Runnable
{
	/**
	 * Номера строк в локали.
	 *
	 * Здесь все номера начинаются с 0 и модуль может считать, что он единственный,
	 * достаточно указать необходимые смещения в файлах offsets.ini и strings.ini
	 */
	public static final int MODEL_INFO = 3;

	private Graphics3D g3 = null;

	private Figure figure;
	private Texture mainTexture;
	private Effect3D effect;
	private AffineTrans viewTrans, modelTrans, tempTrans;
	private ActionTable action;
	private Vector3D Pos, Look, Up;
	private Light light; //Свет
	private Vector3D lightdir; // Позиция источника света
	private int dirIntensity; // ?нтенсивность света
	private int ambIntensity; // ?нтенсивность амбиент света
	private boolean lightEnabled; // использовать ли свет?
	private FigureLayout layout;
	private int centerX, centerY;// центр вывода
	private boolean persEnabled; //использовать перспективу?
	private int persNear, persFar, persAngle;
	private int spinx, spiny, spinz;
	private int scalex, scaley, scalez;
	private int modelx, modely, modelz;
	private int numFrames, frameStep, frame = 0;
	private int w, h;
	private boolean allowKeyRelease = true;
	private boolean moveMode = false;
	private boolean enableUI = true;
	private String OnlyFileName = "";
	private AbstractFont nameFont;
	private boolean animationRunning = false;
	private Thread t;

	private PlayList playlist;
	private int runpanel;

	private static Lib_mcv3 instance;

	public static Lib_mcv3 getInstance()
	{
		if(instance == null)
		{
			instance = new Lib_mcv3();
		}

		return instance;
	}

	public static byte[] getFileData(String filename) throws IOException
	{
		FileConnection fc = (FileConnection)Connector.open("file:///" + filename, Connector.READ);
		byte[] bt = new byte[(int)fc.fileSize()];

		InputStream is = fc.openInputStream();

		int total = 0;
		while((total += is.read(bt, total, bt.length - total)) < bt.length);

		is.close();
		fc.close();

		return bt;
	}

	private class ModelChanger implements Runnable
	{
		private Runnable runnable;
		private int dir;

		public ModelChanger(Runnable runnable, int dir)
		{
			this.runnable = runnable;
			this.dir = dir;
		}

		public void run()
		{
			boolean flag = animationRunning;
			animationRunning = false;

			if(t != null && t.isAlive())
			{
				try
				{
					t.join();
				}
				catch(InterruptedException ie)
				{
				}
			}

			if(dir > 0)
			{
				playlist.nextElement(false);
			}
			else if(dir < 0)
			{
				playlist.prevElement(false);
			}

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

			animationRunning = flag;

			if(animationRunning)
			{
				(t = new Thread(runnable)).start();
			}
		}
	}

	/*
	 * Загрузка
	 * */

	//Текстура
	public void setBMP(byte[] texdata)
	{
		if(texdata != null)
		{
			mainTexture = new Texture(texdata, true);
		}
		else
		{
			mainTexture = null;
		}
	}

	public Lib_mcv3()
	{
		setFullScreenMode(true);

		resetView();

		ambIntensity = 2048;
		dirIntensity = 4096;
		lightdir = new Vector3D(-3511, 731, 878);

		persNear = 1;
		persFar = 4096;
		persAngle = 682;

		Pos = new Vector3D(0, 120, 500);
		Look = new Vector3D(0, 0, -2000);
		Up = new Vector3D(0, 4096, 0);

		centerX = (w = getWidth()) / 2;
		centerY = (h = getHeight()) / 2;

		nameFont = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_PLAIN, AbstractFont.SIZE_SMALL);
	}

	protected void resetView()
	{
		scalex = scaley = scalez = 4096;
		modelx = modely = modelz = 0;
		spinx = spiny = spinz = 0;
	}

	/*
	 * Свет
	 * */
	// Позиция источника света
  /*  public void setLightPos(int x, int y, int z) {
	lightdir = new Vector3D(x, y, z);
	}
	//?нтенсивность света
	public void setLightIntensity(int value) {
	dirIntensity=value;
	}
	//?нтенсивность амбиент света
	public void setAmbLightIntensity(int value) {
	ambIntensity=value;
	}
	public void setLight(boolean light) {
	lightEnabled=light;
	}*/

	/*
	 * FigureLayout
	 * */
	//центр FL
/*   public void setFLCenter(int cx, int cy) {
	centerX=cx;
	centerY=cy;
	}
	//?спользовать ли перспективу
	public void setPerspective(boolean pers) {
	persEnabled=pers;
	}
	// Параметры перспективы
	public void setPersPos(int near, int far, int angle) {
	persNear = near; //коэфициент ближнего угла
	persFar = far; // дальнего угла
	persAngle = angle; // сам угол
	}
	// Параметры увеличения модели
	public void setScaleMDL(int x, int y, int z) {
	scalex=x;
	scaley=y;
	scalez=z;
	}
	// Параметры трансформирования модели
	public void setTransMDL(int x, int y, int z) {
	modelx=x;
	modely=y;
	modelz=z;
	}*/

	/*
	 * Анимация
	 * */
	//Получить кол-во кадров анимации
	protected void nextFrame()
	{
		frame += frameStep;

		if(frame > numFrames)
		{
			frame = numFrames;
		}
	}

	protected void prevFrame()
	{
		frame -= frameStep;

		if(frame < 0)
		{
			frame = 0;
		}
	}

	// Позиция камеры
    /*public void setViewPos(int x, int y, int z) {
	Pos = new Vector3D(x, y, z);
	}
	// Позиция источника света
	public void setViewLook(int x, int y, int z) {
	Look = new Vector3D(x, y, z);
	}
	// Позиция источника света
	public void setViewUp(int x, int y, int z) {
	Up = new Vector3D(x, y, z);
	}*/

	public void init(byte[] mbac, byte[] mtra, String modelName)
	{
		initPanels();

		initPlayList(modelName);

		figure = new Figure(mbac);

		if(mainTexture != null)
		{
			figure.setTexture(mainTexture);
		}

		effect = new Effect3D(null, Effect3D.NORMAL_SHADING, true, null);
		layout = new FigureLayout();
		viewTrans = new AffineTrans();
		modelTrans = new AffineTrans();
		tempTrans = new AffineTrans();
		light = new Light(lightdir, dirIntensity, ambIntensity);

		if(mtra != null)
		{
			action = new ActionTable(mtra);
			numFrames = action.getNumFrames(0);
		}
		else
		{
			action = null;
			numFrames = 0;
		}

		frameStep = numFrames / 100;
		frame = 0;

		g3 = new Graphics3D();

		repaint();
	}

	public void setPlayList(PlayList newlist)
	{
		playlist = newlist;
	}

	public void setPlayList(Enumeration newlist)
	{
		playlist = new PlayList(newlist);
	}

	protected void initPanels()
	{
		if(runpanel < 0)
		{
			runpanel = main.manager.currentPanel();
		}

		main.manager.setCurrent(this, runpanel);
		main.manager.updateAssociation(runpanel, playlist.getCurrentElement());
		main.manager.changePanel(runpanel);
	}

	protected void initPlayList(String file)
	{
		OnlyFileName = file.substring(file.lastIndexOf('/') + 1);

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

		playlist.selectElement(file);
	}

	/**
	 * следующая картинка
	 */
	public void nextModel()
	{
		(new Thread(new ModelChanger(this, 1))).start();
	}

	/**
	 * предыдущая картинка
	 */
	public void prevModel()
	{
		(new Thread(new ModelChanger(this, -1))).start();
	}

	public void paint(ExtGraphics g)
	{
		g.setColor(images.cImgBack);
		g.fillRect(0, 0, w, h);

		drawModel(g.getGraphics());

		if(enableUI)
		{
			if(images.minUI != null)
			{
				g.drawImage(images.minUI, 0, h, Graphics.LEFT | Graphics.BOTTOM);
			}

			g.setFont(nameFont);

			g.setColor(images.cPlayFore1); //0x800000);
			g.drawString(OnlyFileName, w / 2, h - images.uiBottomHeight + images.uiBottomVSpace, Graphics.TOP | Graphics.HCENTER);

			String[] tokens =
			{
				AuxClass.doubleToString(scalex / 4096.0, 2),
				AuxClass.doubleToString(scaley / 4096.0, 2),
				AuxClass.doubleToString(scalez / 4096.0, 2),
				AuxClass.doubleToString(spinx * 360.0 / 4096.0, 0),
				AuxClass.doubleToString(spiny * 360.0 / 4096.0, 0),
				AuxClass.doubleToString(spinz * 360.0 / 4096.0, 0),
				AuxClass.doubleToString(modelx * 100 / 4096.0, 1),
				AuxClass.doubleToString(modely * 100 / 4096.0, 1),
				AuxClass.doubleToString(modelz * 100 / 4096.0, 1),
				frameStep > 0 ? Integer.toString(frame / frameStep) : "0"
			};

			g.setColor(images.cPlayFore2); //0x000080);
			g.drawString(Locale.getString(this, MODEL_INFO, tokens), w / 2, h - images.uiBottomVSpace, Graphics.BOTTOM | Graphics.HCENTER);
		}
	}

	/*
	 * Отрисовка модели
	 * */
	protected void drawModel(Graphics g)
	{
		if(g3 == null)
		{
			return;
		}

		//3D рендеринг
		g3.bind(g);

		if(lightEnabled)
		{
			effect.setLight(light);
		}
		else
		{
			effect.setLight(null);
		}

		if(persEnabled)
		{
			layout.setPerspective(persNear, persFar, persAngle);
		}
		else
		{
			layout.setParallelSize(800, 800);
		}

		layout.setCenter(centerX, centerY);

		modelTrans.setIdentity();
		modelTrans.rotationX(spinx);

		tempTrans.setIdentity();
		tempTrans.rotationY(spiny);
		modelTrans.mul(tempTrans);

		tempTrans.set(scalex, 0, 0, 0, 0, scaley, 0, 0, 0, 0, scalez, 0);
		modelTrans.mul(tempTrans);

		modelTrans.m03 = modelx;
		modelTrans.m13 = modely;
		modelTrans.m23 = modelz;

		viewTrans.lookAt(Pos, Look, Up);
		viewTrans.mul(modelTrans);

		layout.setAffineTrans(viewTrans);

		if(action != null)
		{
			figure.setPosture(action, 0, frame);
		}

		g3.renderFigure(figure, 0, 0, layout, effect);
		g3.flush();

		g3.release(g);
	}

	public void keyReleased(int keyCode)
	{
		keyCode = remapKey(keyCode);

		if(allowKeyRelease)
		{
			handleKeyAction(keyCode);
		}
		else
		{
			allowKeyRelease = true;
		}
	}

	public void keyRepeated(int keyCode)
	{
		keyCode = remapKey(keyCode);

		allowKeyRelease = false;
		handleKeyAction(keyCode);
	}

	public void handleKeyAction(int key)
	{
		/*
		 * Здесь пришлось все-таки нагородить конструкцию из if ... else if ...
		 * потому что switch требует использовать в case константы,
		 * а в gkcCanvas есть и простые переменные вроде KEY_LSK
		 */

		if(key == KEY_RSK)
		{
			animationRunning = false;

			playlist.cancelSearch();
			playlist = null;

			main.manager.ret();
			runpanel = -1;

			if(options.unloadModules)
			{
				instance = null;
			}
		}
		else if(key == KEY_CANCEL)
		{
			animationRunning = false;
			main.manager.minimizePanel();
		}
		else if(key == KEY_LSK || key == KEY_FIRE)
		{
			if(animationRunning)
			{
				animationRunning = false;
			}
			else
			{
				animationRunning = true;
				(t = new Thread(this)).start();
			}
		}
		else if(key == KEY_RIGHT || key == KEY_DOWN)
		{
			nextModel();
		}
		else if(key == KEY_LEFT || key == KEY_UP)
		{
			prevModel();
		}
		else
		{
			if(key == KEY_NUM4)
			{
				if(moveMode)
				{
					modelx += 20;
				}
				else
				{
					spiny -= 40;

					if(spiny < 0)
					{
						spiny += 4096;
					}
				}
			}
			else if(key == KEY_NUM6)
			{
				if(moveMode)
				{
					modelx -= 20;
				}
				else
				{
					spiny += 40;

					if(spiny >= 4096)
					{
						spiny -= 4096;
					}
				}
			}
			else if(key == KEY_NUM2)
			{
				if(moveMode)
				{
					modely -= 20;
				}
				else
				{
					spinx -= 40;

					if(spinx < 0)
					{
						spinx += 4096;
					}
				}
			}
			else if(key == KEY_NUM8)
			{
				if(moveMode)
				{
					modely += 20;
				}
				else
				{
					spinx += 40;

					if(spinx >= 4096)
					{
						spinx -= 4096;
					}
				}
			}
			else if(key == KEY_NUM5)
			{
				resetView();
			}
			else if(key == KEY_STAR)
			{
				moveMode = !moveMode;
			}
			else if(key == KEY_POUND)
			{
				enableUI = !enableUI;
			}
			else if(key == KEY_NUM0)
			{
				lightEnabled = !lightEnabled;
			}
			else if(key == KEY_NUM1)
			{
				int delta = scalex >>> 3;

				if(delta < 1)
				{
					delta = 1;
				}

				scalez = scaley = scalex -= delta; // 196;
			}
			else if(key == KEY_NUM3)
			{
				int delta = scalex >>> 3;

				if(delta < 1)
				{
					delta = 1;
				}

				scalez = scaley = scalex += delta; // 196;
			}
			else if(key == KEY_NUM7)
			{
				prevFrame();
			}
			else if(key == KEY_NUM9)
			{
				nextFrame();
			}

			repaint();
		}
	}

	public void run()
	{
		if(action != null)
		{
			int frameStepSmall = frameStep / 2;

			if(frameStepSmall < 1)
			{
				frameStepSmall = 1;
			}

			while(animationRunning)
			{
				frame += frameStepSmall;

				if(frame > numFrames)
				{
					frame = 0;
				}

				repaint();
				serviceRepaints();

				Thread.yield();
			}
		}
		else
		{
			SlidingNumber slidingSpinX = new SlidingNumber(0, 4096 << 1, spinx, 512, 4096);
			SlidingNumber slidingSpinY = new SlidingNumber(0, 4096 << 1, spiny, 512, 4096);

			while(animationRunning)
			{
				spinx = slidingSpinX.nextValue();
				spiny = slidingSpinY.nextValue();

				repaint();
				serviceRepaints();

				Thread.yield();
			}
		}
	}
}

//#endif