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.connection.ConnectionController;
import com.mars.helios.heliosweb.client.fieldpicker.FieldPickerFactory;
import com.mars.helios.heliosweb.client.i18n.Messages;
import com.mars.helios.heliosweb.client.screen.FormStateChangeHandler;
import com.mars.helios.heliosweb.client.screen.maintainxref.HeliosXRefValueRecords.CrossReferenceValueField;
import com.mars.helios.heliosweb.shared.domain.ConditionalCrossReferenceValue;
import com.mars.helios.heliosweb.shared.domain.CrossReference;
import com.mars.helios.heliosweb.shared.domain.CrossReference.CrossReferenceDimension;
import com.mars.helios.heliosweb.shared.domain.CrossReferenceValue;
import com.mars.helios.heliosweb.shared.domain.FieldDaoIdentifier;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.AutoFitWidthApproach;
import com.smartgwt.client.types.ListGridEditEvent;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.events.CloseClickEvent;
import com.smartgwt.client.widgets.events.CloseClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.UploadItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.CellClickEvent;
import com.smartgwt.client.widgets.grid.events.CellClickHandler;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Represents the grid component contained into the cross reference screen
 * 
 * @author Bertrand Chevrier <bertrand.chevrier@logica.com>
 */
@Singleton
public class HeliosXrefValuesGrid extends VLayout {

    private Messages i18n = GWT.create(Messages.class);
    @Inject private HeliosXRefValueRecords records;
    @Inject private FieldPickerFactory fieldPickerFactory;
    @Inject private ConnectionController connectionController;
    private ListGrid grid;
    private ToolStrip actionBar;
    private ToolStripButton newButton;
    private ToolStripButton deleteButton;
    private ToolStripButton deleteAllButton;
    private ToolStripButton copyValuesButton;
    private ToolStripButton uploadValuesButton;
    private ToolStripButton saveValuesButton;
    private CrossReference crossReference;
    private FormStateChangeHandler formStateChangeHandler;
    
    @Inject
    public HeliosXrefValuesGrid(FormStateChangeHandler formStateChangeHandler) {
        
        this.formStateChangeHandler = formStateChangeHandler;
        
        this.setWidth(520);
        this.setHeight(300);
        this.setPadding(10);

        buildGrid();
        
        buildActionBar();
        
        initFormEvents();
        
        this.addMember(grid);
        this.addMember(actionBar);
    }
    
    /**
     * Build the grid component
     */
    private void buildGrid(){
        grid = new ListGrid();
        grid.setWidth100();
        grid.setHeight(250);
        grid.setCanRemoveRecords(false);
        grid.setCanSort(true);
        grid.setCanResizeFields(true);
        grid.setShowAllRecords(true);
        grid.setEditEvent(ListGridEditEvent.CLICK);
        grid.setEditByCell(true);
        grid.setModalEditing(true);
        grid.setAutoFitWidthApproach(AutoFitWidthApproach.BOTH);
    }
    
    /**
     * Build the grid action bar
     */
    private void buildActionBar(){
        actionBar = new ToolStrip();
        actionBar.setWidth100();
        actionBar.setAlign(Alignment.CENTER);
        
        newButton = new ToolStripButton(i18n.common_new(), "icons/table_row_insert.png");
        deleteButton = new ToolStripButton(i18n.common_delete(), "icons/table_row_delete.png");
        deleteAllButton = new ToolStripButton(i18n.common_delete_all(), "icons/table_delete.png");
        copyValuesButton = new ToolStripButton(i18n.common_copy_values(), "icons/table_multiple.png");
        uploadValuesButton = new ToolStripButton(i18n.common_upload_values(), "icons/table_gear.png");
        saveValuesButton = new ToolStripButton(i18n.common_save(), "icons/table_save.png");
        
        actionBar.addButton(newButton);
        actionBar.addButton(deleteButton);
        actionBar.addButton(deleteAllButton);
        actionBar.addButton(copyValuesButton);
        actionBar.addButton(uploadValuesButton);
        actionBar.addButton(saveValuesButton);
    }
    
