/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package usda.weru.mcrew;

import com.klg.jclass.cell.JCCellEditor;
import com.klg.jclass.cell.JCCellEditorListener;
import com.klg.jclass.cell.JCCellEditorSupport;
import com.klg.jclass.cell.JCCellInfo;
import com.klg.jclass.cell.JCComponentCellRenderer;
import com.klg.jclass.cell.JCKeyModifier;
import de.schlichtherle.io.File;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.Comparator;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.apache.log4j.Logger;
import usda.weru.mcrew.gui.FileDropDown_n;
import usda.weru.util.FileTreeNode;
import usda.weru.util.WepsTreeComboBox;

/**
 * * @author Joseph Levin <joelevin@weru.ksu.edu>
 */
public class FileDropDown extends FileDropDown_n implements JCComponentCellRenderer, JCCellEditor, PropertyChangeListener {

    public enum FileType {

        Crop,
        Operation
    }

    public enum Invoke {

        Menu,
        Popup,
        Drilldown
    }
    private static final Logger logger = Logger.getLogger(FileDropDown.class);
    /**
     * This dummy component is used when the data is null (aka no value is allowed)).
     */
    protected final JComponent DUMMY = new JLabel();
    /**
     * Key strokes to capture
     */
    private static JCKeyModifier[] KEY_MODIFIERS = {new JCKeyModifier(KeyEvent.VK_DOWN, JCKeyModifier.ALL), new JCKeyModifier(KeyEvent.VK_UP, JCKeyModifier.ALL), new JCKeyModifier(KeyEvent.VK_LEFT, JCKeyModifier.ALL), new JCKeyModifier(KeyEvent.VK_RIGHT, JCKeyModifier.ALL)};
    protected FileType c_type;
    protected File c_file;
    protected Table c_table;
    private Table.MyMouseAdapter c_mouseAdapter;
    protected FileFilter c_fileFilter;
    protected static Comparator<java.io.File> c_fileComparator;
    protected boolean c_isEditor;
    protected boolean c_selected;
    protected AWTEvent c_initialEvent;
    protected Invoke c_invokeLater;
    /**
     * When true, the paint method will determine if the user clicked on the button or dropdown.
     */
    protected boolean c_testUserEntry;
    protected Object c_data;
    protected JCCellEditorSupport c_support = new JCCellEditorSupport();
    
    private InternalRootNode c_root;
    protected DefaultTreeModel  c_model;

    public FileDropDown(FileType type) {
        c_type = type;
        g_dropdown.setRootVisible(false);

        if (type != null){
            g_dropdown.addPropertyChangeListener(this);
            g_dropdown.setSelectOnLossOfFocus(false);
        }

        DUMMY.setOpaque(true);
        
    }

    @Override
    public void addFocusListener(FocusListener l) {
        //super.addFocusListener(l);
    }

    @Override
    public void removeFocusListener(FocusListener l) {
        //super.removeFocusListener(l);
    }
    
    

    public void setTable(Table table) {
        c_table = table;
        if(c_table == null){
            c_initialEvent = null;
        }
    }

    public void setMouseAdapter(Table.MyMouseAdapter adapter) {
        c_mouseAdapter = adapter;
    }

    public void setFile(File file) {
        c_file = file;        
        refreshFiles();
    }
    
    public void refreshFiles() {                
        c_root = new InternalRootNode(c_file);                
        c_model = new DefaultTreeModel(c_root);
        g_dropdown.setModel(c_model); 
        
        //if one zup file lives with folders we expand it.
        TreeNode toExpand = null;
        for (int i = 0; i < c_root.getChildCount(); i++){
            TreeNode node = c_root.getChildAt(i);
            if (node instanceof FileTreeNode){
                File file = ((FileTreeNode) node).getFile();
                if (!file.isDirectory()){
                    return;
                }
                else if (file.getName().toLowerCase().endsWith(".zip")){
                    if (toExpand == null){
                        toExpand = node;
                    }
                    else{
                        return;
                    }                    
                }                
            }
        }
        if (toExpand != null){
            c_model.getPathToRoot(toExpand);
            g_dropdown.getTree().expandPath(new TreePath(c_model.getPathToRoot(toExpand)));
        }
    }    
        

