package com.mars.helios.heliosweb.client.screen.maintainxref;

import com.google.gwt.core.client.GWT;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.mars.helios.heliosweb.client.i18n.Messages;
import com.mars.helios.heliosweb.shared.domain.ConditionalCrossReferenceValue;
import com.mars.helios.heliosweb.shared.domain.CrossReference;
import com.mars.helios.heliosweb.shared.domain.CrossReferenceValue;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RecordList;
import com.smartgwt.client.widgets.grid.ListGridField;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Represents a list of records used by the cross reference values grid
 * 
 * @author Bertrand Chevrier <bertrand.chevrier@logica.com>
 */
@Singleton
public class HeliosXRefValueRecords extends RecordList{

    //The available fields
    public enum CrossReferenceValueField{
        EXT_REF, NODE_ID, DESC, FROM_ID, TO_ID, FROM_DESC, TO_DESC, FACTOR;
    }
    
    private Messages i18n = GWT.create(Messages.class);
    private List<Record> recordList = new ArrayList<Record>();
    private Map<CrossReferenceValueField, ListGridField> fields;
    private List<ListGridField> listGridFields;
    private DimensionValues dimensionValues;
    
    @Inject
    public HeliosXRefValueRecords(DimensionValues dimensionValues){
        this.dimensionValues = dimensionValues;
        this.fields = new EnumMap<CrossReferenceValueField, ListGridField>(CrossReferenceValueField.class);
        this.listGridFields = new ArrayList<ListGridField>();
    }
    
    /**
     * Initialize the record list and the grid fields
     * using a cross reference
     * 
     * @param values the list of cross reference values
     */
    public void init(CrossReference crossReference) {

        if(this.recordList.size() > 0){
            this.removeList(recordList.toArray(new Record[0]));
        }
        
        //we clear the fields map
        fields.clear();
        listGridFields.clear();
        
        recordList.clear();
        
        if(crossReference != null && crossReference.getValues().size() > 0){
        
            setUpFields(crossReference);

            this.addValues(crossReference);
        }
    }
    
    /**
     * Set up the grid fields. They are different regarding the kind of
     * crossReferenceValue 
     * @param crossReferenceValue 
     */
    private void setUpFields(CrossReference crossReference){
        
        //we retrieve the dimension label to display
        String toDimensionLabel = dimensionValues.get(crossReference.getToDimension().name());
        if(crossReference.isConditional()){
            //if the xref is conditionnal, we display the mapping for the from and the to dimension
            
            String fromDimensionLabel = dimensionValues.get(crossReference.getFromDimension().name());
            
            ListGridField fromIdField = new ListGridField(
                        CrossReferenceValueField.FROM_ID.name(), 
                        i18n.screen_xref_grid_node_id(fromDimensionLabel)
                    );
            ListGridField fromDescField = new ListGridField(
                        CrossReferenceValueField.FROM_DESC.name(), 
                        i18n.screen_xref_grid_desc(fromDimensionLabel)
                    );
            fromDescField.setCanEdit(false);
            ListGridField toIdField = new ListGridField(
                        CrossReferenceValueField.TO_ID.name(), 
                        i18n.screen_xref_grid_node_id(toDimensionLabel)
                    );
            ListGridField toDescField = new ListGridField(
                        CrossReferenceValueField.TO_DESC.name(), 
                        i18n.screen_xref_grid_desc(toDimensionLabel)
                    );
            toDescField.setCanEdit(false);
            
            fields.put(CrossReferenceValueField.FROM_ID, fromIdField);
            fields.put(CrossReferenceValueField.FROM_DESC, fromDescField);
            fields.put(CrossReferenceValueField.TO_ID, toIdField);
            fields.put(CrossReferenceValueField.TO_DESC, toDescField);
            
            listGridFields.add(fromIdField);
            listGridFields.add(fromDescField);
            listGridFields.add(toIdField);
            listGridFields.add(toDescField);
           
        } else {
            //for other xref we display the common mapping
            
            ListGridField extRefField = new ListGridField(
                        CrossReferenceValueField.EXT_REF.name(), 
                        i18n.screen_xref_grid_ext_ref(toDimensionLabel)
                    );
            ListGridField nodeIdField = new ListGridField(
                        CrossReferenceValueField.NODE_ID.name(), 
                        i18n.screen_xref_grid_node_id(toDimensionLabel)
                    );
             ListGridField descField = new ListGridField(
                        CrossReferenceValueField.DESC.name(), 
                        i18n.screen_xref_grid_desc(toDimensionLabel)
                    );
             descField.setCanEdit(false);
             
            fields.put(CrossReferenceValueField.EXT_REF, extRefField);
            fields.put(CrossReferenceValueField.NODE_ID, nodeIdField);
            fields.put(CrossReferenceValueField.DESC, descField);
                
            if (crossReference.getDirection().equals(CrossReference.CrossReferenceDirection.INBOUND)) {
                listGridFields.add(extRefField);
                listGridFields.add(nodeIdField);
                listGridFields.add(descField);
            } else {
                listGridFields.add(nodeIdField);
                listGridFields.add(descField);
                listGridFields.add(extRefField);
            }
        }
        
        boolean useFactorField = false;
        for(CrossReferenceValue value : crossReference.getValues()){
            if(value.hasFactor()){
                useFactorField = true;
                break;
            }
        }
        
        if(useFactorField){
            ListGridField factorField = new ListGridField(
                        CrossReferenceValueField.FACTOR.name(), 
                        i18n.screen_xref_grid_factor()
                    );
             factorField.setCanEdit(false);
             fields.put(CrossReferenceValueField.FACTOR, factorField);
             listGridFields.add(factorField);
        }
    }
    