    /**
     * Bind events
     */
    private void initFormEvents(){
        newButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                grid.startEditingNew();
                formStateChangeHandler.setChangedState();
            }
        });
        deleteButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                removeRecords(grid.getSelectedRecords());
            }
        });
        deleteAllButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                removeRecords(grid.getRecords());
            }
        });
        copyValuesButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                buildCopyValuesFieldPicker();
            }
        });
        uploadValuesButton.addClickHandler(new ClickHandler() {
            
            @Override
            public void onClick(ClickEvent event) {
                  buildUploadPopup();
            }
        });
        grid.addCellClickHandler(new CellClickHandler() {

            @Override
            public void onCellClick(CellClickEvent event) {
                if(grid.getCanEdit()){
                    String fieldName = grid.getFieldName(event.getColNum());
                    if(crossReference.isConditional()){
                        if(fieldName.equals(CrossReferenceValueField.FROM_ID.name())){
                            buildNodeIdFieldPicker(event.getRecord(), CrossReferenceValueField.FROM_ID);
                        } else if(fieldName.equals(CrossReferenceValueField.TO_ID.name())){
                            buildNodeIdFieldPicker(event.getRecord(), CrossReferenceValueField.TO_ID);
                        }
                    } else {
                        if(fieldName.equals(CrossReferenceValueField.NODE_ID.name())){
                            buildNodeIdFieldPicker(event.getRecord(), CrossReferenceValueField.NODE_ID);
                        }
                    }
                }
            }
        });
    }
    
    /**
     * Build the upload file popup
     * @return the modal popup
     */
    private Window buildUploadPopup() {
        final Window popup = new Window();
        popup.setWidth(400);
        popup.setHeight(150);
        popup.setTitle(i18n.common_upload_values());
        popup.setShowMinimizeButton(false);
        popup.setIsModal(true);
        popup.setShowModalMask(true);
        popup.centerInPage();
        popup.addCloseClickHandler(new CloseClickHandler() {

            @Override
            public void onCloseClick(CloseClickEvent event) {
                popup.destroy();
            }
        });
        DynamicForm form = new DynamicForm();
        form.setHeight100();
        form.setWidth100();
        form.setPadding(5);

        UploadItem upload = new UploadItem();
        upload.setTitle("Upload new mapping");

        form.setFields(upload);

        popup.addItem(form);
        popup.show();
        return popup;
    }
    
    /**
     * Build the field picker used to copy values
     * @return the field picker instance
     */
    private Window buildCopyValuesFieldPicker() {
        Window fieldPicker = fieldPickerFactory.createFieldPicker(
                FieldDaoIdentifier.XREF,
                connectionController.getMoe().getId(), this.crossReference.getId(),
                false, 
                new CopyValuesFieldPickerCallback(this)
            );
        fieldPicker.show();
        return fieldPicker;
    }
    
    /**
     * Build the field picker used to select the right node id
     * @return the field picker instance
     */
    private Window buildNodeIdFieldPicker(Record record, CrossReferenceValueField field) {
        FieldDaoIdentifier daoIdentifier = FieldDaoIdentifier.LISTMOE;
        
        if(crossReference.getFromDimension().equals(crossReference.getToDimension())){
            if(crossReference.getToDimension().equals(CrossReferenceDimension.ITEM)){
                daoIdentifier = FieldDaoIdentifier.LISTITEM;
            }
            if(crossReference.getToDimension().equals(CrossReferenceDimension.LINE_ITEM)){
                daoIdentifier = FieldDaoIdentifier.LISTLINE;
            }
            if(crossReference.getToDimension().equals(CrossReferenceDimension.CUSTOMER)){
                daoIdentifier = FieldDaoIdentifier.LISTCUSTOMER;
            }
        }
        Window fieldPicker = fieldPickerFactory.createFieldPicker(
                daoIdentifier, null, null, false, 
                new SelectNodeIdFieldPickerCallback(this, record, daoIdentifier, field)
            );
        fieldPicker.show();
        return fieldPicker;
    }
    
    /**
     * Load the grid values (fields and records)
     */
    protected void loadValues(){
        records.init(crossReference);
        grid.setFields(records.getFields());
        grid.setData(records);
        grid.refreshFields();
    }
    
    /**
     * Reload the grid values (only records)
     * @param records the records to reload
     */
    protected void reloadRecords(ListGridRecord[] records) {
        grid.setRecords(records);
        formStateChangeHandler.setChangedState();
    }
    
    /**
     * Clear the grid completely (fields and records)
     */
    protected void clearAll(){
        grid.setData(new ListGridRecord[0]);
        grid.setFields(new ListGridField[0]);
        grid.refreshFields();
    }
    
    /**
     * Add new values to the grid (only records)
     * @param crossReference that contains the values
     */
    protected void addValues(CrossReference crossReference) {
        records.addValues(crossReference);
        grid.setData(records);
        formStateChangeHandler.setChangedState();
    }
    
    /**
     * Remove record from the grid
     * @param records the record to remove
     */
    private void removeRecords(Record[] records){
         if (records.length > 0) {
            for (Record record : records) {
                grid.removeData(record);
            }
             formStateChangeHandler.setChangedState();
        }
    }
    
    /**
     * Disable the grid and the buttons
     */
    @Override
    public void disable(){
        this.grid.setCanEdit(false);
        this.actionBar.disable();
    }
    
    /**
     * Enable the grid and the buttons
     */
    @Override
    public void enable(){
        this.grid.setCanEdit(true);
        this.actionBar.enable();
    }
    
    /**
     * Get the list of CrossReferenceValue using the grid data
     * @return the values
     */
    public List<CrossReferenceValue> getFromGrid(){
        List<CrossReferenceValue> values = new ArrayList<CrossReferenceValue>();
        
        Map<CrossReferenceValueField, ListGridField> currentFields = records.getCurrentFields();
        
        for (ListGridRecord rec : grid.getRecords()) {
            
            if (crossReference.isConditional()) {
                ConditionalCrossReferenceValue value = new ConditionalCrossReferenceValue();
                value.setId(rec.getAttribute(CrossReferenceValueField.TO_ID.name()));
                value.setDescription(rec.getAttribute(CrossReferenceValueField.TO_DESC.name()));
                CrossReferenceValue fromValue = new CrossReferenceValue();
                fromValue.setId(rec.getAttribute(CrossReferenceValueField.FROM_ID.name()));
                fromValue.setDescription(rec.getAttribute(CrossReferenceValueField.FROM_DESC.name()));
                value.setFromValue(fromValue);
                if (currentFields.containsKey(CrossReferenceValueField.FACTOR)) {
                    value.setFactor(Integer.valueOf(rec.getAttribute(CrossReferenceValueField.FACTOR.name())));
                }
                values.add(value);
            } else {
                CrossReferenceValue value = new CrossReferenceValue();
                value.setId(rec.getAttribute(CrossReferenceValueField.NODE_ID.name()));
                value.setExternalReference(rec.getAttribute(CrossReferenceValueField.EXT_REF.name()));
                value.setDescription(rec.getAttribute(CrossReferenceValueField.DESC.name()));
                if (currentFields.containsKey(CrossReferenceValueField.FACTOR)) {
                    value.setFactor(Integer.valueOf(rec.getAttribute(CrossReferenceValueField.FACTOR.name())));
                }
                values.add(value);
            }
        }
        return values;
    }
    
    public ListGrid getGrid() {
        return this.grid;
    }
    
    public ToolStripButton getSaveValuesButton() {
        return this.saveValuesButton;
    }
    
    public void setCrossReference(CrossReference crossReference){
        this.crossReference = crossReference;
    }
}
