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

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.screen.HeliosScreen;
import com.mars.helios.heliosweb.client.screen.HeliosScreen.UserMessageSeverity;
import com.mars.helios.heliosweb.client.screen.FormActionCallback;
import com.mars.helios.heliosweb.client.screen.FormStateChangeHandler;
import com.mars.helios.heliosweb.shared.domain.CrossReference;
import com.mars.helios.heliosweb.shared.domain.CrossReference.CrossReferenceDimension;
import com.mars.helios.heliosweb.shared.domain.CrossReference.CrossReferenceDirection;
import com.mars.helios.heliosweb.shared.domain.Moe;
import com.mars.helios.heliosweb.shared.service.CrossReferenceServiceAsync;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.fields.HiddenItem;
import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
import com.smartgwt.client.widgets.form.fields.TextAreaItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.validator.LengthRangeValidator;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;
import java.util.logging.Logger;

/**
 * Maintain Cross Reference screen
 * 
 * <strong>Internal call method tree:</strong>
 *  HeliosMaintainXRefScreen (constructor)
 *  --- HeliosScreen#buildScreen
 *  ------ buildContent
 *  --------- initFormFields
 *  --------- initFormValidation
 *  --------- initFormEvents
 *  ------ buildToolBarButtons
 *  --- fillForm (1st filling)
 * 
 * @author Bertrand Chevrier <bertrand.chevrier@logica.com>
 */
@Singleton
public class HeliosMaintainXRefScreen extends HeliosScreen{

    private static final int FIELDSIZE = 400;
    
    private Logger logger = Logger.getLogger(HeliosMaintainXRefScreen.class.getName());

    /** The remote services called by the screen  */
    @Inject
    private CrossReferenceServiceAsync xrefServiceAsync;
    
    /** The form uses a field picker */
    @Inject 
    private FieldPickerFactory fieldPickerFactory;
    
    /** Domain data bound to the form */
    private Moe currentMoe;
    private CrossReference crossReference;
    
    //form fields' components
    private HiddenItem crossReferenceId;
    private TextItem owningMOE;
    private HiddenItem moeId;
    private TextItem crossReferenceName;
    private RadioGroupItem direction;
    private ComboBoxItem toDimension;
    private ComboBoxItem fromDimension;
    private TextItem defaultValue;
    private TextAreaItem description;
    private DynamicForm form;
    private HeliosXrefValuesGrid gridValues;
    
    //action buttons
    private ToolStripButton newButton;
    private ToolStripButton modifyButton;
    private ToolStripButton saveButton;
    private ToolStripButton deleteButton;
    
    private DimensionValues dimensionValues;
    private DirectionValues directionValues;
    
    //handler that listen for changes
    private FormStateChangeHandler formStateChangeHandler;
    
    //to get the session data
    private ConnectionController connectionController;
    
    /**
     * @param connectionController to get the current MOE id
     */
    @Inject
    public HeliosMaintainXRefScreen(ConnectionController connectionController, 
            HeliosXrefValuesGrid gridValues, FormStateChangeHandler formStateChangeHandler, 
            DimensionValues dimensionValues, DirectionValues directionValues){

        this.connectionController = connectionController;
        this.gridValues = gridValues;
        this.formStateChangeHandler = formStateChangeHandler;
        this.dimensionValues = dimensionValues;
        this.directionValues = directionValues;
        
        currentMoe = connectionController.getMoe();
        
        if (currentMoe != null && !currentMoe.isConsolidationSite()) {
            this.dimensionValues.remove(CrossReferenceDimension.UNIT.name());
        }
        
        super.buildScreen();
        
        //set the screen title
        setTitle(i18n.screen_xref_title());
        
        //we load the default data
        fillForm();
    }
    
