/**
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info:  http://www.jpedal.org
* (C) Copyright 1997-2008, IDRsolutions and Contributors.
*
* 	This file is part of JPedal
*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


*
* ---------------
* SwingSearchWindow.java
* ---------------
*/
package org.jpedal.examples.simpleviewer.gui.swing;

import java.awt.BorderLayout;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.jpedal.PdfDecoder;
import org.jpedal.examples.simpleviewer.Values;
import org.jpedal.examples.simpleviewer.SimpleViewer;
import org.jpedal.examples.simpleviewer.gui.SwingGUI;
import org.jpedal.examples.simpleviewer.gui.generic.GUISearchWindow;
import org.jpedal.exception.PdfException;
import org.jpedal.grouping.DefaultSearchListener;
import org.jpedal.grouping.PdfGroupingAlgorithms;
import org.jpedal.grouping.SearchListener;
import org.jpedal.grouping.SearchType;
import org.jpedal.objects.PdfPageData;
import org.jpedal.utils.Messages;
import org.jpedal.utils.SwingWorker;
import org.jpedal.utils.repositories.Vector_Rectangle;
                                    
/**provides interactive search Window and search capabilities*/
public class SwingSearchWindow extends JFrame implements GUISearchWindow{

	public static int SEARCH_EXTERNAL_WINDOW = 0;
	public static int SEARCH_TABBED_PANE = 1;
	public static int SEARCH_MENU_BAR = 2;

	private boolean backGroundSearch = false;
	
	int style = 0;

	/**flag to stop multiple listeners*/
	private boolean isSetup=false;

    boolean usingMenuBarSearch=false;

    int lastPage=-1;

	String defaultMessage="Search PDF Here";

	JProgressBar progress = new JProgressBar(0,100);
	int pageIncrement = 0;
	JTextField searchText=null;
	JTextField searchCount;
	DefaultListModel listModel;
	SearchList resultsList;
	JLabel label = null;

	private JPanel advancedPanel;
	private JComboBox searchType;
	private JCheckBox wholeWordsOnlyBox, caseSensitiveBox, multiLineBox, highlightAll, searchAll;
	
	public void setWholeWords(boolean wholeWords){
		wholeWordsOnlyBox.setSelected(wholeWords);
	}
	
	public void setCaseSensitive(boolean caseSensitive){
		caseSensitiveBox.setSelected(caseSensitive);
	}
	
	public void setMultiLine(boolean multiLine){
		multiLineBox.setSelected(multiLine);
	}
	
	public void setHighlightAll(boolean highlightAllOnPage){
		highlightAll.setSelected(highlightAllOnPage);
	}
	
	ActionListener AL=null;
	ListSelectionListener LSL = null;
	WindowListener WL;
	KeyListener KL;

	/**swing thread to search in background*/
	SwingWorker searcher=null;

	/**flag to show searching taking place*/
	public boolean isSearch=false;
	
	public boolean requestInterupt=false;

	JButton searchButton=null;

	/**number fo search items*/
	private int itemFoundCount=0;

	/**used when fiding text to highlight on page*/
	Map textPages=new HashMap();
	Map textRectangles=new HashMap();

	/**Current Search value*/
	String[] searchTerms = {""};
	
	/**Search this page only*/
	boolean singlePageSearch = false;
	
	final JPanel nav=new JPanel();

	Values commonValues;
	SwingGUI currentGUI;
	PdfDecoder decode_pdf;
	
	int searchTypeParameters = SearchType.DEFAULT;
	
	int firstPageWithResults = 0;
	
	/**deletes message when user starts typing*/
	private boolean deleteOnClick;

	public SwingSearchWindow(SwingGUI currentGUI) {
		this.currentGUI=currentGUI;
		this.setName("searchFrame");
	}


	public Component getContentPanel(){
		return getContentPane();
	}
	
	public boolean isSearching(){
		return isSearch;
	}
	
