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

        // Allow the contents of files to be browsed.
        // The file is displayed in a non-editable TextArea.
        // Menu options allow a file to be opened and the
        // current file to be searched.
public class FileBrowser extends Frame implements ActionListener {
    FileBrowser(){
        final int width = 400, height = 300;
        setSize(width,height);
        // Create the viewing area for the file's contents.
        final int numRows = 10, numCols = 80;
        FileViewArea area = new FileViewArea(numRows,numCols);

        // Don't allow changes.
        area.setEditable(false);
        add(area);
        // Save the text area as an attribute.
        setContents(area);

        // Add the menu bar.
        setupMenuBar();
    }

        // Take whatever action is required by the menu.
    public void actionPerformed(ActionEvent e){
        String command = e.getActionCommand();
        if((command == null) || (command.length() == 0)){
            // No valid command.
        }
        else if(command.equalsIgnoreCase("Open")){
            // Select a new file.
            selectFile();
        }
        else if(command.equalsIgnoreCase("Exit")){
            this.dispose();
            System.exit(0);
        }
        else if(command.equalsIgnoreCase("Find")){
            SearchDialog search = getSearch();
            // Offset the search dialog slightly from the main frame.
            Point location = getLocation();
            final int offset = 75;
            location.x += offset;
            location.y += offset;
            search.setLocation(location);
            search.show();
            String searchString = search.getSearchString();
            if((searchString == null) || searchString.equals("")){
                // Nothing to search for.
            }
            else if(!findString(searchString,search.searchIsForward(),
                                search.isCaseSensitive())){
                System.err.println("No match.");
            }
        }
        else if(command.equalsIgnoreCase("About")){
        }
        else{
            System.err.println("Unrecognized command: "+command);
        }
    }

        // Find the given string under the given conditions.
    protected boolean findString(String match, boolean forward,
                                        boolean caseSensitive){
        if((match == null) || match.equals("")){
            // Nothing to match.
            return false;
        }
        final TextArea contents = getContents();
        final String text = contents.getText();
        int caretPosition = contents.getCaretPosition();
        // Clear the current selection.
        contents.setSelectionStart(caretPosition);
        contents.setSelectionEnd(caretPosition);
        final int matchLength = match.length();
        final boolean ignoreCase = !caseSensitive;
        if(forward){
            final int endPosition = text.length()-matchLength;
            // Work forwards, char-by-char, from the current caret position.
            for(int startPosition = caretPosition;
                                startPosition <= endPosition; startPosition++){
                if(text.regionMatches(ignoreCase,startPosition,
                                        match,0,matchLength)){
                    contents.setSelectionStart(startPosition);
                    contents.setSelectionEnd(startPosition+matchLength);
                    // Position the caret ready for the next match.
                    contents.setCaretPosition(startPosition+matchLength);
                    return true;
                }
            }
        }
        else{
            // Work backwards, char-by-char.
            // Start from a position matchLength characters back
            // from the caret position.
            for(int startPosition = caretPosition-matchLength;
                                startPosition >= 0; startPosition--){
                if(text.regionMatches(ignoreCase,startPosition,
                                        match,0,matchLength)){
                    contents.setSelectionStart(startPosition);
                    contents.setSelectionEnd(startPosition+matchLength);
                    // Position the caret ready for the next match.
                    contents.setCaretPosition(startPosition);
                    return true;
                }
            }
        }
        return false;
    }

            // Setup the menu bar.
    protected void setupMenuBar(){
        MenuBar bar = new MenuBar();

        bar.add(createFileMenu());
        bar.add(createSearchMenu());
        bar.setHelpMenu(createHelpMenu());
        // Add it to the frame.
        setMenuBar(bar);
    }

        // Create the File menu with items Open and Quit.
    protected Menu createFileMenu(){
        Menu fileMenu = new Menu("File");

        // Open is a simple item with a shortcut associated
        // with the `F1' key.
        MenuItem openItem = new MenuItem("Open",
                                new MenuShortcut(KeyEvent.VK_F1));
        openItem.setActionCommand("Open");
        openItem.addActionListener(this);

        // Quit is a sub-menu.
        Menu quitMenu = new Menu("Quit");
        // Add the sub-menu items to Quit.
        // Cancel requires no action.
        quitMenu.add(new MenuItem("Cancel"));
        MenuItem exitItem = new MenuItem("Really quit");
        exitItem.setActionCommand("Exit");
        exitItem.addActionListener(this);
        // Add a short cut.
        exitItem.setShortcut(new MenuShortcut(KeyEvent.VK_X));
        quitMenu.add(exitItem);

        // Add the items to this menu.
        fileMenu.add(openItem);
        // Add a separator between Open and Quit.
        fileMenu.addSeparator();
        fileMenu.add(quitMenu);
        return fileMenu;
    }

    protected Menu createSearchMenu(){
        Menu searchMenu = new Menu("Search");
        MenuItem searchItem = new MenuItem("Find",
                                new MenuShortcut(KeyEvent.VK_S));
        searchItem.setActionCommand("Find");
        searchItem.addActionListener(this);
        searchMenu.add(searchItem);

        return searchMenu;
    }

    protected Menu createHelpMenu(){
        Menu helpMenu = new Menu("Help");
        helpMenu.add(new MenuItem("About"));
        return helpMenu;
    }

        // The user has requested to open a file.
        // Show a FileDialog in LOAD mode.
    protected void selectFile(){
        FileDialog dialog = new FileDialog(this,"Open File",FileDialog.LOAD);
        dialog.setDirectory("");
        dialog.setFile("");
        dialog.show();

        // Wait for the dialog to complete.
        String filename = dialog.getFile();
        if((filename != null) && (filename.length() != 0)){
            // Prefix the directory name, if any.
            String directory = dialog.getDirectory();
            if((directory != null) && (directory.length() != 0)){
                filename = directory+filename;
            }
            try{
                // Load the file.
                loadFile(filename);
            }
            catch(Exception e){
                System.err.println(e);
            }
        }
    }

        // Load the contents of the given file and display
        // it in the viewing area.
    public void loadFile(String filename) throws Exception {
        // Make sure the file exists.
        File details = new File(filename);
        if(!details.exists()){
            throw new Exception(filename+" does not exist.");
        }
        else if(!details.canRead()){
            throw new Exception("You don't have permission to view: "+filename);
        }
        else if(details.length() > Integer.MAX_VALUE){
            // We can't cope with the file's size.
            throw new Exception("The file is too big to display.");
        }
        // else - it should be ok.

        BufferedReader reader = null;
        try{
            // Read the file into a single array.
            int fileSize = (int) details.length();
            char[] buffer = new char [fileSize];
            // Keep track of how much has been read.
            int totalCharsRead = 0;

            // Open the file and read it.
            reader = new BufferedReader(new FileReader(filename));
            while(totalCharsRead < fileSize){
                // Try to read the remainder in one go.
                int charsRead = reader.read(buffer,totalCharsRead,
                                            fileSize-totalCharsRead);
                totalCharsRead += charsRead;
            }

            // Place the text into the FileViewArea.
            getContents().display(details,String.valueOf(buffer));
        }
        catch(IOException e){
            throw new Exception("Read failure: "+e.getMessage());
        }
        finally{
            if(reader != null){
                reader.close();
            }
        }
    }

    protected FileViewArea getContents(){
        return contents;
    }

    protected void setContents(FileViewArea c){
        contents = c;
    }

    protected SearchDialog getSearch(){
        return search;
    }

    private FileViewArea contents;
    // Construct the search dialog.
    private SearchDialog search = new SearchDialog(this);
}