    /**
     * Method called to fill the form 
     * using the current state data
     */
    protected final void fillForm(){
        
        //1st case (1st time in the screen)
        if(crossReference == null){
            crossReferenceId.setValue("");
            moeId.setValue(currentMoe.getId());
            owningMOE.setValue(currentMoe.getShortDescription());
            crossReferenceName.setValue("");
            direction.setValue(CrossReferenceDirection.INBOUND);
            fromDimension.setValue("");
            toDimension.setValue("");
            defaultValue.setValue("");
            description.setValue("");
            
            gridValues.setCrossReference(null);
            gridValues.clearAll();
        } else {
            //we fill the form with the CrossReference data
            crossReferenceId.setValue(crossReference.getId());
            moeId.setValue(crossReference.getMoeId());
            owningMOE.setValue(crossReference.getOwningMOE());
            crossReferenceName.setValue(crossReference.getName());
            direction.setValue(crossReference.getDirection().name());
            fromDimension.setValue(crossReference.getFromDimension().name());
            toDimension.setValue(crossReference.getToDimension().name());
            defaultValue.setValue(crossReference.getDefaultValue());
            description.setValue(crossReference.getDescription());
            
            gridValues.setCrossReference(crossReference);
            gridValues.loadValues();
        }
    }
    
    /**
     * Instantiate a new CrossReference using the form values
     * @return the new instance
     */
    private CrossReference getFromForm(){
       CrossReference result =  new CrossReference(crossReferenceId.getValue().toString());
       result.setMoeId(moeId.getValue().toString());
       result.setOwningMOE(owningMOE.getValueAsString());
       result.setName(crossReferenceName.getValueAsString());
       result.setDirection(CrossReferenceDirection.valueOf(direction.getValueAsString()));
       result.setFromDimension(CrossReferenceDimension.valueOf(fromDimension.getValueAsString()));
       result.setToDimension(CrossReferenceDimension.valueOf(toDimension.getValueAsString()));
       result.setDefaultValue(defaultValue.getValueAsString());
       result.setDescription(description.getValueAsString());
       return result;
    }
    
    /**
     * We override this method to define which buttons the toolstrip will contain
     * @return the list of button to add to the toolbar
     */
    @Override
    protected ToolStripButton[] buildToolbarButtons() {
        newButton = new ToolStripButton(i18n.common_new(), "icons/new.png");
        modifyButton = new ToolStripButton(i18n.common_modify_values(), "icons/modify.png");
        saveButton = new ToolStripButton(i18n.common_save(), "icons/save.png");
        deleteButton = new ToolStripButton(i18n.common_delete(), "icons/delete.png");
        return new ToolStripButton[]{
                    newButton,
                    modifyButton,
                    saveButton,
                    deleteButton
                };
    }
    
    /**
     * Build and initialize the content of the screen
     * @return the main content component, hier a form
     */
    @Override
    protected Canvas buildContent() {
        
        //create the form fields
        initFormFields();
        
        //initialize the validators
        initFormValidation();
        
        //bind the events to the form fields
        initFormEvents();
        
        //by default the form is disabled
        defaultFormState();
        
        //build the form
        form = new DynamicForm();
        form.setFields(
                crossReferenceId,
                moeId,
                owningMOE, 
                crossReferenceName, 
                direction,
                toDimension,
                fromDimension,
                defaultValue,
                description
            );
        form.setAutoFocus(true);  
        form.setWidth(600);
        form.setPadding(10);
        
        VLayout vlayout = new VLayout();
        vlayout.addMember(form);
        vlayout.addMember(gridValues);
        
        return vlayout;
    }
    