    /*
     * Hack to fix the "jumping" thet occurs when switched from renderer to editor
     */
    @Override
    public void setBounds(int x, int y, int width, int height) {
        if (!c_isEditor) {
            super.setBounds(x, y, width + 1, height);
        } else {
            super.setBounds(x + 2, y + 1, width - 4, height);
        }
    }

    protected void init(JCCellInfo info, Object o) {
        c_data = o;

        if (c_type != null){
            //editor
            g_dropdown.getComboBox().removeAllItems();
            g_dropdown.getComboBox().addItem(o);
            g_dropdown.getComboBox().setSelectedItem(o);
            g_dropdown.getTree().scrollRowToVisible(-1);
            g_dropdown.getTree().setSelectionRow(-1);
        }
        else{
            //renderer           
            g_dropdown.getComboBox().removeAllItems();
            g_dropdown.getComboBox().addItem(o);
            g_dropdown.getComboBox().setSelectedItem(o);
        }
        
   

        Color background = null;
        Color foreground = null;

        if (!c_selected) {
            background = info.getBackground();
            foreground = info.getForeground();
        } else {
            background = info.getSelectedBackground();
            foreground = info.getSelectedForeground();
        }

        setBackground(background);
        setForeground(foreground);
        g_dropdown.setBackground(background);
        g_dropdown.setForeground(foreground);
        g_drilldown.setBackground(background);
        g_drilldown.setForeground(foreground);
        g_dropdown.getTree().setBackground(Color.WHITE);
    }

    //Cell Render Code
    public Component getRendererComponent(JCCellInfo info, Object o, boolean selected) {
        c_isEditor = false;
        if (o == null) {
            DUMMY.setBackground(selected ? info.getSelectedBackground() : ConfigData.getDisabledColor());
            DUMMY.setForeground(selected ? info.getSelectedForeground() : info.getForeground());
            return DUMMY;
        }
        if (o == ManageData.EMPTY_OBJECT) {
            o = "";
        }
        c_selected = selected;
        init(info, o);

        return this;
    }

    public void initialize(AWTEvent ev, JCCellInfo info, Object o) {
        c_isEditor = true;

        if (o == null) {
            g_dropdown.setVisible(false);
            g_drilldown.setVisible(false);
        //o = null;
        } else {
            g_dropdown.setVisible(true);
            g_drilldown.setVisible(true);
        }

        if (o == ManageData.EMPTY_OBJECT) {
            o = "";
        }

        c_initialEvent = ev;


        init(info, o);

        c_testUserEntry = true;
        c_invokeLater = null;

        if (ev instanceof MouseEvent) {
            MouseEvent me = (MouseEvent) ev;
            if (me.getClickCount() > 1) {
                c_table.addColumnData();
            } else if (me.getButton() != MouseEvent.BUTTON1) {
                c_table.getJCTable().cancelEdit(true);
            }
        }
    }

    public Component getComponent() {
        return this;
    }

    //TODO: Review that these methods don't need to be implemented better
    public Object getCellEditorValue() {
        Object item = g_dropdown.getSelectedItem();
        if (item instanceof FileTreeNode){
            return ((FileTreeNode) item).getFile();
        }
        else{
            return null;
        }
    }

    public boolean stopCellEditing() {
        return true;
    }

    public boolean isModified() {
        return false;
    }

    public void cancelCellEditing() {
        
    }

    public JCKeyModifier[] getReservedKeys() {
        return KEY_MODIFIERS != null ? Arrays.copyOf(KEY_MODIFIERS, KEY_MODIFIERS.length) : new JCKeyModifier[0];
    }

    public void addCellEditorListener(JCCellEditorListener listener) {
        c_support.addCellEditorListener(listener);
    }

    public void removeCellEditorListener(JCCellEditorListener listener) {
        c_support.removeCellEditorListener(listener);
    }

