/*
 * GeneralInfoView.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 javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.net.*;




/** 
 * This class is a view panel that shows general information about the device.
 * 
 * This view can be embedded in other panels as desired.
 */


public class GeneralInfoView extends ConfigViewImpl {
    /** A KvpNode that holds just the state fields used in this view */
    KvpNode viewStateTree;
    /** listens to the device for changes to state fields */
    DeviceChangeListener stateChangeListener;
    
    GridContentPanel content;

    // UI Controls
    JLabel productName_UIC;
    JLabel macAddr_UIC;
    JLabel firmwareVersion_UIC;
    JLabel bootVersion_UIC;
    JLabel postVersion_UIC;

    JLabel cpuUtil_UIC;
    JLabel upTime_UIC;
    JLabel totalMem_UIC;
    JLabel usedMem_UIC;
    JLabel freeMem_UIC;

    private static final int MINUTES_PER_HOUR = 60;
    private static final int SECONDS_PER_MINUTE = 60;
    private static final int HOURS_PER_DAY = 24;

    /**
     * Basic constructor. Sets up the tree view and the edit panel.
     */
    public GeneralInfoView() throws Exception {
        super(false);
        setIncludeStateFields(true);
        setIncludeSettingsFields(false);

        // create the KvpNode and the change listener
        viewStateTree = new KvpNode();
        stateChangeListener = new DeviceChangeListener() {
            public void deviceChanged(DeviceChangeEvent e) {
                refreshViewControls();
            }
        };
        
        // Create the panel that will hold the view controls
        content = new GridContentPanel(this.getName(),1);

        //
        // Create the fields and put them on the view
        //
        // NOTE: product name is currently static and is pulled from the resource file.
        productName_UIC = content.addJLabel("ProductNameLbl", null);
//        productName_UIC.setText(ConfigResource.getUiRbString("ProductName"));
        macAddr_UIC = content.addJLabel("MacAddressLbl", null);
        firmwareVersion_UIC = content.addJLabel("FirmwareVersionLbl", null);
        bootVersion_UIC = content.addJLabel("BootVersionLbl", null);
        postVersion_UIC = content.addJLabel("PostVersionLbl", null);
        content.addBlankLine();                           
        cpuUtil_UIC = content.addJLabel("CpuUtilLbl", null);
        upTime_UIC = content.addJLabel("UpTimeLbl", null);
        totalMem_UIC = content.addJLabel("TotalMemoryLbl", null);
        usedMem_UIC = content.addJLabel("UsedMemoryLbl", null);
        freeMem_UIC = content.addJLabel("FreeMemoryLbl", null);
        
        content.addVGlue();
    }

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

    /** 
     * Return the Component that displays the primary content for this view
     */
    public Component getViewContent() {
        return content;
    }


    /**
     * 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);
        refreshViewControls();
    }


    /** 
     * Refreshes the state of the controls in the view to match the data in the views kvpGroup.
     */
    private void refreshViewControls() {
        viewStateTree.clear();

        KvpField field;

        productName_UIC.setText(device.getProductName());
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_info", "mac");
        refreshUIFromField(macAddr_UIC, field, false);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_info", "firmware");
        refreshUIFromField(firmwareVersion_UIC, field, false);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_info", "boot");
        refreshUIFromField(bootVersion_UIC, field, false);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_info", "post");
        refreshUIFromField(postVersion_UIC, field, false);

        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_stats", "cpu");
        refreshUIFromField(cpuUtil_UIC, field, true);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_stats", "uptime");
        refreshUIFromField(upTime_UIC, field, true);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_stats", "totalmem");
        refreshUIFromField(totalMem_UIC, field, true);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_stats", "usedmem");
        refreshUIFromField(usedMem_UIC, field, true);
        field = viewStateTree.mergeFrom(device.getInternalStateTree(), "device_stats", "freemem");
        refreshUIFromField(freeMem_UIC, field, true);
    }

