/*
 * AggregateConfigView.java
 * 
 * Copyright (c) 2003-2004 Digi International
 * This program and the information contained in it is confidential and
 * proprietary to Digi International and may not be used, copied, or re-
 * produced without the prior written permission of Digi International.
 * 
 */

package com.digi.config.ui;

import com.digi.config.core.*;
import com.digi.config.util.*;

import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.awt.*;



/** 
 * This view holds a collection of ConfigView's. It displays a tabbed notebook style control
 * in which each sub view is displayed on a notebook tab. The title of the subview's is 
 * displayed on the tab and when the tab is selected, the content of the subview will be 
 * displayed in the pane. The button panel of the subview will be displayed in the button 
 * panel area of the aggregate view panel. If the subview has no button panel, then the
 * aggregate view's button panel will be displayed by default. The default aggregate button
 * panel view includes Save & Cancel buttons for editable views and Refresh and Help buttons
 * for all views. 
 */
public abstract class AggregateConfigView extends ConfigViewImpl {

    JLabel viewTitle;
    JTabbedPane tabbedPane;
    private JPanel viewPanel;

    ArrayList viewList;
    ConfigView currentView;

    // default button panel actions
    ConfigAction saveKvpNodeAction;
    ConfigAction cancelKvpNodeAction;
    ConfigAction refreshAction;
    ConfigAction viewHelpAction;

    /**
     * Basic constructor of a readonly aggregate view.
     */
    public AggregateConfigView() throws Exception {
        super(false);
        viewList = new ArrayList();
        currentView = null;
    }

    /**
     * Constructor that specifies if this view allows editting of the kvpGroup. If it
     * does, then the view will show the Save & Cancel buttons in the button panel.
     */
    public AggregateConfigView(boolean editView) throws Exception {
        super(editView);
        viewList = new ArrayList();
        currentView = null;
    }

    /**
     * Adds a new sub view to this Aggregate View
     */
    public void addView(ConfigView view) {
        // View must be built before we can add to the tabbed pane
        getViewContent();
        // add the new view to the viewList
        viewList.add(view);
        showView(view);
    }

    /**
     * Shows a sub view from the Aggregate View
     */
    public void showView(ConfigView view) {
        // create a new tab for the view
        int index = viewList.indexOf(view);
        String title = ConfigResource.getUiRbString(view.getName()+"Title");
        Icon icon = null;
        String tip = null;
        tabbedPane.insertTab(title, icon, view.getViewContent(), tip, index);
    }

