package sim.lib.memory.hex;

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import gjt.BulletinLayout;

import sim.util.DialogButton;
import sim.MainWindow;

public class HexEditor extends Frame implements ActionListener
{	
	private HexArea buffer;
	private ScrollPane scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
	
	private int addressSpace;
	private int addressWidth;
	private int dataWidth;
	
	private String targetFile;
	
	private TextField whereToGo = new TextField(10);
	private DialogButton goTo = new DialogButton("Go to...");
	
	private DialogButton save = new DialogButton("Save");
	private DialogButton reload = new DialogButton("Reload");
	private DialogButton ok = new DialogButton("OK");
	
	private HexEditorParent parent;
	
	public HexEditor(HexEditorParent hep, char[][] content, String fileName, int busSize, int space, Font f, boolean isSimulating)
	{
		super("Memory Content - " + fileName);
		
		this.setLayout(new GridBagLayout());
		this.setBackground(MainWindow.BACKGROUND);
		
		this.parent = hep;
		this.addressSpace = space;
		this.addressWidth = Integer.toHexString(this.addressSpace - 1).length();
		this.dataWidth = Integer.toHexString((int)Math.pow(2, busSize) - 1).length();
		this.targetFile = fileName;
		
		this.goTo.addActionListener(this);
		
		Panel p = new Panel(new FlowLayout(FlowLayout.LEFT, 10, 10));
		p.add(this.goTo);
		p.add(this.whereToGo);
		
		GridBagConstraints c = new GridBagConstraints();
		
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.weightx = 0;
		c.weighty = 0;
		c.insets = new Insets(0, 0, 0, 0);
		c.anchor = GridBagConstraints.WEST;
		c.fill = GridBagConstraints.NONE;
		
		this.add(p, c);
		
		
		c.gridx = 0;
		c.gridy = 1;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.weightx = 1;
		c.weighty = 1;
		c.insets = new Insets(0, 10, 0, 10);
		c.anchor = GridBagConstraints.CENTER;
		c.fill = GridBagConstraints.BOTH;
		
		this.scroller.setBackground(Color.white);
		this.add(this.scroller, c);
		
		this.buffer = new HexArea(f, content, busSize, this.addressSpace, this.scroller, isSimulating);
		TextPanel tp = new TextPanel();
		tp.add(this.buffer);
		this.scroller.add(tp);
		
		p = new Panel(new FlowLayout(FlowLayout.LEFT, 10, 10));
		
		this.save.addActionListener(this);
		this.reload.addActionListener(this);
		this.ok.addActionListener(this);
		
		if(MainWindow.MASTER != null)
			this.save.setEnabled(false);
		
		p.add(this.save);
		p.add(this.reload);
		p.add(this.ok);
		
		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 1;
		c.gridheight = 1;
		c.weightx = 0;
		c.weighty = 0;
		c.insets = new Insets(0, 0, 0, 0);
		c.anchor = GridBagConstraints.EAST;
		c.fill = GridBagConstraints.NONE;
		
		this.add(p, c);
		
		this.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent event)
			{
				parent.respondToClosing();
				setVisible(false);
				dispose();
			}
		});
		
		this.addComponentListener(new ComponentAdapter()
		{
			public void componentResized(ComponentEvent e)
			{
				
				if(getSize().width < 320)
				{
					if(getSize().height < 240)
						setSize(320, 240);
					else
						setSize(320, getSize().height);
				}
				else if(getSize().height < 240)
					setSize(getSize().width, 240);
				else
				{
					if(buffer.needNewBuffer(scroller.getViewportSize().width))
						buffer.paintBakground(scroller.getViewportSize().width);
					
					scroller.validate();
				}
			}
		});
		
		if(isSimulating)
		{
			this.reload.setEnabled(false);
			this.save.setEnabled(false);
		}
	}
	
	public void addNotify()
	{
		super.addNotify();
		this.setSize(530, 450);
	}
	
	public void removeNotify()
	{
		super.removeNotify();
		
		System.gc();
	}
	
	public void actionPerformed(ActionEvent e)
	{
		char[][] content;
		int loop;
		
		if(e.getSource() == this.goTo)
		{
			try
			{
				int where = Integer.valueOf(this.whereToGo.getText(), 16).intValue();
				
				if((where >= 0) && (where < this.addressSpace))
				{
					if(this.reload.isEnabled())
						this.buffer.skipToAddress(where);
					else
						this.buffer.showAddress(where);
					
				}
			}
			catch(NumberFormatException nfe)
			{
			}
		}
		else if(e.getSource() == this.ok)
		{
			this.parent.respondToClosing();
			this.setVisible(false);
			this.dispose();
		}
		else if(e.getSource() == this.reload)
		{
			this.parent.reloadMemory();
			this.buffer.deselectCursor();
			
			this.buffer.repaintBakground();
			this.buffer.paint(this.buffer.getGraphics());
		}
		else if(e.getSource() == this.save)
		{
			try
			{
				BufferedWriter outStream = new BufferedWriter(new FileWriter(this.targetFile));
				
				content = this.buffer.getContent();
				
				for(loop = 0; loop < this.addressSpace; loop++)
					outStream.write(content[loop], 0, this.dataWidth);
				
				outStream.close();
			}
			catch(IOException exc)
			{
				MainWindow.OK_WINDOW.setDescription("Exception occur during saving");
				MainWindow.OK_WINDOW.setMessage(exc.getMessage());
				MainWindow.OK_WINDOW.show();
			}
		}
	}
	
	public void changeParameters(char[][] content, String fileName, int busSize, int space)
	{
		this.setTitle("Memory Content - " + fileName);
		
		this.addressSpace = space;
		this.addressWidth = Integer.toHexString(this.addressSpace - 1).length();
		this.dataWidth = Integer.toHexString((int)Math.pow(2, busSize) - 1).length();
		this.targetFile = fileName;
		
		this.buffer.changeParameters(content, busSize, this.addressSpace);
		this.scroller.validate();
		((TextPanel)this.scroller.getComponent(0)).realUpdate();
	}
	
	public void eliminateHighlights()
	{
		this.buffer.eliminateHighlights();
	}
	
	public void readFrom(int address)
	{
		this.buffer.highlightData(address, Color.black, Color.white);
		this.buffer.showAddress(address);
	}
	
	public void writeTo(int address)
	{
		this.buffer.eliminateHighlights();
//		this.buffer.highlightData(address, Color.red, Color.white);
		this.buffer.showAddress(address);
	}
	
	public void writeToEverywhere()
	{
		this.buffer.eliminateHighlights();
		this.buffer.repaintBakground();
		this.buffer.showAddress(0);
	}
	
	public void prepareForSimulation()
	{
		this.buffer.prepareForSimulation();
		this.reload.setEnabled(false);
		this.save.setEnabled(false);
	}
	
	public void prepareForEditing()
	{
		this.buffer.prepareForEditing();
		
		this.reload.setEnabled(true);
		
		if(MainWindow.MASTER == null)
			this.save.setEnabled(true);
	}
	
/* ======================================================================
	Implement Panel to hold Text
	===================================================================== */
	public class TextPanel extends Panel
	{
		public TextPanel()
		{
			super();
			
			this.setLayout(new BulletinLayout());
		}
		
		public Dimension getPrefferedSize()
		{
			return this.getComponent(0).getSize();
		}
		
		public void update(Graphics g)
		{
		}
		
		public void realUpdate()
		{
			super.update(this.getGraphics());
		}
	}
}