/*
 * $Id$
 *
 * JSDAI(TM), a way to implement STEP, ISO 10303
 * Copyright (C) 1997-2008, LKSoftWare GmbH, Germany
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation (AGPL v3).
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * JSDAI is a registered trademark of LKSoftWare GmbH, Germany
 * This software is also available under commercial licenses.
 * See also http://www.jsdai.net/
 */

package jsdai.edit;

import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import java.util.List;
import java.util.*;

import jsdai.lang.*;
import jsdai.beans.*;
import jsdai.SMapping_schema.*;
import jsdai.SExtended_dictionary_schema.*;
import jsdai.edit.SdaiEdit;

/**
 *
 * @author  Vaidas Narg�las
 */
public class MapEditEntitiesPanel extends SdaiPanel {
    
    public static final int ALL_ENTITIES = 1;

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.JPanel north;
	private javax.swing.JLabel label1;
	private javax.swing.JComboBox comboUofs;
	private javax.swing.JPanel instancePanel;
	private javax.swing.JScrollPane instanceScroll;
	private jsdai.beans.GoList instances;
	private javax.swing.JPanel bar;
	private javax.swing.JButton create;
	private javax.swing.JButton delete;
	private javax.swing.JButton buttonGet;
	// End of variables declaration//GEN-END:variables
    
    /** Holds value of property model. */
    private SdaiModel model;    

    /** Holds value of property model. */
    private SchemaInstance schemaInstance;

    /** Holds value of property mappingDomain. */
    private ASdaiModel mappingDomain;
    
    /** ARM (source) model of DICTIONARY schema.  */
    private SdaiModel armModel;
    
    /** ARM (source) schema name.  */
    private String armName;
    
    private ArrayList uofs;
    
    /** Holds value of property selectedUof.  */
    private Object selectedUof = null;
    
    private ArrayList armEntities;

    private UofListModel uofListModel = new UofListModel();
    
    private ArmListModel armListModel = new ArmListModel();

    /** Creates new form MappingEditor */
    public MapEditEntitiesPanel() {
        initComponents();
        model = null;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
	private void initComponents() {//GEN-BEGIN:initComponents
		north = new javax.swing.JPanel();
		label1 = new javax.swing.JLabel();
		comboUofs = new javax.swing.JComboBox();
		instancePanel = new javax.swing.JPanel();
		instanceScroll = new javax.swing.JScrollPane();
		instances = new jsdai.beans.GoList();
		bar = new javax.swing.JPanel();
		create = new javax.swing.JButton();
		delete = new javax.swing.JButton();
		buttonGet = new javax.swing.JButton();
		
		setLayout(new java.awt.BorderLayout());
		
		north.setLayout(new java.awt.GridBagLayout());
		java.awt.GridBagConstraints gridBagConstraints1;
		
		label1.setText("UOFs");
		label1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
		gridBagConstraints1 = new java.awt.GridBagConstraints();
		gridBagConstraints1.gridx = 0;
		gridBagConstraints1.gridy = 0;
		gridBagConstraints1.insets = new java.awt.Insets(0, 0, 0, 5);
		gridBagConstraints1.anchor = java.awt.GridBagConstraints.EAST;
		north.add(label1, gridBagConstraints1);
		
		comboUofs.setModel(uofListModel);
		comboUofs.setMaximumRowCount(15);
		comboUofs.setRenderer(new UofCellRenderer());
		gridBagConstraints1 = new java.awt.GridBagConstraints();
		gridBagConstraints1.gridx = 1;
		gridBagConstraints1.gridy = 0;
		gridBagConstraints1.fill = java.awt.GridBagConstraints.HORIZONTAL;
		gridBagConstraints1.weightx = 1.0;
		north.add(comboUofs, gridBagConstraints1);
		
		add(north, java.awt.BorderLayout.NORTH);
		
		instancePanel.setLayout(new java.awt.BorderLayout());
		
		instancePanel.setBorder(new javax.swing.border.TitledBorder(new javax.swing.border.MatteBorder(new java.awt.Insets(1, 0, 0, 0), java.awt.Color.gray), "Entities"));
		instanceScroll.setViewportBorder(new javax.swing.border.CompoundBorder());
		instances.setModel(armListModel);
		instances.setBackground(instancePanel.getBackground());
		instances.setCellRenderer(new ArmCellRenderer());
		instances.setUnderlying(true);
		instances.addGoListener(new EntityMappingsGoListener());
		instanceScroll.setViewportView(instances);
		
		instancePanel.add(instanceScroll, java.awt.BorderLayout.CENTER);
		
		add(instancePanel, java.awt.BorderLayout.CENTER);
		
		bar.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));
		
