/*******************************************************************************
 * Copyright (c) 2010 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributor:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/
package org.hibernate.eclipse.console.views;

import java.text.MessageFormat;

import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Text;
import org.hibernate.console.StringListDialog;

/**
 * @author Dmitry Geraskov
 *
 */
public class StringArrayDialogCellEditor extends TextCellEditor {
	
	private Text text;
	
    /**
     * The button.
     */
    private Button button;
	
	/**
     * The editor control.
     */
    private Composite editor;
    
    private String[] strValues = null;
    
    private FocusListener buttonFocusListener;
    
    protected StringArrayDialogCellEditor(Composite parent) {
        super(parent);
    }

	@Override
	protected Control createControl(Composite parent) {
		Font font = parent.getFont();
        Color bg = parent.getBackground();

        editor = new Composite(parent, getStyle());
        editor.setFont(font);
        editor.setBackground(bg);
        editor.setLayout(new DialogCellLayout());

        text = (Text) super.createControl(editor);
        updateContents(strValues);

        button = createButton(editor);
        button.setFont(font);

        button.addKeyListener(new KeyAdapter() {
            /* (non-Javadoc)
             * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
             */
            public void keyReleased(KeyEvent e) {
                if (e.character == '\u001b') { // Escape
                    fireCancelEditor();
                }
            }
        });
        
        button.addFocusListener(getButtonFocusListener());
        
        button.addSelectionListener(new SelectionAdapter() {
            /* (non-Javadoc)
             * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            public void widgetSelected(SelectionEvent event) {
            	// Remove the button's focus listener since it's guaranteed
            	// to lose focus when the dialog opens
            	button.removeFocusListener(getButtonFocusListener());
                
            	Object newValue = openDialogBox(editor);
            	
            	// Re-add the listener once the dialog closes
            	button.addFocusListener(getButtonFocusListener());

            	if (newValue != null) {
                    boolean newValidState = isCorrect(newValue);
                    if (newValidState) {
                        markDirty();
                        doSetValue(newValue);
                    } else {
                        // try to insert the current value into the error message.
                        setErrorMessage(MessageFormat.format(getErrorMessage(),
                                new Object[] { newValue.toString() }));
                    }
                    fireApplyEditorValue();
                }
            }

			
        });

        setValueValid(true);

        return editor;
	}
	
	@Override
	protected void focusLost() {
		if (isActivated()) {
			if (button != null && !button.isDisposed() && !button.isFocusControl()) {
	    		if (text != null && !text.isDisposed() && !text.isFocusControl()){
	    			fireApplyEditorValue();
	    			deactivate();
	    		}
	    	}
		}
	}
	
	protected Object openDialogBox(Control cellEditorWindow) {
		String[] value = (String[]) getValue();
		StringListDialog pld = new StringListDialog(null, value);
		if (pld.open()==Window.OK){
			return pld.getValue();//String[]
		}
		return null;
	}
	
    private FocusListener getButtonFocusListener() {
    	if (buttonFocusListener == null) {
    		buttonFocusListener = new FocusListener() {

				/* (non-Javadoc)
				 * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
				 */
				public void focusGained(FocusEvent e) {
					
				}

				/* (non-Javadoc)
				 * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
				 */
				public void focusLost(FocusEvent e) {
					StringArrayDialogCellEditor.this.focusLost();
				}
    		};
    	}
    	
    	return buttonFocusListener;
	}

    protected Button createButton(Composite parent) {
        Button result = new Button(parent, SWT.DOWN);
        result.setText("..."); //$NON-NLS-1$
        return result;
    }
    
    public void deactivate() {
    	if (button != null && !button.isDisposed()) {
    		button.removeFocusListener(getButtonFocusListener());
    	}
    	
		super.deactivate();
	}
    
    @Override
    protected void editOccured(ModifyEvent e) {
    	String text = this.text.getText();
    	if (strValues == null || strValues.length == 0){
    		strValues = new String[]{text};
    	} else {
    		strValues[0] = text;
    	}
    	super.editOccured(e);
    }
    
    protected Object doGetValue() {
        return strValues;
    }

    protected void doSetValue(Object value) {    	
    	if (value == null) {
    		this.strValues = new String[]{""}; //$NON-NLS-1$
    	} else if (value.getClass().isArray()){
    		this.strValues = (String[])value;
    	}
    	super.doSetValue(strValues.length > 0 ? strValues[0] : ""); //$NON-NLS-1$
    }

	protected void updateContents(String[] value) {
        if (text == null) {
			return;
		}

        String strVal = "";//$NON-NLS-1$
        if (value != null && value.length > 0) {
        	strVal = value[0];
		}
        text.setText(strVal);
    }

	private class DialogCellLayout extends Layout {
        public void layout(Composite editor, boolean force) {
            Rectangle bounds = editor.getClientArea();
            Point size = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, force);
            if (text != null) {
            	text.setBounds(0, 0, bounds.width - size.x, bounds.height);
			}
            button.setBounds(bounds.width - size.x, 0, size.x, bounds.height);
        }

        public Point computeSize(Composite editor, int wHint, int hHint,
                boolean force) {
            if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) {
				return new Point(wHint, hHint);
			}
            Point contentsSize = text.computeSize(SWT.DEFAULT, SWT.DEFAULT,
                    force);
            Point buttonSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT,
                    force);
            // Just return the button width to ensure the button is not clipped
            // if the label is long.
            // The label will just use whatever extra width there is
            Point result = new Point(buttonSize.x, Math.max(contentsSize.y,
                    buttonSize.y));
            return result;
        }
    }

	
}