package org.ovirt.engine.ui.webadmin.uicommon.model;

import java.util.ArrayList;
import java.util.List;

import org.ovirt.engine.core.compat.Event;
import org.ovirt.engine.core.compat.EventArgs;
import org.ovirt.engine.core.compat.IEventListener;
import org.ovirt.engine.core.compat.PropertyChangedEventArgs;
import org.ovirt.engine.ui.common.uicommon.model.TreeNodeModel;
import org.ovirt.engine.ui.uicommonweb.models.common.SelectionTreeNodeModel;
import org.ovirt.engine.ui.webadmin.gin.ClientGinjectorProvider;

import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;

/**
 * A {@link TreeNodeModel} for {@link SelectionTreeNodeModel} instances
 */
public class SimpleSelectionTreeNodeModel implements TreeNodeModel<SelectionTreeNodeModel, SimpleSelectionTreeNodeModel> {

    /**
     * Build from a list of {@link SelectionTreeNodeModel} instances
     */
    public static List<SimpleSelectionTreeNodeModel> fromList(List<SelectionTreeNodeModel> list) {
        List<SimpleSelectionTreeNodeModel> result = new ArrayList<SimpleSelectionTreeNodeModel>();
        for (SelectionTreeNodeModel selectionTreeNodeModel : list) {
            result.add(new SimpleSelectionTreeNodeModel(selectionTreeNodeModel));
        }
        return result;
    }

    /**
     * Build from a single {@link SelectionTreeNodeModel} instance
     */
    public static SimpleSelectionTreeNodeModel fromModel(SelectionTreeNodeModel model) {
        return new SimpleSelectionTreeNodeModel(model);
    }

    private final ArrayList<SimpleSelectionTreeNodeModel> children;
    private SimpleSelectionTreeNodeModel parent;

    private final EventBus eventBus;
    private final SelectionTreeNodeModel model;

    protected SimpleSelectionTreeNodeModel(SelectionTreeNodeModel model) {
        this.eventBus = ClientGinjectorProvider.instance().getEventBus();
        this.model = model;

        // Build children list using depth-first recursion
        this.children = new ArrayList<SimpleSelectionTreeNodeModel>();
        for (SelectionTreeNodeModel childModel : model.getChildren()) {
            SimpleSelectionTreeNodeModel child = new SimpleSelectionTreeNodeModel(childModel);
            child.parent = this;
            children.add(child);
        }

        // Add selection listener
        model.getPropertyChangedEvent().addListener(new IEventListener() {
            @Override
            public void eventRaised(Event ev, Object sender, EventArgs args) {
                if ("IsSelectedNullable".equals(((PropertyChangedEventArgs) args).PropertyName)) { //$NON-NLS-1$
                    SelectionEvent.fire(SimpleSelectionTreeNodeModel.this, SimpleSelectionTreeNodeModel.this);
                }
            }
        });
    }

    @Override
    public HandlerRegistration addSelectionHandler(SelectionHandler<SimpleSelectionTreeNodeModel> handler) {
        return eventBus.addHandler(SelectionEvent.getType(), handler);
    }

    @Override
    public void fireEvent(GwtEvent<?> event) {
        eventBus.fireEvent(event);
    }

    @Override
    public ArrayList<SimpleSelectionTreeNodeModel> getChildren() {
        return children;
    }

    @Override
    public SimpleSelectionTreeNodeModel getParent() {
        return parent;
    }

    @Override
    public int getIndex() {
        if (parent == null) {
            return 0;
        }

        ArrayList<SimpleSelectionTreeNodeModel> siblings = parent.getChildren();
        for (int i = 0; i < siblings.size(); i++) {
            if (model == siblings.get(i).model) {
                return i;
            }
        }

        return -1;
    }

    @Override
    public String getName() {
        return model.getDescription();
    }

    @Override
    public boolean getSelected() {
        return model.getIsSelectedNullable() == null ? false : model.getIsSelectedNullable();
    }

    public Boolean getIsSelectedNullable() {
        return model.getIsSelectedNullable();
    }

    @Override
    public boolean isEditable() {
        return model.getIsChangable();
    }

    @Override
    public void setSelected(boolean value) {
        model.setIsSelectedNullable(value);
    }

}