		create.setText("Create");
		create.setEnabled(false);
		bar.add(create);
		
		delete.setText("Delete");
		delete.setEnabled(false);
		bar.add(delete);
		
		buttonGet.setText("Get");
		buttonGet.setEnabled(false);
		bar.add(buttonGet);
		
		add(bar, java.awt.BorderLayout.SOUTH);
		
	}//GEN-END:initComponents

    public void pushChainElementValues(List list) throws SdaiException {
        list.add(getSchemaInstanceOrModel());
        // This is not working well because of strange handling of ChainElements
//        list.add(new Integer(getComboUofsIndex()));
//        list.add(new Integer(getInstancesIndex()));
    }
    
    public void popChainElementValues(List list) throws SdaiException {
        setSchemaInstanceOrModel(list.get(0));
        // See coment above
//        setComboUofsIndex(((Integer)list.get(1)).intValue());
//        setInstancesIndex(((Integer)list.get(2)).intValue());
    }
    
    public Object getSchemaInstanceOrModel() {
        if(schemaInstance != null)
            return getSchemaInstance();
        else
            return getModel();
    }

    public void setSchemaInstanceOrModel(Object obj) throws SdaiException {
        if(obj instanceof SchemaInstance)
            setSchemaInstance((SchemaInstance)obj);
        else
            setModel((SdaiModel)obj);
    }
    
    /** Getter for property model.
     */
    public SdaiModel getModel() {
        return model;
    }
    
    /** Setter for property model.
     * @param model New value of property model.
     */
    public boolean setModel(SdaiModel model) throws SdaiException {
        if(!model.getUnderlyingSchemaString().equals("MAPPING_SCHEMA"))
            return false;
        this.model = model;
        schemaInstance = null;
        mappingDomain =  new ASdaiModel();
        mappingDomain.addByIndex(1, model, null);
        
        refreshData();
        return true;
    }
    
    /** Getter for property schemaInstance.
     * @return Value of property schemaInstance.
     */
    public SchemaInstance getSchemaInstance() {
        return schemaInstance;
    }
    
    /** Setter for property schemaInstance.
     * @param schemaInstance New value of property schemaInstance.
     */
    public boolean setSchemaInstance(SchemaInstance schemaInstance) throws SdaiException {
        ASdaiModel models = schemaInstance.getAssociatedModels();
        SdaiIterator modelterator = models.createIterator();
        boolean isMappingSchema = false;
        while(modelterator.next()) {
             SdaiModel currentModel = models.getCurrentMember(modelterator);
             if(currentModel.getUnderlyingSchemaString().equals("MAPPING_SCHEMA")) {
                 model = currentModel;
                 isMappingSchema = true;
                 break;
             }
        }
        if(!isMappingSchema) return false;
        
        this.schemaInstance = schemaInstance;
        mappingDomain = models;
        
        refreshData();
        return true;
    }
    
    public void refreshData() {
        try {
            // Get source model and this model entity definitions
            ESchema_mapping schemaMapping =
                (ESchema_mapping)model.getInstances(ESchema_mapping.class).getByIndexEntity(1);
            ESchema_definition armSchemaDefinition = schemaMapping.getSource(null);
            armModel = armSchemaDefinition.findEntityInstanceSdaiModel();
            armName = armSchemaDefinition.getName(null);
            
            // Get UOFs
            int oldComboUofsIndex = comboUofs.getSelectedIndex();
            int oldInstancesIndex = instances.getSelectedIndex();
            uofListModel.fireRemoved();
            uofs = new ArrayList();
            AEntity uofMappings = model.getInstances(EUof_mapping.class);
            SdaiIterator uofIterator = uofMappings.createIterator();
            while(uofIterator.next()) {
                EUof_mapping uofMapping = (EUof_mapping)uofMappings.getCurrentMemberEntity(uofIterator);
                uofs.add(uofMapping);
            }
            Collections.sort(uofs, new UofComparator());
            selectedUof = null;
            uofListModel.fireAdded();
			int newUofIndex = oldComboUofsIndex >= 0 && 
                oldComboUofsIndex < comboUofs.getItemCount() ? oldComboUofsIndex : 0;
			if(comboUofs.getItemCount() > 0) {
				comboUofs.setSelectedIndex(newUofIndex);
			}
//             instances.setSelectedIndex(oldInstancesIndex >= 0 && 
//                 oldInstancesIndex < instances.getModel().getSize() ? oldInstancesIndex : 0);
			setSelectedUof(uofListModel.getElementAt(newUofIndex));
        } catch (SdaiException e) {
            processMessage(e);
        }
    }
    
    /** Setter for property selectedUof.
     * @param selectedUof Selected UOF. Give ALL_ENTITIES if you want to select all UOFs
     */
    public void setSelectedUof(Object selectedUof) throws SdaiException {
        if(this.selectedUof == null || !this.selectedUof.equals(selectedUof)) {
            int oldInstancesIndex = instances.getSelectedIndex();
            armListModel.fireRemoved();
            TreeMap armMap = new TreeMap();
            this.selectedUof = selectedUof;
            AEntity entityMapings = selectedUof.equals(new Integer(ALL_ENTITIES)) ?
                model.getInstances(EEntity_mapping.class)
                : ((EUof_mapping)selectedUof).getMappings(null);
            
            SdaiIterator eMapppingIterator = entityMapings.createIterator();
            while(eMapppingIterator.next()) {
                EEntity_mapping entityMapping =
                (EEntity_mapping)entityMapings.getCurrentMemberEntity(eMapppingIterator);
                EEntity_definition armEntity = entityMapping.getSource(null);
                String armEntityName = armEntity.getName(null);
                MapEditEntityInfo mapEditEntityInfo = (MapEditEntityInfo)armMap.get(armEntityName);
                if(mapEditEntityInfo == null) {
                    mapEditEntityInfo = new MapEditEntityInfo(armEntity);
                    mapEditEntityInfo.mappings.add(entityMapping);
                    armMap.put(armEntityName, mapEditEntityInfo);
                } else {
                    mapEditEntityInfo.mappings.add(entityMapping);
                }
            }
            armEntities = new ArrayList(armMap.values());
            armListModel.fireAdded();
            instances.setSelectedIndex(oldInstancesIndex >= 0 && 
                oldInstancesIndex < instances.getModel().getSize() ? oldInstancesIndex : 0);
        }
    }
    
    /** Getter for property mappingDomain.
     * @return Value of property mappingDomain.
     */
    public ASdaiModel getMappingDomain() {
        return mappingDomain;
    }
    
    /** Getter for property comboUofsIndex.
     * @return Value of property comboUofsIndex.
     */
    public int getComboUofsIndex() {
        return comboUofs.getSelectedIndex();
    }
    
    /** Setter for property comboUofsIndex.
     * @param comboUofsIndex New value of property comboUofsIndex.
     */
    public void setComboUofsIndex(int comboUofsIndex) {
        comboUofs.setSelectedIndex(comboUofsIndex >= 0 && 
            comboUofsIndex < comboUofs.getItemCount() ? comboUofsIndex : 0);
    }
    
    /** Getter for property instancesIndex.
     * @return Value of property instancesIndex.
     */
    public int getInstancesIndex() {
        return instances.getSelectedIndex();
    }
    
    /** Setter for property instancesIndex.
     * @param instancesIndex New value of property instancesIndex.
     */
    public void setInstancesIndex(int instancesIndex) {
        instances.setSelectedIndex(instancesIndex >= 0 && 
            instancesIndex < instances.getModel().getSize() ? instancesIndex : 0);
    }
    
	public String getTreeLeave() throws SdaiException {
		if (schemaInstance == null && model == null) {
			return "";
		} else {
            if(schemaInstance != null)
                return "/" + schemaInstance.getRepository().getName() + "/" +
                       schemaInstance.getName() + "/MappingEditor";
            else
                return "/" + model.getRepository().getName() + "/" +
                       model.getName() + "/MappingEditor";
		}
	}

    class UofListModel extends AbstractListModel implements ComboBoxModel {
        
        public Object getSelectedItem() {
            return selectedUof;
        }
        
        public void setSelectedItem(Object obj) {
            try {
                setSelectedUof(obj);
            } catch(SdaiException e) {
                e.printStackTrace(System.err);
            }
        }
        
        public int getSize() {
            return uofs == null || uofs.size() == 0 ? 0 : uofs.size() + 1;
        }
        
        public Object getElementAt(int index) {
            return index == 0 ? new Integer(ALL_ENTITIES) : uofs.get(index - 1);
        }

        public void fireRemoved() {
            if(uofs != null)
                fireIntervalRemoved(this, 0, uofs.size());
        }
        
        public void fireAdded() {
            if(uofs != null)
                fireIntervalAdded(this, 0, uofs.size());
        }
    }
    
    static class UofCellRenderer extends BasicComboBoxRenderer {
        
        public Component getListCellRendererComponent(JList list, Object value, int index,
                                                      boolean isSelected, boolean cellHasFocus) {
            String valueText = "...";
            if(value instanceof Integer) {
                int intValue = ((Integer)value).intValue();
                switch(intValue) {
                    case ALL_ENTITIES:
                        valueText = "All";
                        break;
                    default:
                        valueText = "Other";
                }
            }
            else if(value instanceof EUof_mapping) {
                EUof_mapping uofMapping = (EUof_mapping)value;
                try {
                    valueText = uofMapping.getName(null);
                } catch(SdaiException e) {
                    e.printStackTrace(System.err);
                }
            }
            
            super.getListCellRendererComponent(list, valueText, index, isSelected, cellHasFocus);
            
            if(value instanceof Integer) {
                setFont(list.getFont().deriveFont(list.getFont().getStyle() | Font.ITALIC));
            }
            return this;
        }
        
    }
    
    static class UofComparator implements Comparator {
        
        public int compare(Object obj1, Object obj2) {
            if(obj1 instanceof EUof_mapping && obj2 instanceof EUof_mapping) {
                EUof_mapping uofMapping1 = (EUof_mapping)obj1;
                EUof_mapping uofMapping2 = (EUof_mapping)obj2;
                try {
                    return uofMapping1.getName(null).compareTo(uofMapping2.getName(null));
                } catch(SdaiException e) {
                    e.printStackTrace(System.err);
                }
            }
            return 0;
        }
    }

    class ArmListModel extends AbstractListModel {
        
        public int getSize() {
            return armEntities != null ? armEntities.size() : 0;
        }
        
        public Object getElementAt(int index) {
            return armEntities.get(index);
        }

        public void fireRemoved() {
            if(armEntities != null)
                fireIntervalRemoved(this, 0, armEntities.size() - 1);
        }
        
        public void fireAdded() {
            if(armEntities != null)
                fireIntervalAdded(this, 0, armEntities.size() - 1);
        }
    }
    
    static class ArmCellRenderer extends DefaultListCellRenderer {
        
        public Component getListCellRendererComponent(JList list, Object value, int index,
                                                      boolean isSelected, boolean cellHasFocus) {
            String valueText = "...";
            if(value instanceof MapEditEntityInfo) {
                MapEditEntityInfo entityInfo = (MapEditEntityInfo)value;
                try {
                    valueText = entityInfo.entity.getName(null);
                } catch(SdaiException e) {
                    e.printStackTrace(System.err);
                }
            }
            
            super.getListCellRendererComponent(list, valueText, index, isSelected, cellHasFocus);
            return this;
        }
        
    }    
    
    class EntityMappingsGoListener implements GoListener {
        
        public void goPerformed(GoEvent e) {
            fireGo(new GoEvent(MapEditEntitiesPanel.this, e.getValue(), 
                               SdaiEdit.MAPPING_EDITOR_ENTITY_MAPPINGS));
        }
        
    }
    
}
