/*
 * RHQ Management Platform
 * Copyright (C) 2010 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.rhq.coregui.client.inventory.groups.detail.summary;

import java.util.Map;
import java.util.Set;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;

import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.criteria.DashboardCriteria;
import org.rhq.core.domain.dashboard.Dashboard;
import org.rhq.core.domain.dashboard.DashboardCategory;
import org.rhq.core.domain.dashboard.DashboardPortlet;
import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
import org.rhq.core.domain.util.PageList;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.InitializableView;
import org.rhq.coregui.client.PermissionsLoadedListener;
import org.rhq.coregui.client.PermissionsLoader;
import org.rhq.coregui.client.UserSessionManager;
import org.rhq.coregui.client.dashboard.DashboardContainer;
import org.rhq.coregui.client.dashboard.DashboardView;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupAlertsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupConfigurationUpdatesPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupEventsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupMetricsPortlet;
import org.rhq.coregui.client.dashboard.portlets.groups.GroupOperationsPortlet;
import org.rhq.coregui.client.gwt.DashboardGWTServiceAsync;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton;
import org.rhq.coregui.client.util.enhanced.EnhancedToolStrip;
import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;

/**
 * The content pane for the group Summary>Activity subtab.
 *
 * @author Simeon Pinder
 * @author Jay Shaughnessy
 */
public class ActivityView extends EnhancedVLayout implements DashboardContainer, InitializableView {

    private static final String DASHBOARD_NAME_PREFIX = "GroupDashboard_";

    private ResourceGroupComposite groupComposite;
    private boolean isAutoGroup;
    private boolean isAutoCluster;

    private DashboardGWTServiceAsync dashboardService = GWTServiceLookup.getDashboardService();

    private DashboardView dashboardView;

    private EnhancedToolStrip footer;
    private IButton editButton;
    private IButton resetButton;

    // Capture the user's global permissions for use by any dashboard or portlet that may need it for rendering.
    private Set<Permission> globalPermissions;

    private boolean editMode = false;
    private boolean isInitialized = false;
    //default portlet positioning parameters
    private int colLeft = 0;
    private int colRight = 1;
    private int rowLeft = 0;
    private int rowRight = 0;
    private boolean displayLeft = false;

    public ActivityView(ResourceGroupComposite groupComposite, boolean isAutoCluster, boolean isAutoGroup) {
        super();
        this.groupComposite = groupComposite;
        this.isAutoCluster = isAutoCluster;
        this.isAutoGroup = isAutoGroup;
    }

