package oracle.fodemo.storefront.orders.view.managed;

import java.util.HashSet;

import javax.faces.event.ActionEvent;

import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.adf.view.rich.component.rich.RichDialog;
import oracle.adf.view.rich.component.rich.data.RichTable;
import oracle.adf.view.rich.component.rich.nav.RichCommandLink;

import oracle.adf.view.rich.event.DialogEvent;

import oracle.adfinternal.view.faces.model.binding.FacesCtrlHierNodeBinding;

import oracle.binding.OperationBinding;

import oracle.fodemo.storefront.adf.util.ADFUtils;
import oracle.fodemo.storefront.jsf.util.JSFUtils;

import oracle.jbo.Key;
import oracle.jbo.Row;


public class MyOrdersBean {

    private boolean editGiftMessage;

    public MyOrdersBean() {
        editGiftMessage = false;
    }

    public void cancelOrderActionListener(ActionEvent evt){
        OperationBinding opBinding = ADFUtils.findOperation("cancelOrder");
        opBinding.execute();
    }
    

    public void commitDialogListener(DialogEvent evt){       
        commit();
    }
    
    public void toggleEditGiftMessageActionListener(ActionEvent evt){
        editGiftMessage = !editGiftMessage;
    }

    public void removeItemActionListener(ActionEvent evt){
        OperationBinding opBinding = ADFUtils.findOperation("deleteCurrentMyOrderItem");
        opBinding.execute();
    }

    public void commitActionListener(ActionEvent evt){
        commit();   
    }

    private void commit(){
        OperationBinding opBinding = ADFUtils.findOperation("Commit");
        opBinding.execute();       
    }

    public String cancelButtonAction() {
        // the use cancelled the edit on the order. With the cancelling the operation, there
        // are 3 possible states
        // i)   The user didn't change a value
        // ii)  The user changed a value but this hasn't been submitted to the model
        // iii) The user has changed a value and the change has been submitted to the 
        //      model but hasn't been committed yet. 
        // we don't need to do anything special for i) and ii) but need to handle iii), 
        // which we can do by checking #{bindings.Commit.enabled} on a "Commit" binding 
        // in the pageDef file. If there has been an update to the model then the commit
        // binding shows enabled to persist the change. This information is what we will
        // look at to determine if there is a need to do anything
        
        Boolean commitState = (Boolean) JSFUtils.resolveExpression("#{bindings.Commit.enabled}");
        // if the expression cannot be resolved then assume that no clean up is required. The expression
        // cannot be resolved if the commit binding is missing, which might be the case if this code
        // line is used in a custom application
        boolean commitEnabled = commitState!= null?commitState.booleanValue():false;
        
        // A Rollback operation is defined in the pageDef file and is used to undo the changes. Note that 
        // this rollback does undo all changes that haven't been persisted so far
        
        if (commitEnabled){
            DCBindingContainer dcbindings = (DCBindingContainer) JSFUtils.resolveExpression("#{bindings}");
            DCIteratorBinding dciter = (DCIteratorBinding) dcbindings.get("OrdersIterator");
            dciter.getCurrentRow().refresh(Row.REFRESH_UNDO_CHANGES);
        }
        return null;
    }

    public void onEditOrders(ActionEvent actionEvent) {
        synchronizeViewAndBinding(actionEvent);
    }

    public void onCancelOrders(ActionEvent actionEvent) {
        synchronizeViewAndBinding(actionEvent);
    }

    /**
     * deletes all orders and order items
     * @param actionEvent
     */
    public void onConfirmCancelOrders(ActionEvent actionEvent) {    
        DCBindingContainer dcbindings = (DCBindingContainer) JSFUtils.resolveExpression("#{bindings}");
        DCIteratorBinding dciter = (DCIteratorBinding) dcbindings.get("OrdersIterator");
        HashSet<Key> keySet = new HashSet<Key>();
        keySet.add(dciter.getCurrentRow().getKey());
        
        //call externalized method on the AM
        OperationBinding deleteOrdersOperationBinding = dcbindings.getOperationBinding("cancelOrders");
        deleteOrdersOperationBinding.getParamsMap().put("keySet",keySet);
        // delete orders and order items
        deleteOrdersOperationBinding.execute();                    
    }
    
    /**
     * method ensures that the current displayed table record is synchronized with 
     * the OrdersIterator current row
     * @param actionEvent
     */
    private void synchronizeViewAndBinding(ActionEvent actionEvent){
        RichCommandLink link = (RichCommandLink) actionEvent.getSource();
        RichTable table = (RichTable) link.getParent().getParent();
        // The table current row data is of type FacesCtrHierNodeBinding, which
        // contains the current row
        Row rw = ((FacesCtrlHierNodeBinding) table.getRowData()).getRow();
        //synchornize the binding with the table. This seems to be required because clicking
        //onto the command link that launches the edit dialog doesn't set the current row in time
        DCBindingContainer dcbindings = (DCBindingContainer) JSFUtils.resolveExpression("#{bindings}");
        DCIteratorBinding dciter = (DCIteratorBinding) dcbindings.get("OrdersIterator");
        dciter.setCurrentRowWithKey(rw.getKey().toStringFormat(true));
        dciter.refreshIfNeeded();
        return;
    }

    public void setEditGiftMessage(boolean newshippingAddressEditable) {
        this.editGiftMessage = newshippingAddressEditable;
    }

    public boolean isEditGiftMessage() {
        return editGiftMessage;
    }
}
