/*
 * DiffTable.java
 *
 * Created on May 25, 2006, 2:51 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package usda.weru.util.diff.table;

import com.klg.jclass.cell.JCCellInfo;
import com.klg.jclass.cell.JCComponentCellRenderer;
import com.klg.jclass.cell.renderers.JCLabelCellRenderer;
import com.klg.jclass.table.JCSelectEvent;
import com.klg.jclass.table.JCSelectListener;
import com.klg.jclass.table.JCTableEnum;
import com.klg.jclass.table.beans.LiveTable;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Font;
import java.util.Hashtable;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import usda.weru.mcrew.DataObject;
import usda.weru.mcrew.ManageData;
import usda.weru.mcrew.RowInfo;
import usda.weru.resources.Resources;
import usda.weru.util.diff.DiffEngine;
import usda.weru.util.diff.Differ;

/**
 *
 * @author Joseph Levin
 */
public class DiffTable extends LiveTable implements JCSelectListener{
     private DiffTabelModel dataSource;     
     private Hashtable <Integer, Boolean> c_expandedMap;
     private int c_filter;
    /** Creates a new instance of DiffTable */
    public DiffTable() {
        super();
        init();
        initCellRenderers();
        
    }
    
    private void init(){
        c_expandedMap = new Hashtable <Integer, Boolean> ();
        
        //Default data source       
        setDataSource(new DiffTabelModel());
        
        //Selection events
        addSelectListener(this);
        
        
        //Default display
        setColumnHidden(-1, true);
        setAutoscrolls(false);
        setAutoScroll(JCTableEnum.AUTO_SCROLL_NONE);
        setHorizSBPosition(JCTableEnum.POSITION_AT_SIDE);
        setVertSBPosition(JCTableEnum.POSITION_AT_SIDE);
        setSelectionPolicy(JCTableEnum.SELECT_RANGE);
        setAllowResizeBy(JCTableEnum.RESIZE_BY_LABELS);
        setAllowCellResize(JCTableEnum.RESIZE_COLUMN);
        setPopupMenuEnabled(false);
        
        //this.setTrackCursor(false);
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        
        //Cells
        getDefaultCellStyle().setEditable(false);
        
        
        setPixelWidth(0, 160);
        setPixelWidth(1, 100);
        setPixelWidth(2, 1);
        setPixelWidth(3, 1);
        
        autoResizeColumns();

        
        
        //Header
        getDefaultLabelStyle().setBackground(new Color(Integer.parseInt("FFEC8B", 16)));
        getDefaultLabelStyle().setVerticalAlignment(JCTableEnum.CENTER);
        Font headerFont = getDefaultLabelStyle().getFont();
        headerFont = new Font(headerFont.getName(), Font.BOLD, 12);
        getDefaultLabelStyle().setFont(headerFont);
        setPixelHeight(-1, 25);
            
        
    }
    
    private void initCellRenderers(){
         //setCellRenderer(TreeWrapper.class, TreeCellRenderer.class);
        setCellRenderer(TreeWrapper.class, new TreeCellRenderer());
        setCellRenderer(DiffWrapper.class, new DiffCellRenderer());
        setCellRenderer(ManageData.class, WepsObjectsCellRenderer.class);
        setCellRenderer(RowInfo.class, WepsObjectsCellRenderer.class);
        setCellRenderer(DataObject.class, WepsObjectsCellRenderer.class);
    }
        

    public void autoResizeColumns(){        
        int total = 0;
        int[] widths = new int[4];
        for (int c = 0; c < 4; c++){
            widths[c] = getPixelWidth(c);
            total += widths[c];            
        }
        //if (total < getWidth()){
                        
            int valueSpace = getWidth() - widths[0] - widths[1] ;
            JScrollBar vbar = getVertSB();
            if (vbar.isVisible()){
                valueSpace -= vbar.getWidth();
            }
            int half = (int)(valueSpace / 2);
            setPixelWidth(2, half);
            setPixelWidth(3, half);
        //}
    }

    
    