    @Override
    protected void onInit() {
        if (!isInitialized()) {
            super.onInit();

            // first async call to get global permissions
            new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() {

                public void onPermissionsLoaded(Set<Permission> permissions) {
                    globalPermissions = permissions;

                    // now make async call to look for customized dash for this user and entity
                    DashboardCriteria criteria = new DashboardCriteria();
                    criteria.addFilterCategory(DashboardCategory.GROUP);
                    criteria.addFilterGroupId(groupComposite.getResourceGroup().getId());
                    dashboardService.findDashboardsByCriteria(criteria, new AsyncCallback<PageList<Dashboard>>() {
                        public void onFailure(Throwable caught) {
                            CoreGUI.getErrorHandler().handleError(MSG.view_dashboardsManager_error1(), caught);
                        }

                        public void onSuccess(final PageList<Dashboard> result) {
                            Dashboard dashboard = result.isEmpty() ? getDefaultDashboard() : result.get(0);
                            setDashboard(dashboard);

                            isInitialized = true;

                            // draw() may be done since onInit finishes asynchronously, if so redraw
                            if (isDrawn()) {
                                markForRedraw();
                            }
                        }
                    });
                }
            });
        }
    }

    private void setDashboard(Dashboard dashboard) {
        Canvas[] members = getMembers();
        removeMembers(members);
        //pass in the group information
        EntityContext context = EntityContext.forGroup(groupComposite.getResourceGroup().getId(), isAutoCluster,
            isAutoGroup);
        dashboardView = new DashboardView(this, dashboard, context, groupComposite);
        addMember(dashboardView);

        footer = new EnhancedToolStrip();
        footer.setPadding(5);
        footer.setWidth100();
        footer.setMembersMargin(15);

        editButton = new EnhancedIButton(editMode ? MSG.common_title_view_mode() : MSG.common_title_edit_mode());
        editButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent clickEvent) {
                editMode = !editMode;
                editButton.setTitle(editMode ? MSG.common_title_view_mode() : MSG.common_title_edit_mode());
                dashboardView.setEditMode(editMode);
            }
        });

        resetButton = new EnhancedIButton(MSG.common_button_reset());
        resetButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent clickEvent) {
                String message = MSG.view_summaryDashboard_resetConfirm();

                SC.ask(message, new BooleanCallback() {
                    public void execute(Boolean confirmed) {
                        if (confirmed) {
                            dashboardView.delete();
                            setDashboard(getDefaultDashboard());
                            markForRedraw();
                        }
                    }
                });
            }
        });

        footer.addMember(editButton);
        footer.addMember(resetButton);

        addMember(footer);
    }

    protected Dashboard getDefaultDashboard() {
        Subject sessionSubject = UserSessionManager.getSessionSubject();
        final ResourceGroup group = groupComposite.getResourceGroup();

        final Dashboard dashboard = new Dashboard();

        dashboard.setName(DASHBOARD_NAME_PREFIX + sessionSubject.getId() + "_" + group.getId());
        dashboard.setCategory(DashboardCategory.GROUP);
        dashboard.setGroup(group);
        dashboard.setColumns(2);

        // set leftmost column and let the rest be equally divided
        dashboard.setColumnWidths("40%");
        dashboard.getConfiguration().put(new PropertySimple(Dashboard.CFG_BACKGROUND, "transparent"));

        //figure out which portlets to display and how
        Map<String, String> groupKeyNameMap = DashboardView.processPortletNameMapForGroup(groupComposite);

        //reset positioning parameters
        colLeft = 0;
        colRight = 1;
        rowLeft = 0;
        rowRight = 0;
        //Left Column
        if (groupKeyNameMap.containsKey(GroupMetricsPortlet.KEY)) {//measurments top left if available
            DashboardPortlet measurements = new DashboardPortlet(GroupMetricsPortlet.NAME, GroupMetricsPortlet.KEY, 220);
            dashboard.addPortlet(measurements, colLeft, rowLeft++);
            groupKeyNameMap.remove(GroupMetricsPortlet.KEY);
        }

        // right Column(approx 60%. As larger more room to display table and N rows.)
        if (groupKeyNameMap.containsKey(GroupAlertsPortlet.KEY)) {//alerts top right if available
            DashboardPortlet alerts = new DashboardPortlet(GroupAlertsPortlet.NAME, GroupAlertsPortlet.KEY, 210);
            dashboard.addPortlet(alerts, colRight, rowRight++);
            groupKeyNameMap.remove(GroupAlertsPortlet.KEY);
        }
        if (groupKeyNameMap.containsKey(GroupEventsPortlet.KEY)) {//events if available
            DashboardPortlet events = new DashboardPortlet(GroupEventsPortlet.NAME, GroupEventsPortlet.KEY, 210);
            dashboard.addPortlet(events, colRight, rowRight++);
            groupKeyNameMap.remove(GroupEventsPortlet.KEY);
        }
        if (groupKeyNameMap.containsKey(GroupOperationsPortlet.KEY)) {//operations if available
            DashboardPortlet ops = new DashboardPortlet(GroupOperationsPortlet.NAME, GroupOperationsPortlet.KEY, 210);
            dashboard.addPortlet(ops, colRight, rowRight++);
            groupKeyNameMap.remove(GroupOperationsPortlet.KEY);
        }
        if (groupKeyNameMap.containsKey(GroupConfigurationUpdatesPortlet.KEY)) {//operations if available
            DashboardPortlet ops = new DashboardPortlet(GroupConfigurationUpdatesPortlet.NAME,
                GroupConfigurationUpdatesPortlet.KEY, 210);
            dashboard.addPortlet(ops, colRight, rowRight++);
            groupKeyNameMap.remove(GroupConfigurationUpdatesPortlet.KEY);
        }

        //Fill out left column(typically smaller portlets) then alternate cols with remaining
        displayLeft = false;
        updateDashboardWithPortlets(groupKeyNameMap, dashboard, 105);
        return dashboard;
    }

    /**Iterates list of new portlets and updates the dashboard reference with these new portlets.
     * Attempts to fill the spaces around the remaining larger portlets if already installed, then alternates
     * adding to left and right columns. Assumes dashboard has only two columns.
     *
     * @param keyNameMap portlet key|name map
     * @param dashboard dasboard instance to update
     */
    private void updateDashboardWithPortlets(Map<String, String> keyNameMap, Dashboard dashboard, int initialHeight) {
        if ((keyNameMap != null) && (dashboard != null)) {
            for (String key : keyNameMap.keySet()) {
                //locate portlet and add to dashboard
                DashboardPortlet portlet = new DashboardPortlet(keyNameMap.get(key), key, initialHeight);
                if (rowLeft < 4) {
                    dashboard.addPortlet(portlet, colLeft, rowLeft++);
                } else {//alternate
                    if (!displayLeft) {
                        dashboard.addPortlet(portlet, colRight, rowRight++);
                    } else {
                        dashboard.addPortlet(portlet, colLeft, rowLeft++);
                    }
                    //toggle
                    displayLeft = !displayLeft;
                }
            }
        }
    }

    @Override
    public boolean isInitialized() {
        return isInitialized;
    }

    public Set<Permission> getGlobalPermissions() {
        return globalPermissions;
    }

    /**
     * name update not supported because the name is derived from the entity id.
     * @return
     */
    public boolean supportsDashboardNameEdit() {
        return false;
    }

    public void updateDashboardNames() {
        return;
    }

    @Override
    public boolean isValidDashboardName(String name) {
        return ((name != null) && (dashboardView != null) && name.equals(dashboardView.getDashboard().getName()));
    }

    @Override
    public void refresh() {
        if (isInitialized()) {
            dashboardView.rebuild();
        }
    }

}