    // Helper to set field values and state
    private void refreshUIFromField(JLabel jLabel, KvpField kvpField, boolean format) {
        jLabel.setEnabled(kvpField!=null);
        if (kvpField!=null) {
            String text;
            if (format) {
                text = formatField(kvpField);
            } else {
                text = kvpField.getStringValue();
            }

            jLabel.setText(text);
        }
    }

    /**
     * Helper to format field values
     */
    String formatField(KvpField kvpField) {
        String strValue = kvpField.getStringValue();
        if (kvpField.getName().equals("cpu")) {
            return formatCpuUtil(kvpField.getStringValue());
        } else if (kvpField.getName().equals("uptime")) {
            return formatUpTime(kvpField.getStringValue());
        } else if (kvpField.getName().equals("totalmem") ||
                   kvpField.getName().equals("usedmem") ||
                   kvpField.getName().equals("freemem")) {
            return formatByteSize(kvpField.getStringValue());
        }

        return strValue;
    }

    String formatCpuUtil(String value) {
        if (value.length() == 0) {
            value = "0";
        }

        return ConfigResource.getUiRbString("CpuUtilFormat", new Object[] {value});
    }

    String formatUpTime(String value) {
        int seconds = 0;
        int minutes = 0;
        int hours = 0;
        int days = 0;

        try {
            seconds = Integer.parseInt(value);
        } catch (NumberFormatException nfe) {}


        if((minutes = (seconds / SECONDS_PER_MINUTE)) != 0){
            seconds = (seconds % SECONDS_PER_MINUTE);
            if((hours = (minutes / MINUTES_PER_HOUR)) != 0){
                minutes = (minutes % MINUTES_PER_HOUR);
                if((days = (hours / HOURS_PER_DAY)) != 0){
                    hours = (hours % HOURS_PER_DAY);
                }
            }
        }

        Object parms[];
        if (days > 0) {
            parms = new Object[] {new Integer(days), new Integer(hours), new Integer(minutes), new Integer(seconds)};
            return ConfigResource.getUiRbString("UpTimeFormatDays", parms);
        } else if (hours > 0) {
            parms = new Object[] {new Integer(hours), new Integer(minutes), new Integer(seconds)};
            return ConfigResource.getUiRbString("UpTimeFormatHours", parms);
        } else if (minutes > 0) {
            parms = new Object[] {new Integer(minutes), new Integer(seconds)};
            return ConfigResource.getUiRbString("UpTimeFormatMinutes", parms);
        } else {
            parms = new Object[] {new Integer(seconds)};
            return ConfigResource.getUiRbString("UpTimeFormatSeconds", parms);
        }
    }

    String formatByteSize(String value) {
        int size = 0;
        try {
            size = Integer.parseInt(value);
        } catch (NumberFormatException nfe) {}

        int kbSize = size / 1024;
        if (kbSize > 0) {
            return ConfigResource.getUiRbString("MemorySizeFormatKB",
                                                new Object[] {new Integer(kbSize)});
        } else {
            return ConfigResource.getUiRbString("MemorySizeFormatBytes",
                                                new Object[] {new Integer(size)});
        }
    }


    /**
     * 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.
     */
    public void activate() {
        SystemLog.debug("Activating "+getName());
        device.addStateChangeListener(stateChangeListener);
        doRefreshAction();
    }

    /**
     * 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() {
        device.removeStateChangeListener(stateChangeListener);
    }

    /**
     * Indicates if any changes have been made by the user that have not yet been
     * saved to the device(ie committed).
     */
    public boolean isChanged() {
        // All fields are readonly
        return false;
    }

    /**
     * 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) {
        // All fields are readonly
    }

    /**
     * Instructs the view to consider any user changes within the view as 
     * saved to the device (ie committed).
     */
    public void commitChanges() {
        // All fields are readonly
    }

    /** 
     * 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() {
        // All fields are readonly
    }
}

