/*************************************************************************************

This file is part of FragMend.

Written by Florian Buchholz, Glenn Henderson, David Horvath, and Jeff Jones.

Copyright (c) 2006, Florian Buchholz, Glenn Henderson, David Horvath, and Jeff Jones.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.     
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.       
    * Neither the name of Florian Buchholz, Glenn Henderson, David Horvath, Jeff
      Jones, nor the names of its contributors may be used to endorse or promote
      products derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*************************************************************************************/

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Insets;

import java.io.File;

import java.lang.String;

import java.util.Enumeration;
import java.util.Vector;

import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;


public class FileView extends JPanel implements ActionListener,ListSelectionListener {

	private JList fragments;
	private DefaultListModel fragments_model;
	
	private JLabel file_name;
	private JComboBox type_field;
	private JButton view_hex;
	private JButton view_ascii;
	private JButton byte_pos;
	private JButton get_size;
	private JButton remove_button;
	private JButton up_button;
	private JButton down_button;
	private JTextField length;
	private JTextField md5sum;
	private JButton get_md5sum;
	private JButton set_size;
	
	private JFileChooser fc;
	
	private AssembledFile currentFile;
	private FragmentView fragmentView;
	
	public FileView(ActionListener parent_listener, FragmentView fv) {
		super();
		
		fc = new JFileChooser(new File(System.getProperty("user.dir")));

		fragmentView = fv;
		
		fragments_model = new DefaultListModel();
		fragments = new JList(fragments_model);
		fragments.setCellRenderer(new FileListCellRenderer());
		fragments.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
		fragments.addListSelectionListener(this);
		
		JPanel topPanel = new JPanel(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.insets = new Insets(5, 5, 5, 5);
		
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 3;
		file_name = new JLabel("File: ", JLabel.LEADING);
		topPanel.add(file_name, c);
		
		c.gridx = 0;
		c.gridy++;
		type_field = new JComboBox();
		for (int i = 0; i <= AssembledFile.TYPE_OFFICE; i++)
			type_field.addItem(AssembledFile.getType(i));
		type_field.setActionCommand("type");
		type_field.addActionListener(this);
		topPanel.add(type_field, c);
		
		c.gridy++;
		c.gridx= 0;
		c.gridwidth = 1;
		get_size = new JButton("Get length");
		get_size.setActionCommand("size");
		get_size.addActionListener(this);
		topPanel.add(get_size, c);

		c.gridx = 1;
		c.gridwidth = 2;
		JPanel size_panel = new JPanel();
		size_panel.setLayout(new BoxLayout(size_panel, BoxLayout.X_AXIS));
		length = new JTextField();
		set_size = new JButton("Set");
		set_size.setActionCommand("setsize");
		set_size.addActionListener(this);
		size_panel.add(length);
		size_panel.add(set_size);
		topPanel.add(size_panel, c);
		
		c.gridy++;
		c.gridx=0;
		c.gridwidth=1;
		get_md5sum = new JButton("Get md5 Sum");
		get_md5sum.setActionCommand("md5sum");
		get_md5sum.addActionListener(this);
		topPanel.add(get_md5sum, c);
		
		c.gridx = 1;
		c.gridwidth = 2;
		md5sum = new JTextField();
		topPanel.add(md5sum, c);
		
		c.gridx = 0;
		c.gridy++;
		c.gridwidth = 1;
		view_hex = new JButton("Hex");
		view_hex.setActionCommand("hex");
		view_hex.addActionListener(this);
		topPanel.add(view_hex, c);

		c.gridx = 1;
		view_ascii = new JButton("Ascii");
		view_ascii.setActionCommand("ascii");
		view_ascii.addActionListener(this);
		topPanel.add(view_ascii, c);

		c.gridx = 2;
		byte_pos = new JButton("Byte pos");
		byte_pos.setActionCommand("byte_pos");
		byte_pos.addActionListener(this);
		topPanel.add(byte_pos, c);


		JPanel contentPane = new JPanel();
		contentPane.add(new JScrollPane(fragments));
		
		JPanel buttonPane = new JPanel();		
		
		up_button = new JButton("Up");
		up_button.setActionCommand("up");
		up_button.addActionListener(parent_listener);
		buttonPane.add(up_button);

		down_button = new JButton("Down");
		down_button.setActionCommand("down");
		down_button.addActionListener(parent_listener);
		buttonPane.add(down_button);

		remove_button = new JButton(">>");
		remove_button.setActionCommand("remove");
		remove_button.addActionListener(parent_listener);
		buttonPane.add(remove_button);

		this.setLayout(new BorderLayout());
		this.add(topPanel, BorderLayout.PAGE_START);
		this.add(new JScrollPane(fragments), BorderLayout.CENTER);
		this.add(buttonPane, BorderLayout.PAGE_END);

	}

	public void displayFile(AssembledFile toDisplay) {
		fragments_model.clear();
		currentFile = toDisplay;
		for (Enumeration<Fragment> frags = toDisplay.getFragments().elements(); frags.hasMoreElements();) {
			fragments_model.addElement(frags.nextElement());
		}
		file_name.setText("File: " + toDisplay.getName() + " (" + fragments_model.getSize() + " Fragments)");
		type_field.setSelectedIndex(currentFile.getType());
		long size = currentFile.getSize();
		if (size != -1)
			length.setText(""+size);
		else
			length.setText("");
		md5sum.setText(""+toDisplay.getMD5sum());
	}

	public void clear() {
		fragments_model.clear();
		currentFile = null;
		file_name.setText("File:");
	}
	
	public AssembledFile getCurrentFile() {
		return currentFile;
	}
	
	public void addFragments(Fragment[] newFragments) {
		
		for (int i = 0; i< newFragments.length; i++) {
			currentFile.addFragment(newFragments[i]);
			fragments_model.addElement(newFragments[i]);
		}
		file_name.setText("File: " + currentFile.getName() + " (" + fragments_model.getSize() + " Fragments)");
	}
	
	public void removeFragments(Fragment[] toRemove) {
				
		for (int i = 0; i< toRemove.length; i++) {
			currentFile.removeFragment(toRemove[i]);
			fragments_model.removeElement(toRemove[i]);
		}
		file_name.setText("File: " + currentFile.getName() + " (" + fragments_model.getSize() + " Fragments)");
	}
	
	public void moveFragmentUp() {
		
		Fragment f = (Fragment)fragments.getSelectedValue();
		int pos = fragments_model.indexOf(f);
		if (pos < 1)
			return;
		fragments_model.remove(pos);
		fragments_model.add(pos-1, f);
		fragments.setSelectedValue(f, true);
		
		currentFile.moveFragmentUp(f);
		
	}
	
	public void moveFragmentDown() {
		
		Fragment f = (Fragment)fragments.getSelectedValue();
		int pos = fragments_model.indexOf(f);
		if (pos < 0 || pos == fragments_model.getSize()-1)
			return;
		fragments_model.remove(pos);
		fragments_model.add(pos+1, f);
		fragments.setSelectedValue(f, true);

		currentFile.moveFragmentDown(f);
		
	}
	
	public Fragment[] getSelected() {
		Object[] values = fragments.getSelectedValues();
		
		Fragment[] ret = new Fragment[values.length];
		for (int i = 0; i < values.length; i++)
			ret[i] = (Fragment)values[i];
		return ret;
	}
	
	public boolean isEmpty() {
		return (fragments_model.getSize() == 0);
	}

	public byte[] getSelectedData() {
		
		Object[] selected = fragments.getSelectedValues();
		byte[] data = new byte[selected.length*FragMend.getSectorSize()];
			
		int position = 0;
		for (int i = 0; i < selected.length; i++) {
			Fragment f = (Fragment)selected[i];
			byte[] f_data = f.getData();
			for (int j = 0; j < f_data.length; j++)
				data[position+j] = f_data[j];
			position += f_data.length;
		}

		return data;
		
	}
	
	public void actionPerformed(ActionEvent e) {
		
		if(e.getActionCommand().equals("hex")) {
			
			
			FragMend.showTextFrame("Hex view: " + currentFile.getName() + " (Selected)", 
						DataUtilities.getHexView(getSelectedData()));
			return;
		}
		else if(e.getActionCommand().equals("ascii")) {
			
			String display = new String();
			Object[] selected = fragments.getSelectedValues();
			
			for (int i = 0; i < selected.length; i++) {
				display += "\n++++++++++++++++++++ " + ((Fragment)selected[i]).getName() + " ++++++++++++++++++++\n";
				display += DataUtilities.getAsciiView(((Fragment)selected[i]).getData(), 0);
			}
			
			FragMend.showTextFrame("Ascii view: " + currentFile.getName(), display);

			return;
		}
		else if(e.getActionCommand().equals("jpg")) {
			FragMend.showPictureFrame("Image view: " + currentFile.getName(), 
						currentFile.getData());
			return;
		}
		else if(e.getActionCommand().equals("byte_pos")) {
			
			String address = (String)JOptionPane.showInputDialog(
				this,
				"Enter byte positon: ",
				"Find byte position",
				JOptionPane.PLAIN_MESSAGE,
				null,
				null,
				"");

			if (address == null)
				return;
				
			Integer posInt;
			
			try {
				posInt = new Integer(address);
			}
			catch (NumberFormatException nfe) {
				return;
			}
			
			int pos = posInt.intValue();
			if (pos < 0)
				return;
			
			int counter = 0;
			
			while (pos > FragMend.getSectorSize()) {
				pos -= FragMend.getSectorSize();
				counter++;
			}
			
			if (counter > fragments.getModel().getSize()) {
				fragments.clearSelection();
				return;
			}
			
			fragments.setSelectedValue(fragments_model.getElementAt(counter), true);

		}
		else if (e.getActionCommand().equals("type")) {
			currentFile.setType(type_field.getSelectedIndex());	
		}
		else if (e.getActionCommand().equals("setsize")) {
			currentFile.setSize(new Integer(length.getText()).intValue());	
		}
		else if (e.getActionCommand().equals("size")) {
			
			int len = -1;
			
			switch (type_field.getSelectedIndex()) {
				
				case AssembledFile.TYPE_JPG:
					len = JPGUtilities.getSize(currentFile.getData());
					break;
				case AssembledFile.TYPE_HTML:
					len = HTMLUtilities.getSize(currentFile.getData());
					break;
				case AssembledFile.TYPE_ZIP:
					len = ZIPUtilities.getSize(currentFile.getData());
					break;
				case AssembledFile.TYPE_OFFICE:
					len = OfficeUtilities.getSize(currentFile.getData());
					break;
				case AssembledFile.TYPE_TEXT:
					len = TextUtilities.getSize(currentFile.getData());
			}
			
			if (len != -1)
				length.setText(""+len);
			else
				length.setText("");
			
			currentFile.setSize(len);
		}
		else if(e.getActionCommand().equals("md5sum")) {
			md5sum.setText(""+currentFile.getMD5sum());
		}
	}

	public void valueChanged(ListSelectionEvent e) {
		if (! e.getValueIsAdjusting()) {
			if (fragments.getSelectedIndex() > -1) {
				fragmentView.displayFragment((Fragment)fragments.getSelectedValue());
			}
		}
				
	}

}