    /**
     * Add values to the record list
     * @param values the cross reference values to add
     */
    public void addValues(CrossReference crossReference){
        
        if(crossReference.isConditional()){
            
            for (CrossReferenceValue value : crossReference.getValues()) {
                Map<String, Object> properties = new HashMap<String, Object>();
                if (value instanceof ConditionalCrossReferenceValue) {
                    ConditionalCrossReferenceValue conditionalValue = (ConditionalCrossReferenceValue) value;
                    properties.put(CrossReferenceValueField.FROM_ID.name(), conditionalValue.getFromValue().getId());
                    properties.put(CrossReferenceValueField.FROM_DESC.name(), 
                          conditionalValue.getFromValue().getDescription());
                    properties.put(CrossReferenceValueField.TO_ID.name(), conditionalValue.getId());
                    properties.put(CrossReferenceValueField.TO_DESC.name(), conditionalValue.getDescription());
                }
                if (fields.containsKey(CrossReferenceValueField.FACTOR)) {
                    properties.put(CrossReferenceValueField.FACTOR.name(), value.getFactor());
                }
                recordList.add(new Record(properties));
            }
        } else {
        
            for (CrossReferenceValue value : crossReference.getValues()) {

                Map<String, Object> properties = new HashMap<String, Object>();
                properties.put(CrossReferenceValueField.EXT_REF.name(), value.getExternalReference());
                properties.put(CrossReferenceValueField.NODE_ID.name(), value.getId());
                properties.put(CrossReferenceValueField.DESC.name(), value.getDescription());
                if(fields.containsKey(CrossReferenceValueField.FACTOR)){
                    properties.put(CrossReferenceValueField.FACTOR.name(), value.getFactor());
                }

                recordList.add(new Record(properties));
            }
        }
        
        this.addList(recordList.toArray(new Record[0]));
    }
    
    /**
     * Get the fields of the grid
     * @return an array of fields
     */
    public ListGridField[] getFields(){
        return this.listGridFields.toArray(new ListGridField[this.listGridFields.size()]);
    }
    
    /**
     * Get the fields of the grid
     * @return a map of fields
     */
    public Map<CrossReferenceValueField, ListGridField> getCurrentFields(){
        return this.fields;
    }
}
