//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package de.ugoe.cs.autoquest.ui.swt;

import java.util.LinkedList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;

import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;

import de.ugoe.cs.util.FileTools;
import de.ugoe.cs.util.StringTools;
import de.ugoe.cs.util.console.CommandExecuter;
import de.ugoe.cs.util.console.Console;
import de.ugoe.cs.util.console.GlobalDataContainer;
import de.ugoe.cs.util.console.listener.ICommandListener;

/**
 * <p>
 * Implements the composite for the console tab in the applications main window.
 * </p>
 * 
 * @author Steffen Herbold
 * @version 1.0
 */
public class ConsoleTabComposite extends Composite implements ICommandListener {

    protected java.util.List<String> commandHistory = new LinkedList<String>();
    
    protected int commandHistoryIndex = 0;

    protected Text textCommand;

    protected StyledText textConsoleOutput;

    /**
     * Create the composite.
     * 
     * @param parent
     * @param style
     */
    public ConsoleTabComposite(Composite parent, int style) {
        super(parent, style);
        createContents();
        Console.getInstance().registerCommandListener(this);
    }

    @Override
    public void commandNotification(String command) {
        commandHistory.add(command);
        commandHistoryIndex = commandHistory.size();
    }

    private void createContents() {
        setLayout(new GridLayout(3, false));

        Label lblCommand = new Label(this, SWT.NONE);
        lblCommand.setText("Command:");

        textCommand = new Text(this, SWT.BORDER);
        textCommand.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.keyCode == SWT.CR) {
                    executeCommand();
                }
                else if (e.keyCode == SWT.TAB) {
                    autoCompleteCommand();
                }
                else if (e.keyCode == SWT.ARROW_UP) {
                    setToPreviousCommand();
                }
                else if (e.keyCode == SWT.ARROW_DOWN) {
                    setToNextCommand();
                }
            }
        });
        textCommand.addTraverseListener(new TraverseListener() {
            @Override
            public void keyTraversed(TraverseEvent e) {
                if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS))
                {
                    e.doit = false;
                }
            }
            
        });
        
        GridData gd_textCommand = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
        gd_textCommand.widthHint = 304;
        textCommand.setLayoutData(gd_textCommand);
        textCommand.setFocus();

        Button btnEnter = new Button(this, SWT.NONE);
        btnEnter.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                executeCommand();
            }
        });
        btnEnter.setText("Enter");

        textConsoleOutput =
            new StyledText(this, SWT.BORDER | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL |
                SWT.CANCEL);
        GridData gd_textConsoleOutput = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1);
        gd_textConsoleOutput.heightHint = 102;
        gd_textConsoleOutput.widthHint = 456;
        textConsoleOutput.setLayoutData(gd_textConsoleOutput);
        textConsoleOutput.addListener(SWT.Modify, new Listener() {
            public void handleEvent(Event e) {
                textConsoleOutput.setTopIndex(textConsoleOutput.getLineCount() - 1);
            }
        });

    }

    private void executeCommand() {
        String command = textCommand.getText().trim();
        CommandExecuter.getInstance().exec(command);
        textCommand.setText("");
    }

    private void autoCompleteCommand() {
        String prefix = textCommand.getText();
        int end = textCommand.getCaretPosition() - 1;
        int start = 0;
        
        for (int i = end; i >= 0; i--) {
            if (Character.isWhitespace(prefix.charAt(i))) {
                start = i + 1;
                break;
            }
        }
        
        String textPrefix = prefix.substring(0, start);
        String textSuffix = prefix.substring(end + 1);
        prefix = prefix.substring(start, end + 1);
        
        String completedPrefix = null;
        if ("".equals(textCommand.getText().substring(0, start).trim())) {
            // search for a command completion
            completedPrefix = CommandExecuter.getInstance().autoCompleteCommand(prefix);
        }
        else {
            // complete an object in the data store or a file name
            completedPrefix = FileTools.autoCompletePath(prefix);
            
            if (prefix.equals(completedPrefix)) {
                // file completion wasn't possible, so try to complete using data objects
                String[] completions =
                    GlobalDataContainer.getInstance().getAllKeys().toArray(new String[0]);
                completedPrefix = StringTools.autocomplete(prefix, completions);
            }
        }
        
        textCommand.setText(textPrefix + completedPrefix + textSuffix);
        textCommand.setSelection(textPrefix.length() + completedPrefix.length());
    }
    
    private void setToPreviousCommand() {
        if (commandHistoryIndex > 0) {
            commandHistoryIndex--;
            
            textCommand.setText(commandHistory.get(commandHistoryIndex));
            textCommand.setSelection(commandHistory.get(commandHistoryIndex).length());
        }
    }

    private void setToNextCommand() {
        if (commandHistoryIndex < (commandHistory.size() - 1)) {
            commandHistoryIndex++;
            
            textCommand.setText(commandHistory.get(commandHistoryIndex));
            textCommand.setSelection(commandHistory.get(commandHistoryIndex).length());
        }
    }
    
    @Override
    protected void checkSubclass() {
        // Disable the check that prevents subclassing of SWT components
    }

}
