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

import java.lang.String;

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

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListModel;

public class FragmentView extends JPanel implements ActionListener,ListSelectionListener {

	private JLabel fragment_name;
	private final String name_text = "Name: ";
	private JLabel fragment_printable;
	private JCheckBox fragment_has_JPG_header;
	private JCheckBox fragment_has_JPG_footer;
	private JLabel fragment_JPG_marker_count;
	private JCheckBox fragment_has_ZIP_header;
	private JCheckBox fragment_has_ZIP_footer;
	private JCheckBox fragment_has_HTML_header;
	private JCheckBox fragment_has_HTML_footer;
	private JCheckBox fragment_has_Office_header;
	private JCheckBox fragment_has_Office_footer;
	private JCheckBox fragment_has_Office_rootdir;
	private JLabel fragment_bracket_count;
	private JLabel fragment_sequence_count;
	private JLabel fragment_count;
	private JLabel label_start_marker;
	private JLabel label_end_marker;
	
	private JList fragments;
	private FragmentListModel fragments_model;
	
	private JButton assign_button;
	private JButton new_button;
	private JButton vhex_button;
	private JButton vascii_button;
	
	private Fragment currentFragment;
	private Fragment start_marker;
	private Fragment end_marker;
	
	public FragmentView(ActionListener parent_listener) {
		super();
		
		JPanel listPane = new JPanel();
		listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
		
		fragments_model = new FragmentListModel();
		fragments = new JList(fragments_model);
		fragments.addListSelectionListener(this);
		
		listPane.add(new JScrollPane(fragments));
		
		fragment_count = new JLabel("Sector count:");
		listPane.add(fragment_count);
		
		label_start_marker = new JLabel("Mark start:");
		listPane.add(label_start_marker);
		start_marker = null;
		
		label_end_marker = new JLabel("Mark end:");
		listPane.add(label_end_marker);
		end_marker = null;
		
		JPanel displayPane = new JPanel(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		
		c.fill = GridBagConstraints.HORIZONTAL;
		c.insets = new Insets(5, 5, 5, 5);
		
		c.gridy = 0;

		c.gridx = 0;
//		displayPane.add(new JLabel("Fragment: ", JLabel.TRAILING), c);
		fragment_name = new JLabel(name_text);
//		c.gridx = 1;
		displayPane.add(fragment_name, c);
//		JLabel filler = new JLabel("MMMMMMMM");
		c.gridx = 1;
		Dimension filler = new Dimension(50, 1);
		displayPane.add(new Box.Filler(filler, filler, filler), c);
//		filler.setVisible(false);
		
		fragment_has_JPG_header = new JCheckBox("Contains JPG header");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_JPG_header, c);
		
		fragment_has_JPG_footer = new JCheckBox("Contains JPG footer");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_JPG_footer, c);
		
		c.gridx = 0;
		c.gridy++;
		displayPane.add(new JLabel("JPG Data Markers: "), c);
		fragment_JPG_marker_count = new JLabel();
		c.gridx = 1;
		displayPane.add(fragment_JPG_marker_count, c);
				
		fragment_has_ZIP_header = new JCheckBox("Contains PKZip header");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_ZIP_header, c);
		
		fragment_has_ZIP_footer = new JCheckBox("Contains PKZip footer");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_ZIP_footer, c);
		
		fragment_has_HTML_header = new JCheckBox("Contains HTML header");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_HTML_header, c);
		
		fragment_has_HTML_footer = new JCheckBox("Contains HTML footer");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_HTML_footer, c);
		
		fragment_has_Office_header = new JCheckBox("Contains Office header");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_Office_header, c);
		
		fragment_has_Office_footer = new JCheckBox("Contains Office footer");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_Office_footer, c);
		
		fragment_has_Office_rootdir = new JCheckBox("Contains Office root directory");
		c.gridx = 0;
		c.gridy++;
		displayPane.add(fragment_has_Office_rootdir, c);
		
		c.gridx = 0;
		c.gridy++;
		displayPane.add(new JLabel("Printable characters: "), c);		
		fragment_printable = new JLabel();
		c.gridx = 1;
		displayPane.add(fragment_printable, c);
		
		c.gridx = 0;
		c.gridy++;
		displayPane.add(new JLabel("Bracket count: "), c);
		fragment_bracket_count = new JLabel();
		c.gridx = 1;
		displayPane.add(fragment_bracket_count, c);
				
		c.gridx = 0;
		c.gridy++;
		displayPane.add(new JLabel("Max 32-bit number sequence: "), c);
		fragment_sequence_count = new JLabel();
		c.gridx = 1;
		displayPane.add(fragment_sequence_count, c);
				
		JPanel buttonPane = new JPanel();
		