    /**
     * Shows all sub views from the Aggregate View
     */
    public void showAllViews() {
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            showView(view);
        }
    }

    /**
     * Hides a sub view from the Aggregate View
     */
    public void hideView(ConfigView view) {
        // create a new tab for the view
        int index = viewList.indexOf(view);
        tabbedPane.remove(index);
    }

    /**
     * Hides all sub views from the Aggregate View
     */
    public void hideAllViews() {
        tabbedPane.removeAll();
    }

    /**
     * Return a one word name identifying this view. 
     */
    public String getName() {
        return "AggregateConfigView";
    }

    /** 
     * Return the Component that displays the primary content for this view
     */
    public Component getViewContent() {
        if (viewPanel==null) {
            //viewPanel = new JPanel();
            viewPanel = new CustomPanel();
            viewPanel.setLayout(new BorderLayout());
            tabbedPane = new JTabbedPane();
            tabbedPane.setBackground(new Color(0,0,0,0));

            viewPanel.add(tabbedPane, BorderLayout.CENTER);
            ChangeListener tabListener = new ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                    // Are we being notified prematurely?
                    if (device == null) {
                        return;
                    }

                    ConfigView newView = null;
                    int index = tabbedPane.getSelectedIndex();
                    if (index>=0) {
                        newView = (ConfigView)viewList.get(index);
                    }
                    if (newView!=currentView) {
                        if (currentView!=null) {
                            currentView.deactivate();
                        }
                        if (newView!=null) {
                            ((ConfigView)newView).activate();
                        }
                        currentView = (ConfigView)newView;
                    }
                }
            };
            tabbedPane.addChangeListener(tabListener);
        }
        return viewPanel;
    }


    /**
     * Returns a resource key to the help information for this view. The actual
     * URL will be looked up in the Help Resource bundle.
     */
    public String getHelpResource() {
        String key = null;
        if (currentView!=null) {
            key = currentView.getHelpResource();
        }
        return key;
    }

    /**
     * Informs view what device to work with. View should flush any
     * cached device data and mark current view content as invalid
     * so that it is refreshed appropriatly.
     */
    public void setDevice(Device device) {
        super.setDevice(device);
        // iterate through views in viewList and have each of them update their kvpGroup
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            view.setDevice(device);
        }
    }

    /**
     * Informs view to use the specified primary index in selecting the
     * data to display in the view. Not all views will support indexed
     * viewing and it is up to each view to define what the index is based 
     * upon. 
     * <p>
     * An example of an indexed view would be the SerialBasicView. This view
     * is indexed off the port # whose data is to be displayed in the view. An
     * external control in the SerialView lets the user select the port to view
     * and then that view instructs the SerialBasicView to use the selected 
     * port number as it's ViewIndex. Other views could use the index to base
     * their view off other integer keys such as Alarm#, Destination#,etc...
     * <p>
     * Views that do not support indexing can simply ignore this call.
     */
    public void setViewIndex(int primaryIndex) {
        super.setViewIndex(primaryIndex);
        // iterate through views in viewList and have each of them update their index
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            view.setViewIndex(primaryIndex);
        }
    }


    /**
     * This method is called to instruct the view that it is about to be made
     * active. When a view is active it needs to make sure its content is correct.
     * An example of why a panel may be inactive is if it were on a tabbed pane 
     * and was not currently visible or if the user selected some other view.
     * 
     * Views can use this method to create their content on first touch or to refresh their
     * content when the device kvpGroup have been reset.
     */
    public void activate() {
        if (viewList.size()>0) {
            // Deactivate the selected view
            if (currentView==null) {
                // If not view is already selected, choose the first view
                currentView = (ConfigView)viewList.get(0);
            }
            currentView.activate();
        }
        super.activate();
    }

    /**
     * This method is called to instruct the view that it is about to be made
     * inactive. When a view is inactive, it does not need to worry
     * about maintaining its content in a correct state. An example of why a panel
     * may be inactive is if it were on a tabbed pane and was not currently visible
     * or if the user selected some other view.
     */
    public void deactivate() {
        if (viewList.size()>0) {
            // Deactivate the selected view
            if (currentView==null) {
                // If not view is already selected, choose the first view
                currentView = (ConfigView)viewList.get(0);
            }
            currentView.deactivate();
        }
        super.deactivate();
    }

    /**
     * Indicates if any changes have been made by the user that have not yet been
     * saved back into the kvpCluster.
     */
    public boolean isChanged() {
        // iterate through views in viewList and query to see if they have unsaved changes
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            if (view.isChanged()) {
                return true;
            }
        }
        return false;
    }

    /**
     * This method instructs the view to validate any of the changes the user has made
     * within the view. Any errors are to be added to the provided errorList.
     * 
     * @param errorList is a collection of ViewValidationError objects
     */
    public void validateChanges(Collection errorList) {
        // iterate through views in viewList and have each of them get their Field changes
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            view.validateChanges(errorList);
        }
    }


    /**
     * This method instructs the view to place any changes the user has made within 
     * the view into the provided clusters. Once the changes have been saved to
     * to the device, a subsequent call to commitChanges() will be made.
     */
    public void getChanges(KvpNode settingCluster, KvpNode stateCluster) {
        // iterate through views in viewList and have each of them get their Field changes
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            view.getChanges(settingCluster, stateCluster);
        }
    }

    /**
     * Instructs the view to consider any user changes within the view as 
     * saved to the device (ie committed).
     */
    public void commitChanges() {
        // iterate through views in viewList and have each of them save their Field changes
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            view.commitChanges();
        }
    }

    /** 
     * Instructs the view to discard any changes the user has made within the
     * view and revert those fields to the original state. The view is also 
     * free to refresh all its fields to the present cached state of the device at 
     * this time.
     */
    public void cancelChanges() {
        // iterate through views in viewList and have each of them cancel their Field changes
        for (Iterator i=viewList.iterator(); i.hasNext();) {
            ConfigView view = (ConfigView)i.next();
            view.cancelChanges();
        }
    }







}