	public void init(final PdfDecoder dec, final Values values){
		
		this.decode_pdf = dec;
		this.commonValues = values;
		
		if(isSetup){ //global variable so do NOT reinitialise
			searchCount.setText(Messages.getMessage("PdfViewerSearch.ItemsFound")+ ' ' +itemFoundCount);
			searchText.selectAll();
			searchText.grabFocus();
		}else{
			isSetup=true;

			setTitle(Messages.getMessage("PdfViewerSearchGUITitle.DefaultMessage"));

			defaultMessage=Messages.getMessage("PdfViewerSearchGUI.DefaultMessage");

			searchText=new JTextField(defaultMessage);
			searchText.setName("searchText");

			searchButton=new JButton(Messages.getMessage("PdfViewerSearch.Button"));

			advancedPanel = new JPanel(new GridBagLayout());

			searchType = new JComboBox(new String[] {"Match Exact word or phrase", 
			"Match Any of the words"});

			wholeWordsOnlyBox = new JCheckBox("Whole words only");
			wholeWordsOnlyBox.setName("wholeWords");

			caseSensitiveBox = new JCheckBox("Case-Sensitive");
			caseSensitiveBox.setName("caseSensitive");

			multiLineBox = new JCheckBox("Include split line results");
			multiLineBox.setName("multiLine");
			
			highlightAll = new JCheckBox("Highlight all results");
			highlightAll.setName("highlightAll");

			searchType.setName("combo");

			GridBagConstraints c = new GridBagConstraints();

			advancedPanel.setPreferredSize(new Dimension(advancedPanel.getPreferredSize().width, 150));
			c.gridx = 0;
			c.gridy = 0;

			c.anchor = GridBagConstraints.PAGE_START;
			c.fill = GridBagConstraints.HORIZONTAL; 

			c.weightx = 1;
			c.weighty = 0;
			advancedPanel.add(new JLabel("Return results containing:"), c);

			c.insets = new Insets(5,0,0,0);
			c.gridy = 1;
			advancedPanel.add(searchType, c);

			c.gridy = 2;
			advancedPanel.add(new JLabel("Use these additional criteria:"), c);

			c.insets = new Insets(0,0,0,0);
			c.gridy = 3;
			advancedPanel.add(wholeWordsOnlyBox, c);

			c.gridy = 4;
			advancedPanel.add(caseSensitiveBox, c);

			c.weighty = 1;
			c.gridy = 5;
			advancedPanel.add(multiLineBox, c);
			
			c.weighty = 1;
			c.gridy = 6;
			advancedPanel.add(highlightAll, c);

			advancedPanel.setVisible(false);

			nav.setLayout(new BorderLayout());

			WL = new WindowListener(){
				public void windowOpened(WindowEvent arg0) {}

				//flush objects on close
				public void windowClosing(WindowEvent arg0) {

					removeSearchWindow(true);
				}

				public void windowClosed(WindowEvent arg0) {}

				public void windowIconified(WindowEvent arg0) {}

				public void windowDeiconified(WindowEvent arg0) {}

				public void windowActivated(WindowEvent arg0) {}

				public void windowDeactivated(WindowEvent arg0) {}
			};

			this.addWindowListener(WL);

			nav.add(searchButton,BorderLayout.EAST);

			nav.add(searchText,BorderLayout.CENTER);

			searchAll=new JCheckBox();
			searchAll.setSelected(true);
			searchAll.setText(Messages.getMessage("PdfViewerSearch.CheckBox"));

			JPanel topPanel = new JPanel();
			topPanel.setLayout(new BorderLayout());
			topPanel.add(searchAll, BorderLayout.NORTH);

			label = new JLabel("<html><center> " + "Show Advanced");
			label.setForeground(Color.blue);
			label.setName("advSearch");

			label.addMouseListener(new MouseListener() {
				boolean isVisible = false;

				String text = "Show Advanced";

				public void mouseEntered(MouseEvent e) {
					nav.setCursor(new Cursor(Cursor.HAND_CURSOR));
					label.setText("<html><center><a href=" + text + ">" + text + "</a></center>");
				}

				public void mouseExited(MouseEvent e) {
					nav.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
					label.setText("<html><center>" + text);
				}

				public void mouseClicked(MouseEvent e) {
					if (isVisible) {
						text = "Show Advanced";
						label.setText("<html><center><a href=" + text + ">" + text + "</a></center>");
						advancedPanel.setVisible(false);
					} else {
						text = "Hide Advanced";
						label.setText("<html><center><a href=" + text + ">" + text + "</a></center>");
						advancedPanel.setVisible(true);
					}

					isVisible = !isVisible;
				}

				public void mousePressed(MouseEvent e) {}
				public void mouseReleased(MouseEvent e) {}
			});

			label.setBorder(BorderFactory.createEmptyBorder(3, 4, 4, 4));
			topPanel.add(label, BorderLayout.SOUTH);
			//			nav.

			nav.add(topPanel,BorderLayout.NORTH);
			itemFoundCount=0;
			textPages.clear();
			textRectangles.clear();
			listModel = null;

			searchCount=new JTextField(Messages.getMessage("PdfViewerSearch.ItemsFound")+ ' ' +itemFoundCount);
			searchCount.setEditable(false);
			nav.add(searchCount,BorderLayout.SOUTH);

			listModel = new DefaultListModel();
			resultsList=new SearchList(listModel,textPages, textRectangles);
			resultsList.setName("results");

			//<link><a name="search" />
			/**
			 * highlight text on item selected
			 */
			LSL = new ListSelectionListener(){
				public void valueChanged(ListSelectionEvent e) {
					/** 
					 * Only do something on mouse button up,
					 * prevents this code being called twice
					 * on mouse click
					 */
					if (!e.getValueIsAdjusting()) {

						if(!commonValues.isProcessing()){//{if (!event.getValueIsAdjusting()) {

							float scaling=currentGUI.getScaling();
							//int inset=currentGUI.getPDFDisplayInset();

							int id=resultsList.getSelectedIndex();

							decode_pdf.clearHighlights();
							//System.out.println("clicked pdf = "+decode_pdf.getClass().getName() + "@" + Integer.toHexString(decode_pdf.hashCode()));

							if(id!=-1){

								Integer key=new Integer(id);
								Object newPage=textPages.get(key);

								if(newPage!=null){
									int nextPage=((Integer)newPage).intValue();


									//move to new page
									if(commonValues.getCurrentPage()!=nextPage){

										commonValues.setCurrentPage(nextPage);

										currentGUI.resetStatusMessage(Messages.getMessage("PdfViewer.LoadingPage")+ ' ' +commonValues.getCurrentPage());

										/**reset as rotation may change!*/
										decode_pdf.setPageParameters(scaling, commonValues.getCurrentPage());

										//decode the page
										currentGUI.decodePage(false);

										decode_pdf.invalidate();
									}

									while(commonValues.isProcessing()){
										//Ensure page has been processed else highlight may be incorrect
                                        try {
                                            Thread.sleep(500);
                                        } catch (InterruptedException ee) {
                                            ee.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                                        }
									}



									/**
									 * Highlight all search results on page.
									 */
									if((searchTypeParameters & SearchType.HIGHLIGHT_ALL_RESULTS)== SearchType.HIGHLIGHT_ALL_RESULTS){

//										PdfHighlights.clearAllHighlights(decode_pdf);
										Rectangle[] showAllOnPage;
										Vector_Rectangle storageVector = new Vector_Rectangle();
										int lastPage = -1;
										for(int k=0; k!=resultsList.getModel().getSize(); k++){
											Object page=textPages.get(new Integer(k));

											if(page!=null){

												int currentPage = ((Integer)page).intValue();
												if(currentPage!=lastPage){
													storageVector.trim();
													showAllOnPage = storageVector.get();
													
													for(int p=0; p!=showAllOnPage.length; p++){
						                    			System.out.println(showAllOnPage[p]);
						                    		}
													
													decode_pdf.addHighlights(showAllOnPage, true, lastPage);
													lastPage = currentPage;
													storageVector = new Vector_Rectangle();
												}

												Object highlight= textRectangles.get(new Integer(k));

												if(highlight instanceof Rectangle){
													storageVector.addElement((Rectangle)highlight);
												}
												if(highlight instanceof Rectangle[]){
													Rectangle[] areas = (Rectangle[])highlight;
													for(int i=0; i!=areas.length; i++){
														storageVector.addElement(areas[i]);
													}
												}
												//decode_pdf.addToHighlightAreas(decode_pdf, storageVector, currentPage);
//												}
											}
										}
										storageVector.trim();
										showAllOnPage = storageVector.get();
										
										decode_pdf.addHighlights(showAllOnPage, true, lastPage);
									}else{
//										PdfHighlights.clearAllHighlights(decode_pdf);
										Object page=textPages.get(key);
										int currentPage = ((Integer)page).intValue();
										
										Vector_Rectangle storageVector = new Vector_Rectangle();
										Rectangle scroll = null;
										Object highlight= textRectangles.get(key);
										if(highlight instanceof Rectangle){
											storageVector.addElement((Rectangle)highlight);
											scroll=(Rectangle)highlight;
										}
										
										if(highlight instanceof Rectangle[]){
											Rectangle[] areas = (Rectangle[])highlight;
											scroll=areas[0];
											for(int i=0; i!=areas.length; i++){
												storageVector.addElement(areas[i]);
											}
										}
										decode_pdf.scrollRectToHighlight(scroll,currentPage);
										storageVector.trim();
										decode_pdf.addHighlights(storageVector.get(), true, currentPage);
										//PdfHighlights.addToHighlightAreas(decode_pdf, storageVector, currentPage);
										
									}

									decode_pdf.invalidate();
									decode_pdf.repaint();
									currentGUI.zoom(false);
								}
							}
						}

						//When page changes make sure only relevant navigation buttons are displayed
						if(commonValues.getCurrentPage()==1)
							currentGUI.setBackNavigationButtonsEnabled(false);
						else
							currentGUI.setBackNavigationButtonsEnabled(true);

						if(commonValues.getCurrentPage()==decode_pdf.getPageCount())
							currentGUI.setForwardNavigationButtonsEnabled(false);
						else
							currentGUI.setForwardNavigationButtonsEnabled(true);


					}else{
						resultsList.repaint();

					}
				}
			};

			resultsList.addListSelectionListener(LSL);
			resultsList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);

			//setup searching
			//if(AL==null){
			AL = new ActionListener(){
				public void actionPerformed(ActionEvent e) {

					if(!isSearch){

						try {
							searchTypeParameters = SearchType.DEFAULT;

							if(wholeWordsOnlyBox.isSelected())
								searchTypeParameters |= SearchType.WHOLE_WORDS_ONLY;

							if(caseSensitiveBox.isSelected())
								searchTypeParameters |= SearchType.CASE_SENSITIVE;

							if(multiLineBox.isSelected())
								searchTypeParameters |= SearchType.MUTLI_LINE_RESULTS;
							
							if(highlightAll.isSelected())
								searchTypeParameters |= SearchType.HIGHLIGHT_ALL_RESULTS;
							
							String textToFind = searchText.getText().trim();
							if(searchType.getSelectedIndex() == 0){ // find exact word or phrase
								searchTerms = new String[] { textToFind };
							} else { // match any of the words
								searchTerms = textToFind.split(" ");
								for (int i = 0; i < searchTerms.length; i++) {
									searchTerms[i] = searchTerms[i].trim();
								}
							}
							
							singlePageSearch = !searchAll.isSelected();
							
							searchText();
						} catch (Exception e1) {
							e1.printStackTrace();
						}
					}else{
						requestInterupt = true;
						//searcher.interrupt();
						isSearch=false;
						searchButton.setText(Messages.getMessage("PdfViewerSearch.Button"));
					}
				}
			};

			searchButton.addActionListener(AL);
			//}

			searchText.selectAll();
			deleteOnClick=true;

			KL = new KeyListener(){
				public void keyTyped(KeyEvent e) {
					if(searchText.getText().length() == 0){
						currentGUI.nextSearch.setVisible(false);
						currentGUI.previousSearch.setVisible(false);
					}

					//clear when user types
					if(deleteOnClick){
						deleteOnClick=false;
						searchText.setText("");
					}
					int id = e.getID();
					if (id == KeyEvent.KEY_TYPED) {
						char key=e.getKeyChar();

						if(key=='\n'){

							if(!decode_pdf.isOpen()){
								currentGUI.showMessageDialog("File must be open before you can search.");
							}else{
								try {
									currentGUI.nextSearch.setVisible(true);
									currentGUI.previousSearch.setVisible(true);

									currentGUI.nextSearch.setEnabled(false);
									currentGUI.previousSearch.setEnabled(false);

									isSearch=false;
									searchTypeParameters = SearchType.DEFAULT;

									if(wholeWordsOnlyBox.isSelected())
										searchTypeParameters |= SearchType.WHOLE_WORDS_ONLY;

									if(caseSensitiveBox.isSelected())
										searchTypeParameters |= SearchType.CASE_SENSITIVE;

									if(multiLineBox.isSelected())
										searchTypeParameters |= SearchType.MUTLI_LINE_RESULTS;
									
									if(highlightAll.isSelected())
										searchTypeParameters |= SearchType.HIGHLIGHT_ALL_RESULTS;
									
									String textToFind = searchText.getText().trim();
									if(searchType.getSelectedIndex() == 0){ // find exact word or phrase
										searchTerms = new String[] { textToFind };
									} else { // match any of the words
										searchTerms = textToFind.split(" ");
										for (int i = 0; i < searchTerms.length; i++) {
											searchTerms[i] = searchTerms[i].trim();
										}
									}
									
									singlePageSearch = !searchAll.isSelected();
									
									
									searchText();
								} catch (Exception e1) {
									e1.printStackTrace();
								}
							}
						}
					}
				}

				public void keyPressed(KeyEvent arg0) {}

				public void keyReleased(KeyEvent arg0) {}
			};

			searchText.addKeyListener(KL);
			if(style==SEARCH_EXTERNAL_WINDOW || style==SEARCH_TABBED_PANE){
				//build frame
				JScrollPane scrollPane=new JScrollPane();
				scrollPane.getViewport().add(resultsList);
				scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
				scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
				scrollPane.getVerticalScrollBar().setUnitIncrement(80);
				scrollPane.getHorizontalScrollBar().setUnitIncrement(80);

				getContentPane().setLayout(new BorderLayout());
				getContentPane().add(scrollPane,BorderLayout.CENTER);
				getContentPane().add(nav,BorderLayout.NORTH);
				getContentPane().add(advancedPanel, BorderLayout.SOUTH);

				//position and size
				Container frame = currentGUI.getFrame();
				if(commonValues.getModeOfOperation() == Values.RUNNING_APPLET){
					if (currentGUI.getFrame() instanceof JFrame)
						frame = ((JFrame)currentGUI.getFrame()).getContentPane();
				}

				if(style==SEARCH_EXTERNAL_WINDOW){
					int w=230;

					int h=frame.getHeight();
					int x1=frame.getLocationOnScreen().x;
					int x=frame.getWidth()+x1;
					int y=frame.getLocationOnScreen().y;
					Dimension d = Toolkit.getDefaultToolkit().getScreenSize();

					int width = d.width;
					if(x+w>width && style==SEARCH_EXTERNAL_WINDOW){
						x=width-w;
						frame.setSize(x-x1,frame.getHeight());
					}

					setSize(w,h);
					setLocation(x,y);
				}
				searchAll.setFocusable(false);

				searchText.grabFocus();

			}else{
				//Whole Panel not used, take what is needed
				currentGUI.setSearchText(searchText);
			}
		}
		
	}
	
	/**
	 * find text on page withSwingWindow
	 */
	public void findWithoutWindow(final PdfDecoder dec, final Values values, int searchType, boolean listOfTerms, boolean singlePageOnly, String searchValue){

        if(!isSearch){
			backGroundSearch = true;
			isSearch=true;

			this.decode_pdf = dec;
			this.commonValues = values;

			decode_pdf.setLayout(new BorderLayout());
			decode_pdf.add(progress, BorderLayout.SOUTH);
			progress.setValue(0);
			progress.setMaximum(commonValues.getPageCount());
			progress.setVisible(true);
			decode_pdf.validate();

			String textToFind = searchValue;
			if(!listOfTerms){ // find exact word or phrase
				searchTerms = new String[] { textToFind };
			} else { // match any of the words
				searchTerms = textToFind.split(" ");
				for (int i = 0; i < searchTerms.length; i++) {
					searchTerms[i] = searchTerms[i].trim();
				}
			}

			searchTypeParameters = searchType;

			singlePageSearch = singlePageOnly;

			find(dec, values);
			
		}else{
			currentGUI.showMessageDialog("Please wait for search to finish before starting another.");
		}
	}
	
	/**
	 * find text on page
	 */
	public void find(final PdfDecoder dec, final Values values){


		//		System.out.println("clicked pdf = "+decode_pdf.getClass().getName() + "@" + Integer.toHexString(decode_pdf.hashCode()));
		
		/**
		 * pop up new window to search text (initialise if required
		 */
		if(!backGroundSearch){
			init(dec, values);
			if(style==SEARCH_EXTERNAL_WINDOW)
				setVisible(true);
		}else{
			try {
				searchText();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}


	public void removeSearchWindow(boolean justHide) {

		//System.out.println("remove search window");

		setVisible(false);

		setVisible(false);

		if(searcher!=null)
			searcher.interrupt();

		if(isSetup && !justHide){
			if(listModel!=null)
				listModel.clear();//removeAllElements();

			//searchText.setText(defaultMessage);
			//searchAll=null;
			//if(nav!=null)
			//    nav.removeAll();

			itemFoundCount=0;
			isSearch=false;

		}

        //lose any highlights and force redraw with non-existent box
        if(decode_pdf!=null){
            decode_pdf.clearHighlights();
            decode_pdf.repaint();
        }
    }

	private void searchText() throws Exception {

		/** if running terminate first */
		if ((searcher != null))
			searcher.interrupt();

		if(style==SEARCH_MENU_BAR){
			usingMenuBarSearch = true;
		}else{
			usingMenuBarSearch = false;
		}
		
        //reset list of pages searched
        lastPage=-1;
		
		if(listModel == null)
			listModel = new DefaultListModel();
		
		if(resultsList==null)
			resultsList=new SearchList(listModel,textPages, textRectangles);
		
		resultsList.setStatus(SearchList.SEARCH_INCOMPLETE);
		
		if(!backGroundSearch){
			searchButton.setText(Messages.getMessage("PdfViewerSearchButton.Stop"));
			searchButton.invalidate();
			searchButton.repaint();
			
			searchCount.setText(Messages.getMessage("PdfViewerSearch.Scanning1"));
			searchCount.repaint();
		}

		searcher = new SwingWorker() {
			public Object construct() {

				isSearch=true;
				
				try {
					
//					System.out.println("seareching pdf = "+decode_pdf.getClass().getName() + "@" + Integer.toHexString(decode_pdf.hashCode()));
					
					listModel.removeAllElements();
					
					if(!backGroundSearch)
						resultsList.repaint();

					int listCount = 0;
					textPages.clear();

					textRectangles.clear();
					itemFoundCount = 0;
					decode_pdf.clearHighlights();

					//System.out.println("textToFind = "+textToFind);

					// get page sizes
					PdfPageData pageSize = decode_pdf.getPdfPageData();

					int x1, y1, x2, y2;

					// page range
					//int startPage = 1;
					//int endPage = commonValues.getPageCount() + 1;
					
					if (singlePageSearch || usingMenuBarSearch) {
						//startPage = commonValues.getCurrentPage();
						//endPage = startPage + 1;
						if(singlePageSearch){
							searchPageRange(pageSize, commonValues.getCurrentPage(), commonValues.getCurrentPage()+1);
						}else{
							for(int p=0; p!=commonValues.getPageCount()+1 && resultsList.getResultCount()<1;p++){
								int page = commonValues.getCurrentPage()+p;
								if(page>commonValues.getPageCount())
									page -=commonValues.getPageCount();
								searchPageRange(pageSize, page, page+1);
							}
						}
                        
					}else if(!backGroundSearch || !usingMenuBarSearch){
                        //this page to end
                        searchPageRange(pageSize, 1, commonValues.getPageCount() + 1);
                    }



					if(!backGroundSearch){
						searchCount.setText(Messages.getMessage("PdfViewerSearch.ItemsFound") + ' ' + itemFoundCount + "  "
								+ Messages.getMessage("PdfViewerSearch.Done"));
						searchButton.setText(Messages.getMessage("PdfViewerSearch.Button"));
					}

					resultsList.invalidate();
					resultsList.repaint();
					resultsList.setSelectedIndex(0);
					resultsList.setLength(listModel.capacity());
					currentGUI.setResults(resultsList);

					currentGUI.nextSearch.setEnabled(true);
					currentGUI.previousSearch.setEnabled(true);

					// reset search button
					isSearch = false;
					requestInterupt = false;

                }catch(InterruptedException ee){

                    //Exception caused so use alert user and allow search
					SwingUtilities.invokeLater(new Runnable(){
						public void run() {
							requestInterupt = false;
							backGroundSearch = false;
                            currentGUI.showMessageDialog("Search stopped by user.");
							if(!backGroundSearch){
                            currentGUI.nextSearch.setEnabled(true);
							currentGUI.previousSearch.setEnabled(true);
							}
						}
					});
                } catch (Exception e) {
					//Exception caused so use alert user and allow search
					SwingUtilities.invokeLater(new Runnable(){
						public void run() {
							requestInterupt = false;
							backGroundSearch = false;
                            if(SimpleViewer.showMessages)
                            currentGUI.showMessageDialog("An error occured during search. Some results may be missing.\n\nPlease send the file to IDRSolutions for investigation.");
							if(!backGroundSearch){
                            currentGUI.nextSearch.setEnabled(true);
							currentGUI.previousSearch.setEnabled(true);
							}
						}
					});

				}
                
				if(!commonValues.isProcessing()){//{if (!event.getValueIsAdjusting()) {

					float scaling=currentGUI.getScaling();
					//int inset=currentGUI.getPDFDisplayInset();

					resultsList.setSelectedIndex(0);
					int id=resultsList.getSelectedIndex();

					decode_pdf.clearHighlights();
					//							System.out.println("clicked pdf = "+decode_pdf.getClass().getName() + "@" + Integer.toHexString(decode_pdf.hashCode()));

					if(id!=-1){

						Integer key=new Integer(id);
						Object newPage=textPages.get(key);

						if(newPage!=null){
							int nextPage=((Integer)newPage).intValue();


							//move to new page
							if(commonValues.getCurrentPage()!=nextPage){

								commonValues.setCurrentPage(nextPage);

								currentGUI.resetStatusMessage(Messages.getMessage("PdfViewer.LoadingPage")+ ' ' +commonValues.getCurrentPage());

								/**reset as rotation may change!*/
								decode_pdf.setPageParameters(scaling, commonValues.getCurrentPage());

								//decode the page
								currentGUI.decodePage(false);

								decode_pdf.invalidate();
							}

							while(commonValues.isProcessing()){
								//Ensure page has been processed else highlight may be incorrect
                                try {
                                    Thread.sleep(500);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                                }
                            }
							
							firstPageWithResults = commonValues.getCurrentPage();
							
							/**
							 * Highlight all search results on page.
							 */
							
							if((searchTypeParameters & SearchType.HIGHLIGHT_ALL_RESULTS)== SearchType.HIGHLIGHT_ALL_RESULTS){
								Rectangle[] showAllOnPage;
								Vector_Rectangle storageVector = new Vector_Rectangle();
								int lastPage = -1;
								for(int k=0; k!=resultsList.getModel().getSize(); k++){
									Object page=textPages.get(new Integer(k));

									if(page!=null){

										int currentPage = ((Integer)page).intValue();
										if(currentPage!=lastPage){
											storageVector.trim();
											showAllOnPage = storageVector.get();
											decode_pdf.addHighlights(showAllOnPage, true, lastPage);
											lastPage = currentPage;
											storageVector = new Vector_Rectangle();
										}

											Object highlight= textRectangles.get(new Integer(k));

											if(highlight instanceof Rectangle){
												storageVector.addElement((Rectangle)highlight);
											}
											if(highlight instanceof Rectangle[]){
												Rectangle[] areas = (Rectangle[])highlight;
												for(int i=0; i!=areas.length; i++){
													storageVector.addElement(areas[i]);
												}
											}
											//decode_pdf.addToHighlightAreas(decode_pdf, storageVector, currentPage);
//										}
									}
								}
								storageVector.trim();
								showAllOnPage = storageVector.get();
								decode_pdf.addHighlights(showAllOnPage, true, lastPage);
								
							}else{

								Object highlight= textRectangles.get(key);

								if(highlight instanceof Rectangle){
									decode_pdf.scrollRectToHighlight((Rectangle)highlight,commonValues.getCurrentPage());

									//add text highlight
									decode_pdf.addHighlights(new Rectangle[]{(Rectangle)highlight}, true, commonValues.getCurrentPage());
								}
								if(highlight instanceof Rectangle[]){
									decode_pdf.scrollRectToHighlight(((Rectangle[])highlight)[0],commonValues.getCurrentPage());

									//add text highlight
									decode_pdf.addHighlights(((Rectangle[])highlight), true, commonValues.getCurrentPage());
								}

							}

							decode_pdf.invalidate();
							decode_pdf.repaint();

						}
					}
				}

				//When page changes make sure only relevant navigation buttons are displayed
				if(commonValues.getCurrentPage()==1)
					currentGUI.setBackNavigationButtonsEnabled(false);
				else
					currentGUI.setBackNavigationButtonsEnabled(true);

				if(commonValues.getCurrentPage()==decode_pdf.getPageCount())
					currentGUI.setForwardNavigationButtonsEnabled(false);
				else
					currentGUI.setForwardNavigationButtonsEnabled(true);

				decode_pdf.remove(progress);
				decode_pdf.validate();
                backGroundSearch = false;
                resultsList.setStatus(SearchList.SEARCH_COMPLETE_SUCCESSFULLY);
				return null;
			}
		};

		searcher.start();
	}

    public int getFirstPageWithResults() {
		return firstPageWithResults;
	}


	private void searchPageRange(PdfPageData pageSize, int startPage, int endPage) throws Exception {

        int x1;
        int x2;
        int y1;
        int y2;// search all pages

        int listCount=0;

        //System.out.println("Search range "+startPage+" "+endPage);

        for (int page = startPage; page < endPage && !requestInterupt; page++) {

//@kieran -changed by Mark to stop thread issue
            if (Thread.interrupted()) {
                continue;
                //throw new InterruptedException();
            }

//System.out.println("page=="+page);

            progress.setValue(progress.getValue()+1);
            decode_pdf.repaint();

            /** common extraction code */
            PdfGroupingAlgorithms currentGrouping;

            /** create a grouping object to apply grouping to data */
            try {
                if (page == commonValues.getCurrentPage())
                    currentGrouping = decode_pdf.getGroupingObject();
                else {
                    decode_pdf.decodePageInBackground(page);
                    currentGrouping = decode_pdf.getBackgroundGroupingObject();
                }

                // tell JPedal we want teasers
                currentGrouping.generateTeasers();

//allow us to add options
                currentGrouping.setIncludeHTML(true);

// set size
                x1 = pageSize.getCropBoxX(page);
                x2 = pageSize.getCropBoxWidth(page);
                y1 = pageSize.getCropBoxY(page);
                y2 = pageSize.getCropBoxHeight(page);

                final SearchListener listener = new DefaultSearchListener();

                SortedMap highlightsWithTeasers = currentGrouping.findMultipleTermsInRectangleWithMatchingTeasers(x1, y1, x2, y2, pageSize.getRotation(page), page, searchTerms, searchTypeParameters, listener);

//changed by MArk
                if (Thread.interrupted()) {
                    continue;
                    //throw new InterruptedException();
                }

/**
 * update data structures with results from this page
 */
                if (!highlightsWithTeasers.isEmpty()) {

//@kieran
//switch on buttons as soon as search produces valid results
                    if(!backGroundSearch){
                        currentGUI.nextSearch.setEnabled(true);
                        currentGUI.previousSearch.setEnabled(true);

                    }
// update count display
                    itemFoundCount = itemFoundCount + highlightsWithTeasers.size();

                    Iterator iter = highlightsWithTeasers.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry e = (Map.Entry) iter.next();

/*highlight is a rectangle or a rectangle[]*/
                        Object highlight = e.getKey();

                        final String teaser = (String) e.getValue();

                        if (!SwingUtilities.isEventDispatchThread()) {
                            Runnable setTextRun = new Runnable() {
                                public void run() {

    //if highights ensure displayed by wrapping in tags
                                    if(teaser.indexOf("<b>")==-1)
                                        listModel.addElement(teaser);
                                    else
                                        listModel.addElement("<html>"+teaser+"</html>");
                                }
                            };
                            SwingUtilities.invokeLater(setTextRun);
                        }else{
                           if(teaser.indexOf("<b>")==-1)
                                        listModel.addElement(teaser);
                                    else
                                        listModel.addElement("<html>"+teaser+"</html>");
                        }
                        
                        Integer key = new Integer(listCount);
                        listCount++;
                        textRectangles.put(key, highlight);
                        textPages.put(key, new Integer(page));
                    }

                }

                // new value or 16 pages elapsed
                if (!backGroundSearch && (!highlightsWithTeasers.isEmpty()) | ((page % 16) == 0)) {
                    searchCount.setText(Messages.getMessage("PdfViewerSearch.ItemsFound") + ' ' + itemFoundCount + ' '
                            + Messages.getMessage("PdfViewerSearch.Scanning") + page);
                    searchCount.invalidate();
                    searchCount.repaint();
                }
            } catch (PdfException e1) {
                backGroundSearch = false;
                requestInterupt = false;
            }
            if(requestInterupt){
                currentGUI.showMessageDialog("Search stopped by user.");
            }

        }
    }

    public int getListLength(){
		return listModel.capacity();
	}

	public void grabFocusInInput() {
		searchText.grabFocus();

	}

	public boolean isSearchVisible() {
		return this.isVisible();
	}

	public void setStyle(int style) {
		this.style = style;
	}

	public int getStyle() {
		return style;
	}

	public JTextField getSearchText() {
		return searchText;
	}

	public Map getTextRectangles() {
		return textRectangles;
	}

	public SearchList getResults() {

        return resultsList;
	}

    public SearchList getResults(int page) {

        if(usingMenuBarSearch && page !=lastPage && style==SEARCH_MENU_BAR){

            //if(listModel == null)
            listModel = new DefaultListModel();

            textPages.clear();
            textRectangles.clear();
            //if(resultsList==null)
            resultsList=new SearchList(listModel,textPages, textRectangles);

            resultsList.setStatus(SearchList.SEARCH_INCOMPLETE);

            try {
                searchPageRange(decode_pdf.getPdfPageData(), page, page + 1);
            } catch (Exception e) {
                e.printStackTrace();
            }


            lastPage=page;
        }

        return resultsList;
    }
	
}