//		fragment_count = new JLabel("Sector count:");
//		buttonPane.add(fragment_count);
		
		assign_button = new JButton("<<");
		assign_button.setActionCommand("assign");
		assign_button.addActionListener(parent_listener);
		assign_button.setEnabled(false);
		buttonPane.add(assign_button);
		
		new_button = new JButton("New File");
		new_button.setActionCommand("new");
		new_button.addActionListener(parent_listener);
		new_button.setEnabled(false);
		buttonPane.add(new_button);
		
		vhex_button = new JButton("View Hex");
		vhex_button.setActionCommand("hex");
		vhex_button.addActionListener(this);
		vhex_button.setEnabled(false);
		buttonPane.add(vhex_button);		
		
		vascii_button = new JButton("View Ascii");
		vascii_button.setActionCommand("ascii");
		vascii_button.addActionListener(this);
		vascii_button.setEnabled(false);
		buttonPane.add(vascii_button);		
		
		JPanel contentPane = new JPanel(new GridLayout(1,2));
//		contentPane.add(new JScrollPane(fragments));
		contentPane.add(listPane);
		contentPane.add(displayPane);
		
		this.setLayout(new BorderLayout());
		this.add(contentPane, BorderLayout.CENTER);
		this.add(buttonPane, BorderLayout.PAGE_END);
	}
	
	public void displayFragment(Fragment toDisplay) {
	
		fragment_name.setText(name_text + toDisplay.getName());
		fragment_has_JPG_header.setSelected(toDisplay.containsJPGHeader());
		fragment_has_JPG_footer.setSelected(toDisplay.containsJPGFooter());
		fragment_JPG_marker_count.setText(Integer.toString(toDisplay.getJPGMarkerCount()));
		fragment_has_ZIP_header.setSelected(toDisplay.containsZIPHeader());
		fragment_has_ZIP_footer.setSelected(toDisplay.containsZIPFooter());
		fragment_has_HTML_header.setSelected(toDisplay.containsHTMLHeader());
		fragment_has_HTML_footer.setSelected(toDisplay.containsHTMLFooter());
		fragment_has_Office_header.setSelected(toDisplay.containsOfficeHeader());
		fragment_has_Office_footer.setSelected(toDisplay.containsOfficeFooter());
		fragment_has_Office_rootdir.setSelected(toDisplay.containsOfficeRootDirectory());
		fragment_printable.setText(Integer.toString(toDisplay.getPrintableCount()));
		fragment_bracket_count.setText(Integer.toString(toDisplay.getBracketCount()));
		fragment_sequence_count.setText(Integer.toString(toDisplay.getSequenceCount()));
		
	}
	
	public void clearDisplay() {
	
		fragment_name.setText(name_text);
		fragment_has_JPG_header.setSelected(false);
		fragment_has_JPG_footer.setSelected(false);
		fragment_JPG_marker_count.setText("");
		fragment_has_ZIP_header.setSelected(false);
		fragment_has_ZIP_footer.setSelected(false);
		fragment_has_HTML_header.setSelected(false);
		fragment_has_HTML_footer.setSelected(false);
		fragment_has_Office_header.setSelected(false);
		fragment_has_Office_footer.setSelected(false);
		fragment_has_Office_rootdir.setSelected(false);
		fragment_printable.setText("");
		fragment_bracket_count.setText("");
		fragment_sequence_count.setText("");
		
	}
	
	public void clear() {
		
		clearDisplay();
		fragments_model.clear();
		clearFilters();
		fragments.repaint(fragments.getVisibleRect());
	}
	
	public Vector<Fragment> getFragments() {
		Vector<Fragment> ret = new Vector<Fragment>();
		for (int i = 0; i < fragments_model.getSize(); i++)
			ret.add((Fragment)fragments_model.getElementAt(i));
		return ret;	
	}
	
	public void setListData(Vector<Fragment> newFragments) {
		/*
		for (Enumeration<Fragment> frags = newFragments.elements(); frags.hasMoreElements();) {
			fragments_model.addElement(frags.nextElement());
		}
		*/
		fragments_model.setElements(newFragments);
//		fragments.setModel(new FilteredFragmentListModel(fragments_model, new FragmentFilter()));
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public void addFilter(FragmentFilter filter) {
		fragments.setModel(new FilteredFragmentListModel((AbstractFragmentListModel)fragments.getModel(), filter));
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public void removeFilter() {
		ListModel m = fragments.getModel();
		if (m instanceof FilteredFragmentListModel) {
			Object[] selected = fragments.getSelectedValues();
			fragments.setModel(((FilteredFragmentListModel)m).getDelegate());			
			for (int i = 0; i < selected.length; i++) {
				fragments.setSelectedValue(selected[i], true);
			}
		}
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public void clearFilters() {
		fragments.setModel(fragments_model);
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	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 void setStartMarker() {
		start_marker = currentFragment;
		label_start_marker.setText("Mark start: " + currentFragment.getName());
	}
	
	public void setEndMarker() {
		end_marker = currentFragment;
		label_end_marker.setText("Mark end: " + currentFragment.getName());		
	}
	
	public void clearMarkers() {
		start_marker = null;
		label_start_marker.setText("Mark start:");
		end_marker = null;
		label_end_marker.setText("Mark end:");
	}
	
	public void selectMarkers() {
		
		int start;
		int end;
		
		if (start_marker == null)
			start = 0;
		else
			start = ((AbstractFragmentListModel)fragments.getModel()).getPosition(start_marker);

		if (end_marker == null)
			end = fragments.getModel().getSize()-1;
		else
			end = ((AbstractFragmentListModel)fragments.getModel()).getPosition(end_marker);
		
		
		
		/*
		if (start > end) {
			int tmp = start;
			start = end;
			end = tmp;
		}
		*/
		fragments.setSelectionInterval(start, end);
		
	}
	
	public void addFragment(Fragment newFragment) {
		((AbstractFragmentListModel)fragments.getModel()).addElement(newFragment, true);
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public void addFragments(Fragment[] newFragments) {
		for (int i = 0; i < newFragments.length; i++)
			((AbstractFragmentListModel)fragments.getModel()).addElement(newFragments[i], false);
		fragments.repaint(fragments.getVisibleRect());
		ListModel lf = fragments.getModel();
		fragments.setModel(new DefaultListModel());
		fragments.setModel(lf);
		fragments.clearSelection();
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public void removeFragment(Fragment toRemove) {
		((AbstractFragmentListModel)fragments.getModel()).removeElement(toRemove, true);
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public void removeFragments(Fragment[] toRemove) {
		for (int i = 0; i < toRemove.length; i++)
			((AbstractFragmentListModel)fragments.getModel()).removeElement(toRemove[i], false);
		fragments.repaint(fragments.getVisibleRect());
		ListModel lf = fragments.getModel();
		fragments.setModel(new DefaultListModel());
		fragments.setModel(lf);
		fragments.clearSelection();
		fragment_count.setText("Sector count: " + fragments.getModel().getSize());
	}
	
	public boolean findNextFragment(FragmentFilter filter) {
		
		int current_pos = fragments.getLeadSelectionIndex();
		if (current_pos == -1)
			current_pos = 0;
		
		ListModel m = fragments.getModel();
		
		for (int i = current_pos+1; i < m.getSize(); i++) {
			Fragment f = (Fragment)m.getElementAt(i);
			if (filter.passes(f)) {
				fragments.setSelectedValue(f, true);
				return true;
			}
		}
		
		for (int i = 0; i < current_pos; i++) {
			Fragment f = (Fragment)m.getElementAt(i);
			if (filter.passes(f)) {
				fragments.setSelectedValue(f, true);
				return true;
			}
		}
		
		return false;
		
	}
	
	public boolean findPreviousFragment(FragmentFilter filter) {
		
		int current_pos = fragments.getLeadSelectionIndex();
		if (current_pos == -1)
			current_pos = 0;
		
		ListModel m = fragments.getModel();
		
		for (int i = current_pos-1; i >= 0; i--) {
			Fragment f = (Fragment)m.getElementAt(i);
			if (filter.passes(f)) {
				fragments.setSelectedValue(f, true);
				return true;
			}
		}
		
		for (int i = m.getSize()-1; i > current_pos; i--) {
			Fragment f = (Fragment)m.getElementAt(i);
			if (filter.passes(f)) {
				fragments.setSelectedValue(f, true);
				return true;
			}
		}
		
		return false;
		
	}
	
	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand().equals("hex")) {
			FragMend.showTextFrame("Hex view: " + currentFragment.getName(), 
						DataUtilities.getHexView(currentFragment.getData()));
			return;
		}
		else if(e.getActionCommand().equals("ascii")) {
			FragMend.showTextFrame("Ascii view: " + currentFragment.getName(), 
						DataUtilities.getAsciiView(currentFragment.getData(), 0));
			return;
		}
	}
	
	public void valueChanged(ListSelectionEvent e) {
		if (! e.getValueIsAdjusting()) {
			if (fragments.getSelectedIndex() == -1) {
				assign_button.setEnabled(false);
				new_button.setEnabled(false);
				vhex_button.setEnabled(false);
				vascii_button.setEnabled(false);
			}
			else {
				assign_button.setEnabled(true);
				new_button.setEnabled(true);
				vhex_button.setEnabled(true);
				vascii_button.setEnabled(true);
//				currentFragment = (Fragment) fragments.getSelectedValue();
				currentFragment = (Fragment) fragments.getModel().getElementAt(fragments.getLeadSelectionIndex());
				displayFragment(currentFragment);
			}
		}
				
	}
}

