package filemanager;

import com.one.AbstractFont;
import com.one.ExtGraphics;
import javax.microedition.lcdui.*;
import com.vmx.*;

public class MemoryMonitor extends gkcCanvas implements Runnable, CommandListener, HotKeyListener
{
	protected Object parent;

	protected AbstractFont ttlfont, font;
	protected int ttlfnth, fnth;
	
	protected int ttlx, ttly, ttlw, ttlh;
	
	protected Image histogram;
	protected Graphics hgraphics;
	protected int hx, hy, hw, hh;
	protected long[] usedvalues;
	protected long[] totalvalues;
	protected long maxvalue;
	
	protected String usedmem;
	protected int[] umpos = new int[8];
	
	protected String totalmem;
	protected int[] tmpos = new int[8];
	
	protected int width, height;
	protected long delay;
	protected int threshold;
	protected boolean isshown;
	protected long used, total;
	protected boolean offscreen;
	
	protected CommandMenu cmenu;
	
	protected Thread t;
	
	protected Command cmdUpdate, cmdClear, cmdFill, cmdBack;
	
	public MemoryMonitor()
	{
		setFullScreenMode(true);
		
		width = getWidth();
		height = getHeight();
		
		ttlfont = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_PLAIN, AbstractFont.SIZE_MEDIUM);
		font = AbstractFont.getFont(AbstractFont.FACE_SYSTEM, AbstractFont.STYLE_PLAIN, options.largeFontInMenu ? AbstractFont.SIZE_MEDIUM : AbstractFont.SIZE_SMALL);
		
		ttlfnth = ttlfont.getHeight();
		fnth = font.getHeight();
		
		ttlw = ttlfont.stringWidth(Locale.getString(this, Locale.MEMORY_MONITOR)) + ttlfnth;
		ttlh = ttlfnth * 3 / 2;
		ttlx = ttlfnth / 2;
		ttly = (ttlh - ttlfnth) / 2;
		
		cmenu = new CommandMenu(getRenderer(), this, width, height, options.largeFontInMenu ? AbstractFont.SIZE_MEDIUM : AbstractFont.SIZE_SMALL, true, true, true, false, false);
		
		hw = width - ttlfnth;
		hh = height - ttlh - cmenu.getSoftHeight() - ttlfnth * 2 - fnth * 3;
		hx = (width - hw) / 2;
		hy = ttlh + ttlfnth;
		
		histogram = Image.createImage(hw, hh);
		hgraphics = histogram.getGraphics();
		hgraphics.setColor(ColorScheme.colors[ColorScheme.back1]);
		hgraphics.fillRect(0, 0, hw, hh);
		
		usedvalues = new long[hw];
		totalvalues = new long[hw];
		
		usedmem = AuxClass.formatNumber(0);
		totalmem = AuxClass.formatNumber(0);
		
		umpos[0] = hx;
		umpos[1] = hy + hh - 1;
		umpos[2] = hw;
		umpos[3] = fnth * 3 / 2;
		umpos[4] = umpos[0] + fnth / 2;
		umpos[5] = umpos[1] + (umpos[3] - fnth) / 2;
		umpos[7] = umpos[5];
		
		tmpos[0] = umpos[0];
		tmpos[1] = umpos[1] + umpos[3] - 1;
		tmpos[2] = umpos[2];
		tmpos[3] = umpos[3];
		tmpos[4] = umpos[4];
		tmpos[5] = tmpos[1] + (tmpos[3] - fnth) / 2;
		tmpos[7] = tmpos[5];
		
		cmdUpdate = new Command(Locale.getString(this, Locale.UPDATE_CMD), Command.ITEM, 1);
		cmdClear = new Command(Locale.getString(this, Locale.CLEAR_CMD), Command.OK, 2);
		cmdFill = new Command(Locale.getString(this, Locale.FILL_CMD), Command.OK, 3);
		cmdBack = new Command(Locale.getString(this, Locale.BACK_CMD), Command.BACK, 5);
		