    /**
     * Build and initialize the form fields at their default state
     */
    private void initFormFields(){
        
        //xref id
        crossReferenceId = new HiddenItem();
        
        //moe id
        moeId = new HiddenItem();
        
        //Owning MOE text field
        owningMOE = new TextItem();
        owningMOE.setTitle(i18n.screen_xref_form_owning_moe());
        owningMOE.setWidth(FIELDSIZE);
        
        //Cross Reference Name text field

        crossReferenceName = new TextItem();
        crossReferenceName.setTitle(i18n.screen_xref_form_xref_name());
        crossReferenceName.setWidth(FIELDSIZE);
        
        //uses the default icon : "[SKIN]/DynamicForm/default_formItem_icon.gif"
        crossReferenceName.setIcons(new FormItemIcon());
        
        //Direction radio button
        direction = new RadioGroupItem();
        direction.setVertical(true);
        direction.setValueMap(directionValues);
        direction.setDefaultValue(CrossReferenceDirection.INBOUND.name());
        direction.setTitle(i18n.screen_xref_form_direction());
        
        //Dimesions Comboboxes
        toDimension = new ComboBoxItem("toDimension");
        toDimension.setTitle(i18n.screen_xref_form_dimension_to());
        toDimension.setWidth(FIELDSIZE);
        toDimension.setValueMap(dimensionValues);
        toDimension.setCompleteOnTab(true);
        
        fromDimension = new ComboBoxItem("fromDimension");
        fromDimension.setTitle(i18n.screen_xref_form_dimension_from());
        fromDimension.setWidth(FIELDSIZE);
        fromDimension.setValueMap(dimensionValues);
        fromDimension.setCompleteOnTab(true);
        
        defaultValue = new TextItem();
        defaultValue.setTitle(i18n.screen_xref_form_default_value());
        defaultValue.setWidth(FIELDSIZE);
        
        description = new TextAreaItem();
        description.setTitle(i18n.screen_xref_form_description());
        description.setWidth(FIELDSIZE);
    }
    