    public void toggleNode(int index){        
        if (isExpanded(index)){
            collapseNode(index);
        }
        else{
            expandNode(index);
        }
        //int a = this.get
        //int b = this.getWidth();
        
        //int x = 0;
    }
    
    public void expandNode(int index){
        c_expandedMap.put(index, true);
        int numDecendants = dataSource.getNumDescendants(index);
        for (int i = 0; i < numDecendants; i++){
            updateVisibility(i + index + 1);
        }
    }
    
    public void collapseNode(int index){
        c_expandedMap.put(index, false);
        int numDecendants = dataSource.getNumDescendants(index);
        for (int i = 0; i < numDecendants; i++){
            updateVisibility(i + index + 1);
        }
        
    }
    
    private void updateVisibility(int index){        
        setRowHidden(index, isHidden(index) || isFilteredOut(index));
    }
    
    private boolean isLeaf(int index){
        return dataSource.getNumDescendants(index) == 0;
    }
    
    private boolean isExpanded(int index){
        boolean expanded;        
        try{
            expanded = c_expandedMap.get(index);
        }
        catch(NullPointerException npe){
            expanded = false;
        }
        return expanded;
    }
    
    private boolean isHidden(int index){
        int parentIndex = dataSource.getParentIndex(index);
        if (parentIndex < 0) return false;
        
        while (parentIndex >= 0){
            if (isExpanded(parentIndex) == false) return true;
            parentIndex = dataSource.getParentIndex(parentIndex);
        }
        return false;        
    }
    
    private boolean isFilteredOut(int index){
        return !isFilteredIn(index);
    }
            
    private boolean isFilteredIn(int index){
        DiffWrapper wrapper = (DiffWrapper) dataSource.getTableDataItem(index, 1);
        int diff = wrapper.getDiff();
        for (int childIndex : dataSource.getDirectChildren(index)){
            if (isFilteredIn(childIndex)) return true;
        }
        if ((diff & c_filter) > 0){
            return true;
        }
        else return false;        
    }
    
    public void setFilter(int filter){
        c_filter = filter;
        for (int index = 0; index < dataSource.getNumRows(); index++){
            updateVisibility(index);
        }
        autoResizeColumns();
    }
    
    //Selection events
    public void beforeSelect(JCSelectEvent  event){
        if (event.getStartColumn() == 0 && event.getStartRow() >= 0){
            toggleNode(event.getStartRow());            
        }
    }
    
    public void select(JCSelectEvent  event){
        
    }
    
    public void afterSelect(JCSelectEvent  event){
         
    }
       

    public void setDataSource(DiffTabelModel model) {
        c_expandedMap = new Hashtable <Integer, Boolean> ();
        dataSource = model;
        super.setDataSource(model);    
        setFilter(c_filter);
        expandChangedNodes();
        
    }
    
    public void ensureVisible(int index){       
       int parentIndex = dataSource.getParentIndex(index);
       while (parentIndex >= 0){
           expandNode(parentIndex);
           parentIndex = dataSource.getParentIndex(parentIndex);
       }
    }
    
    public void expandChangedNodes(){
        for (int i = 0; i < dataSource.getNumRows(); i ++){            
            Object o = dataSource.getTableDataItem(i, 1);
            DiffWrapper wrapper = (DiffWrapper) o;
            int diff = wrapper.getDiff();
            if (DiffEngine.bitFlag(diff, Differ.DIFF_SAME) == false){
                ensureVisible(i);
            }
            
        }
    }
        

    public DiffTabelModel getDataSource() {
        return dataSource;
    }
    
    class TreeCellRenderer implements JCComponentCellRenderer{
        private DefaultTreeCellRenderer c_renderer;
        private JTree c_tree;
        private static final int NODE_SPACING = 10;
        /**
         * Creates a new instance of TreeCellRenderer
         */
        public TreeCellRenderer() {
            c_renderer = new DefaultTreeCellRenderer();
            c_tree = new JTree();
            
            c_renderer.setOpenIcon(Resources.getIcon("openfolder.gif"));
            c_renderer.setClosedIcon(Resources.getIcon("folder.gif"));


        }