		addCommand(cmdUpdate);
		addCommand(cmdClear);
		addCommand(cmdFill);
		addCommand(cmdBack);
		setCommandListener(this);
	}
	
	public void update()
	{
		total = Runtime.getRuntime().totalMemory();
		used = total - Runtime.getRuntime().freeMemory();
		
		if(used > total * threshold / 100)
		{
			System.gc();
			
			total = Runtime.getRuntime().totalMemory();
			used = total - Runtime.getRuntime().freeMemory();
		}
		
		if(isshown || offscreen)
		{
			maxvalue = 1;
			
			for(int i = 1; i < hw; i++)
			{
				usedvalues[i - 1] = usedvalues[i];
				totalvalues[i - 1] = totalvalues[i];
				
				if(usedvalues[i] > maxvalue)
				{
					maxvalue = usedvalues[i];
				}
				
				if(totalvalues[i] > maxvalue)
				{
					maxvalue = totalvalues[i];
				}
			}
			
			usedvalues[hw - 1] = used;
			totalvalues[hw - 1] = total;
			
			if(used > maxvalue)
			{
				maxvalue = used;
			}
			
			if(total > maxvalue)
			{
				maxvalue = total;
			}
			
			if(isshown)
			{
				usedmem = AuxClass.formatNumber(used);
				totalmem = AuxClass.formatNumber(total);
				
				umpos[6] = umpos[0] + umpos[2] - fnth / 2 - font.stringWidth(usedmem);
				tmpos[6] = tmpos[0] + tmpos[2] - fnth / 2 - font.stringWidth(totalmem);
				
				repaint();
			}
		}
	}

	protected void drawHistogram(ExtGraphics g, boolean clear)
	{
		if(clear)
		{
			g.setColor(ColorScheme.colors[ColorScheme.back1]);
			g.fillRect(0, 0, hw, hh);
		}

		g.setColor(ColorScheme.colors[ColorScheme.fore]);

		for(int i = 1; i < hw; i++)
		{
			g.drawLine(i - 1, hh - (int)(usedvalues[i - 1] * (hh - 1) / maxvalue) - 1, i, hh - (int)(usedvalues[i] * (hh - 1) / maxvalue) - 1);
		}

		g.setColor(ColorScheme.colors[ColorScheme.ltborder]);
		g.drawRect(0, 0, hw - 1, hh - 1);
	}
	
	public void paint(ExtGraphics g)
	{
		//g.setColor(ColorScheme.colors[ColorScheme.back1]);
		//g.fillRect(0, 0, width, height);
		
		images.drawVGradient(g, ColorScheme.colors[ColorScheme.back1], ColorScheme.colors[ColorScheme.back2], 0, 0, width, height, options.ditherGradients);
		
		g.setColor(ColorScheme.colors[ColorScheme.fore]);
		g.setFont(ttlfont);
		g.drawString(Locale.getString(this, Locale.MEMORY_MONITOR), ttlx, ttly, Graphics.LEFT | Graphics.TOP);
		
		g.setColor(ColorScheme.colors[ColorScheme.ltborder]);
		g.drawLine(0, ttlh, ttlw, ttlh);
		
		//g.drawImage(histogram, hx, hy, Graphics.LEFT | Graphics.TOP);
		g.translate(hx, hy);
		drawHistogram(g, false);
		g.translate(-hx, -hy);
		g.drawRect(hx, hy, hw - 1, hh - 1);
		
		g.drawRect(umpos[0], umpos[1], umpos[2] - 1, umpos[3] - 1);
		g.drawRect(tmpos[0], tmpos[1], tmpos[2] - 1, tmpos[3] - 1);
		
		g.setColor(ColorScheme.colors[ColorScheme.fore]);
		g.setFont(font);
		
		g.drawString(Locale.getString(this, Locale.USED_MEMORY), umpos[4], umpos[5], Graphics.LEFT | Graphics.TOP);
		g.drawString(Locale.getString(this, Locale.TOTAL_MEMORY), tmpos[4], tmpos[5], Graphics.LEFT | Graphics.TOP);
		
		g.drawString(usedmem, umpos[6], umpos[7], Graphics.LEFT | Graphics.TOP);
		g.drawString(totalmem, tmpos[6], tmpos[7], Graphics.LEFT | Graphics.TOP);
		
		cmenu.paint(g);
	}
	
	public void setDelay(long delay)
	{
		this.delay = delay;
		
		if(t != null && t.isAlive())
		{
			t.interrupt();
		}
		
		if(delay > 0)
		{
			(t = new Thread(this, "MemoryMonitor/Update")).start();
		}
	}
	
	public void setThreshold(int percent)
	{
		if(percent < 0)
		{
			threshold = 0;
		}
		else if(percent <= 100)
		{
			threshold = percent;
		}
		else
		{
			threshold = 100;
		}
	}
	
	public void setOffscreenUpdate(boolean flag)
	{
		offscreen = flag;
	}

	public void show(Object parent)
	{
		this.parent = parent;
		main.dsp.setCurrent(this);
	}
	
	public void showNotify()
	{
		isshown = true;
		update();
	}
	
	public void hideNotify()
	{
		isshown = false;
	}
	
	public void run()
	{
		try
		{
			while(true)
			{
				update();
				Thread.sleep(delay);
			}
		}
		catch(InterruptedException ie)
		{
		}
	}
	
	public void commandAction(Command c, Displayable dp)
	{
		if(c == cmdUpdate)
		{
			update();
		}
		else if(c == cmdClear)
		{
			fontConfig.unloadAll();
			System.gc();
		}
		else if(c == cmdFill)
		{
			AuxClass.allocateMemory(-1, -1);
		}
		else if(c == cmdBack)
		{
			main.dsp.setCurrent(parent);
		}
	}
	
	public void addCommand(Command c)
	{
		cmenu.addCommand(c);
	}
	
	public void removeCommand(Command c)
	{
		cmenu.removeCommand(c);
	}
	
	public void removeAllCommands()
	{
		cmenu.removeAllCommands();
	}
	
	public void setCommandListener(CommandListener cl)
	{
		cmenu.setCommandListener(cl);
	}
	
	public void hotKeyAction(int keyCode)
	{
		if(keyCode == KEY_STAR)
		{
			main.dsp.setCurrent(parent);
		}
	}
	
	public void keyPressed(int keyCode)
	{
		keyCode = remapKey(keyCode);

		if(cmenu.keyPressed(keyCode))
		{
			repaint();
		}
	}
	
	public void keyReleased(int keyCode)
	{
		keyCode = remapKey(keyCode);
		
		if(cmenu.keyReleased(keyCode))
		{
			repaint();
		}
	}
}