    synchronized FileFilter getFileFilter() {
        if (c_fileFilter == null) {
            c_fileFilter = new FileFilter() {

                public boolean accept(java.io.File file) {                    
                    if (file.isDirectory() && file.getName().toLowerCase().startsWith(".svn")) {
                        return false;
                    }
                    else if(file.isDirectory()){
                        return true;
                    }
                    else if (c_type == FileType.Operation) {
                        return file.getName().toLowerCase().trim().endsWith(".oprn");
                    } else if (c_type == FileType.Crop) {
                        return file.getName().toLowerCase().trim().endsWith(".crop");
                    } else {
                        return true;
                    }
                }
            };
        }
        return c_fileFilter;
    }

    public void paint(java.awt.Graphics g) {
        if (c_data == null) {

            DUMMY.setBackground(ConfigData.getDisabledColor());
            DUMMY.paint(g);
            cancelCellEditing();
            return;
        }
        super.paint(g);
        if (c_testUserEntry) {
            if (c_initialEvent != null && c_initialEvent instanceof MouseEvent) {
                MouseEvent me = (MouseEvent) c_initialEvent;
                try {
                    int x = getLocationOnScreen().x;
                    int y = getLocationOnScreen().y;
                    int mx = me.getXOnScreen();
                    int my = me.getYOnScreen();
                    x = mx - x;
                    y = my - y;
                    Component comp = getComponentAt(x, y);
                    if (comp == g_drilldown) {
                        c_invokeLater = Invoke.Drilldown;
                    } else if (comp == g_dropdown) {
                        if (me.getButton() == MouseEvent.BUTTON1) {
                            if (x > g_dropdown.getWidth() - 25) {
                                c_invokeLater = Invoke.Popup;
                            } else {
                                c_table.getJCTable().cancelEdit(true);
                            }
                        } else if (me.getButton() == MouseEvent.BUTTON2) {
                            c_invokeLater = Invoke.Menu;
                        }
                    }
                } catch (Exception e) {
                    //ignore
                }
            }
            c_testUserEntry = false;
        }
        if (c_invokeLater != null) {
            SwingUtilities.invokeLater(new Invoker());
        }
    }

    @Override
    protected void dropdownMouseClicked(MouseEvent evt) {
        if (evt.getButton() != MouseEvent.BUTTON1) {
            c_table.getJCTable().cancelEdit(true);
            MouseEvent me = c_mouseAdapter.translateEvent(evt); //new MouseEvent ((Component) initialEvent.getSource(), evt.getID(), evt.getWhen(), evt.getModifiers(), x, y, evt.getClickCount(), true, evt.getButton());
            c_table.requestFocusInWindow();
            c_mouseAdapter.mousePressed(me);
        } else if (evt.getClickCount() > 1) {
            c_table.addColumnData();
        } else {            
            //c_table.getJCTable().cancelEdit(true);
        }
    }

    protected void drilldownActionPerformed(ActionEvent evt) {
        c_table.getJCTable().commitEdit(true);
        c_mouseAdapter.openDrillDownScreen();
    }

    /*
     * Invokes the correct action for the user's entry into the editor.
     */
    class Invoker implements Runnable {

        public void run() {
            switch (c_invokeLater) {
                case Popup:
                    if (g_dropdown.isShowing() && !g_dropdown.isPopupVisible()) {
                        g_dropdown.showPopup();
                    //g_dropdown.requestFocusInWindow();
                    }
                    break;
                case Drilldown:
                    c_table.getJCTable().cancelEdit(true);
                    g_drilldown.doClick();
                    break;
                case Menu:
                    c_mouseAdapter.mousePressed((MouseEvent) c_initialEvent);

                    break;
            }
            c_invokeLater = null;
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent event) {
        if (WepsTreeComboBox.PROP_SELECTED_ITEM.equals(event.getPropertyName())) {
            Object selectedItem = event.getNewValue();
            
            if (selectedItem instanceof FileTreeNode) {
                File file = ((FileTreeNode) selectedItem).getFile();
                c_table.addColumnData(file);
                c_table.getJCTable().commitEdit(true);
            }
        }                
    }
    
    private class InternalRootNode extends FileTreeNode{
        public InternalRootNode(File file){
            super(file, getFileFilter());

        }               
        
    }
}