        public Component getRendererComponent(JCCellInfo cellInfo, Object o, boolean selected){
            TreeWrapper wrapper = (TreeWrapper) o;
            int index = wrapper.getIndex();
            int depth = wrapper.getDepth();
            String text = wrapper.getText();
            boolean expanded = isExpanded(index);
            boolean leaf = !wrapper.hasChildren();
            boolean hasFocus = false;
        
            JPanel panel = new JPanel(null);        
            Component component = c_renderer.getTreeCellRendererComponent(c_tree, text, selected, expanded, leaf, 1, hasFocus);                
            
            int fillerWidth = (depth - 1) * NODE_SPACING;
            panel.add(component);  
            panel.setBackground(cellInfo.getBackground());        
            component.setLocation(fillerWidth, -2);
            component.setSize(component.getPreferredSize());
            return panel;
        }

    }
    
    class DiffCellRenderer extends JCLabelCellRenderer{

        /** Creates a new instance of DiffCellRenderer */
        public DiffCellRenderer() {
            super();
        }

        public Component getRendererComponent(JCCellInfo cellInfo, Object o, boolean selected) {
            DiffWrapper wrapper = (DiffWrapper) o;
            int index = wrapper.getIndex();
            int diff;
            boolean expanded = isExpanded(index);
            boolean leaf = isLeaf(index);
            if (expanded){
                diff = wrapper.getDiff();            
            }
            else{
                diff = wrapper.getDiffRecursive();
            }
            
            String text = "";
            

            //Changed values
            if (leaf || expanded){
                if (DiffEngine.bitFlag(diff, Differ.DIFF_UNKNOWN)){
                text = text + bold(font("#CCCCCC", "?"));   //Gray
                } 
                if (DiffEngine.bitFlag(diff, Differ.DIFF_SAME) && DiffEngine.bitFlag(c_filter, Differ.DIFF_SAME)){
                    text += font("BLACK", "Same");
                } 
                if (DiffEngine.bitFlag(diff, Differ.DIFF_INCREASED)){
                    text = text + bold(font("BLUE", "Increased"));
                } 
                else if (DiffEngine.bitFlag(diff, Differ.DIFF_DECREASED)){
                    text = text + bold(font("BLUE", "Decreased"));
                } 
                else if (DiffEngine.bitFlag(diff, Differ.DIFF_CHANGED)){
                    text = text + font("BLUE", "Changed");
                } 

                if (DiffEngine.bitFlag(diff, Differ.DIFF_ADDED)){
                    text = text + bold(font("GREEN", "Added"));
                } 

                if (DiffEngine.bitFlag(diff, Differ.DIFF_REMOVED)){
                    text = text + bold(font("RED", "Removed"));
                } 


                if (DiffEngine.bitFlag(diff, Differ.DIFF_ERROR)){
                    text = bold(font("RED", "ERROR"));
                } 
            }
            else{
                if (DiffEngine.bitFlag(diff, Differ.DIFF_CHANGED)){
                    text = bold(font("BLUE", "Changed"));
                }
                else{
                    text = font("BLACK", "Same");
                }
            }

            setText(html(text));
            setBackground(selected ? cellInfo.getSelectedBackground() : cellInfo.getBackground());
            setForeground(selected ? cellInfo.getSelectedForeground() : cellInfo.getForeground());
            setHorizontalAlignment(cellInfo.getHorizontalAlignment());
            setVerticalAlignment(cellInfo.getVerticalAlignment());
            return(this);
        }

        private String font(String color, String text){
            return "<font color=" + color + ">" + text + "</font>";
        }

        private String html(String text){
            return "<HTML>" + text + "</HTML>";
        }
        
        private String bold(String text){
            return "<b>" + text + "</b>";
        }
    }

    
}

