package oracle.forms.fd;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.text.*;

/* This work is hereby released into the Public Domain.
 * To view a copy of the public domain dedication, visit
 * http://creativecommons.org/licenses/publicdomain/
 */
public class CBAutoCompletion extends PlainDocument {
  
  public ComboBoxCompletion CBC ;

  JComboBox comboBox;
  ComboBoxModel model;
  JTextComponent editor;
  // flag to indicate if setSelectedItem has been called
  // subsequent calls to remove/insertString should be ignored
  boolean selecting=false;
  boolean hidePopupOnFocusLoss;
  boolean hitBackspace=false;
  boolean hitBackspaceOnSelection;
  int     iSelection = 0 ;

  KeyListener editorKeyListener;
  FocusListener editorFocusListener;

  public CBAutoCompletion(final JComboBox comboBox) {
    this.comboBox = comboBox;
    model = comboBox.getModel();
    comboBox.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        /*
         *  Modif F. Degrelle
         *  tell Forms that the selection has changed
         */
        if(comboBox.getSelectedIndex() != -1) iSelection = comboBox.getSelectedIndex();
        if(e.getActionCommand().equalsIgnoreCase("comboBoxChanged"))
        {
            String sValue = (String)comboBox.getSelectedItem() ;
            setText(sValue);
            // send the new value to the standard list item
            // to make PJC fire the When-List-Changed trigger

           if(CBC != null)
           {
             CBC.dispatchanevent(iSelection+1, sValue);
           }
           else System.err.println("CBC is null !!!");
        }
        if (!selecting) highlightCompletedText(0);        
      }
    });
    comboBox.addPropertyChangeListener(new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent e) {
        if (e.getPropertyName().equals("editor")) configureEditor((ComboBoxEditor) e.getNewValue());
        if (e.getPropertyName().equals("model")) model = (ComboBoxModel) e.getNewValue();
      }
    });
    editorKeyListener = new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        if (comboBox.isDisplayable()) comboBox.setPopupVisible(true);
        hitBackspace=false;
        switch (e.getKeyCode()) {
          // determine if the pressed key is backspace (needed by the remove method)
          case KeyEvent.VK_BACK_SPACE : hitBackspace=true;
          hitBackspaceOnSelection=editor.getSelectionStart()!=editor.getSelectionEnd();
          break;
          /*
           *  modification F. Degrelle
           *  transmit other keys back to Forms
           *  to keep a standard behaviour
           *  (F4, Tab, Enter, etc.)
           */
          case KeyEvent.VK_ENTER:
          case KeyEvent.VK_TAB:
          case KeyEvent.VK_CANCEL:
          case KeyEvent.VK_CLEAR:
          case KeyEvent.VK_SHIFT:
          case KeyEvent.VK_CONTROL:
          case KeyEvent.VK_ALT:
          case KeyEvent.VK_PAUSE:
          case KeyEvent.VK_CAPS_LOCK:
          case KeyEvent.VK_ESCAPE:
          case KeyEvent.VK_PAGE_UP:
          case KeyEvent.VK_PAGE_DOWN:
          //case KeyEvent.VK_UP:
          //case KeyEvent.VK_DOWN:
          case KeyEvent.VK_F1:
          case KeyEvent.VK_F2:
          case KeyEvent.VK_F3:
          case KeyEvent.VK_F4:
          case KeyEvent.VK_F5:
          case KeyEvent.VK_F6:
          case KeyEvent.VK_F7:
          case KeyEvent.VK_F8:
          case KeyEvent.VK_F9:
          case KeyEvent.VK_F10:
          case KeyEvent.VK_F11:
          case KeyEvent.VK_F12:            
          case KeyEvent.VK_F13:
          case KeyEvent.VK_F14:
          case KeyEvent.VK_F15:
          case KeyEvent.VK_F16:
          case KeyEvent.VK_F17:
          case KeyEvent.VK_F18:            
          case KeyEvent.VK_F19:
          case KeyEvent.VK_F20:
          case KeyEvent.VK_F21:
          case KeyEvent.VK_F22:
          case KeyEvent.VK_F23:
          case KeyEvent.VK_F24:                        
          CBC.setKeyPressed(e);
        }
      }
    };

    // Bug 5100422 on Java 1.5: Editable JComboBox won't hide popup when tabbing out
    hidePopupOnFocusLoss=System.getProperty("java.version").startsWith("1.5");
    // Highlight whole text when gaining focus
    editorFocusListener = new FocusAdapter() {
      public void focusGained(FocusEvent e) {
        try{
          highlightCompletedText(0);
        } catch(Exception ex){}
      }
      public void focusLost(FocusEvent e) {
        // Workaround for Bug 5100422 - Hide Popup on focus loss
        try{
          if (hidePopupOnFocusLoss) comboBox.setPopupVisible(false);
        } catch(Exception ex){}
      }
    };
    configureEditor(comboBox.getEditor());
    // Handle initially selected object
    Object selected = comboBox.getSelectedItem();
    if (selected!=null) setText(selected.toString());
    highlightCompletedText(0);
  }

  public  void enable(JComboBox comboBox) {
    // has to be editable
    comboBox.setEditable(true);
    // change the editor's document
    new CBAutoCompletion(comboBox);
  }

  void configureEditor(ComboBoxEditor newEditor) {
    if (editor != null) {
      editor.removeKeyListener(editorKeyListener);
      editor.removeFocusListener(editorFocusListener);
    }

    if (newEditor != null) {
      editor = (JTextComponent) newEditor.getEditorComponent();
      editor.addKeyListener(editorKeyListener);
      editor.addFocusListener(editorFocusListener);
      editor.setDocument(this);
    }
  }

  public void remove(int offs, int len) throws BadLocationException {
    // return immediately when selecting an item
    if (selecting) return;
    if (hitBackspace) {
      // user hit backspace => move the selection backwards
      // old item keeps being selected
      if (offs>0) {
        if (hitBackspaceOnSelection) offs--;
      } else {
        // User hit backspace with the cursor positioned on the start => beep
        comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
      }
      highlightCompletedText(offs);
    } else {
      super.remove(offs, len);
    }
  }

  private final boolean strict_match = false;

  public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
    // return immediately when selecting an item
    if (selecting) return;
    // insert the string into the document
    super.insertString(offs, str, a);
    // lookup and select a matching item
    Object item = lookupItem(getText(0, getLength()));
    if(strict_match) {
      if (item != null) {
        setSelectedItem(item);
      } else {
        // keep old item selected if there is no match
        item = comboBox.getSelectedItem();
        // imitate no insert (later on offs will be incremented by str.length(): selection won't move forward)
        offs = offs-str.length();
        // provide feedback to the user that his input has been received but can not be accepted
        comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
      }
      setText(item.toString());
      // select the completed part
      highlightCompletedText(offs+str.length());
    } else {
      boolean listContainsSelectedItem = true;
      if (item == null) {
        // no item matches => use the current input as selected item
        item=getText(0, getLength());
        listContainsSelectedItem=false;
      } else {
        setSelectedItem(item);
      }
      setText(item.toString());

      // select the completed part
      if (listContainsSelectedItem) highlightCompletedText(offs+str.length());
    }
  }

  private void setText(String text) {
    try {
      // remove all text and insert the completed string
      super.remove(0, getLength());
      super.insertString(0, text, null);
    } catch (BadLocationException e) {
      throw new RuntimeException(e.toString());
    }
  }

  private void highlightCompletedText(int start) {
    editor.setCaretPosition(getLength());
    editor.moveCaretPosition(start);
  }

  private void setSelectedItem(Object item) {
    selecting = true;
    model.setSelectedItem(item);
    selecting = false;
  }

  private Object lookupItem(String pattern) {
    Object selectedItem = model.getSelectedItem();
    // only search for a different item if the currently selected does not match
    if (selectedItem != null && startsWithIgnoreCase(selectedItem.toString(), pattern)) {
      return selectedItem;
    } else {
      // iterate over all items
      for (int i=0, n=model.getSize(); i < n; i++) {
        Object currentItem = model.getElementAt(i);
        // current item starts with the pattern?
        if (currentItem != null && startsWithIgnoreCase(currentItem.toString(), pattern)) {
          return currentItem;
        }
      }
    }
    // no item starts with the pattern => return null
    return null;
  }

  // checks if str1 starts with str2 - ignores case
  private boolean startsWithIgnoreCase(String str1, String str2) {
    return str1.toUpperCase().startsWith(str2.toUpperCase());
  }
  /*
  private static void createAndShowGUI() {
    // the combo box (add/modify items if you like to)
    final JComboBox test_comboBox = new JComboBox(new Object[] {"Ester", "Jordi", "Jordina", "Jorge", "Sergi"});
    enable(test_comboBox);

    // create and show a window containing the combo box
    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(3);
    frame.getContentPane().add(test_comboBox);
    frame.pack(); frame.setVisible(true);
  }

  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
  */
 
  void setAlignement( int i ) { 
      DefaultListCellRenderer renderer = new DefaultListCellRenderer();
      renderer.setHorizontalAlignment(i);
      renderer.setHorizontalTextPosition(i);
      comboBox.setRenderer(renderer);
      comboBox.setEditor(new MyComboEditor(i));
  }

 
}