    /**
     * Bind the events and the related behaviors
     */
    private void initFormEvents(){
        
        //listening for any change on the form
        owningMOE.addChangedHandler(this.formStateChangeHandler);
        crossReferenceName.addChangedHandler(this.formStateChangeHandler);
        direction.addChangedHandler(this.formStateChangeHandler);
        toDimension.addChangedHandler(this.formStateChangeHandler);
        fromDimension.addChangedHandler(this.formStateChangeHandler);
        defaultValue.addChangedHandler(this.formStateChangeHandler);
        description.addChangedHandler(this.formStateChangeHandler);
        
        //open a tree picker by clicking the icon right to the xref name field
        crossReferenceName.addIconClickHandler(
                    new OpenXRefFieldPickerHandler(this, fieldPickerFactory, currentMoe.getId())
                );
        
        //change dimension check
        toDimension.addChangedHandler(new ChangeDimensionHandler(this, false));
        fromDimension.addChangedHandler(new ChangeDimensionHandler(this, true));
        
        /*
         * Bind events to the action buttons
         */
        
        final FormStateChangeChecker formStateChangeChecker = new FormStateChangeChecker(this);
        newButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                if (!formStateChangeChecker.performCheck(new BooleanCallback() {

                    @Override
                    public void execute(Boolean value) {
                        if (!value) {
                            clearForm();
                            newFormState();
                        }
                    }
                })) {
                    clearForm();
                    newFormState();
                }
            }
        });
        
        modifyButton.addClickHandler(new ClickHandler() {
            
            @Override
            public void onClick(ClickEvent event) {
                if (!formStateChangeChecker.performCheck(new BooleanCallback() {

                    @Override
                    public void execute(Boolean value) {
                        if (!value) {
                            modifyFormState();
                        }
                    }
                })) {
                    modifyFormState();
                }
            }
        });
        
        saveButton.addClickHandler(new ClickHandler() {
            
            @Override
            public void onClick(ClickEvent event) {
               performSave();
            }
        });
        
        final DeleteXRefCallback deleteCallback = new DeleteXRefCallback(this);
        deleteButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                if (crossReference != null) {
                    SC.ask(i18n.screen_xref_alert_confirm_delete(), new BooleanCallback() {

                        @Override
                        public void execute(Boolean value) {
                            if (value.equals(Boolean.TRUE)) {
                                xrefServiceAsync.remove(crossReference, deleteCallback);
                            }
                        }
                    });
                }
            }
        });
        
        //grid values saving
        final FormActionCallback saveValuesCallback = new FormActionCallback(
                this, 
                i18n.screen_xref_info_values_saved(), 
                i18n.screen_xref_err_values_not_saved()
            );
        gridValues.getSaveValuesButton().addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
               crossReference.setValues(gridValues.getFromGrid());
               xrefServiceAsync.saveValues(crossReference, saveValuesCallback);
            }
        });
    }
    
    /**
     * Initialize the validators on the fields
     */
    private void initFormValidation(){
        crossReferenceName.setRequired(true);
        crossReferenceName.setRequiredMessage(i18n.screen_xref_validation_xref_name_required());
        
        DimensionValidator dimensionValidator = new DimensionValidator(this);
        
        toDimension.setRequired(true);
        toDimension.setRequiredMessage(i18n.screen_xref_validation_todim_required());
        toDimension.setValidators(dimensionValidator);
        
        fromDimension.setRequired(true);
        fromDimension.setRequiredMessage(i18n.screen_xref_validation_fromdim_required());
        fromDimension.setValidators(dimensionValidator);
        
        direction.setRequired(true);
        direction.setRequiredMessage(i18n.screen_xref_validation_dir_required());
        
        description.setLength(300);
        
        LengthRangeValidator lenghtValidator = new LengthRangeValidator();
        lenghtValidator.setMin(0);
        lenghtValidator.setMax(300);
        description.setValidators(lenghtValidator);
    }
    
    /**
     * En/Disabled state of the form by default
     */
    protected void defaultFormState(){
        owningMOE.disable();
        crossReferenceName.enable();
        direction.enable();
        toDimension.disable();
        fromDimension.disable();
        defaultValue.disable();
        description.disable();
        gridValues.disable();
    }
    
    /**
     * En/Disabled state of the form when adding an new xref
     */
    protected void newFormState(){
        owningMOE.disable();
        crossReferenceName.enable();
        direction.enable();
        toDimension.enable();
        fromDimension.enable();
        defaultValue.enable();
        description.enable();
        gridValues.disable();
    }
    
    /**
     * En/Disabled state of the form when modifying an xref
     */
    private void modifyFormState(){
        if(crossReference == null){
            displayUserMessage(UserMessageSeverity.Error, i18n.screen_xref_warn_not_selected());
        } else {
            if (currentMoe.getAncestors().contains(crossReference.getMoeId())) {
                displayUserMessage(UserMessageSeverity.Error, i18n.screen_xref_warn_not_granted());
            } else {
                owningMOE.disable();
                crossReferenceName.enable();
                direction.enable();
                toDimension.disable();
                fromDimension.disable();
                defaultValue.enable();
                description.enable();
                gridValues.enable();
            }
        }
    }
    
    /**
     * Clear the form
     */
    protected void clearForm() {
        setCrossReference(null);
        fillForm();
    }
  
    /**
     * Save the form data
     */
    public void performSave() {
        if (form.validate()) {
            crossReference = getFromForm();
            xrefServiceAsync.save(crossReference, 
                    connectionController.getConnectionId(), 
                    new FormActionCallback(this,
                        i18n.screen_xref_info_saved(),
                        i18n.screen_xref_err_not_saved()
                    )
                );
            formStateChangeHandler.setUnchangedState();
        }
    }
    
    public void setCrossReference(CrossReference crossReference){
        this.gridValues.setCrossReference(crossReference);
        this.crossReference = crossReference;
    }
    
    public CrossReference getCrossReference() {
        return this.crossReference;
    }

    public RadioGroupItem getDirection() {
        return this.direction;
    }

    public ComboBoxItem getToDimension() {
        return this.toDimension;
    }

    public ComboBoxItem getFromDimension() {
        return this.fromDimension;
    }
    
    public FormStateChangeHandler getFormStateChangeHandler(){
        return this.formStateChangeHandler;
    }
}
