/*
 * BackupView.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.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;




/** 
 * This class is a view panel that allow users to backup and restore
 * device settings for the ConnectMe device
 * 
 * This view can be embedded in other panels as desired.
 */


public class BackupView extends ConfigViewImpl {
    /** A KvpNode that holds just the settings used in this view */
    KvpNode viewSettingTree;
    /** listens to the device for changes to settings */
    DeviceChangeListener settingChangeListener;
    /** Panel that holds the view content */
    GridContentPanel content;
    GridContentPanel backupContent;
    GridContentPanel restoreContent;

    // Data Fields currently used in this view

    // UI Controls for each field
    JTextField restoreFileName_UIC;
    JButton backup_UIC;
    JButton browse_UIC;
    JButton restore_UIC;

    /**
     * Basic constructor. Sets up the tree view and the edit panel.
     */
    public BackupView() throws Exception {
        // create the KvpNode and the kvpGroup change listener
        viewSettingTree = new KvpNode();
        settingChangeListener = new DeviceChangeListener() {
            public void deviceChanged(DeviceChangeEvent e) {
                //SystemLog.debug("SerialBasicView was notified that device kvpGroup changed");
                refreshViewData();
                refreshViewControls();
            }
        };
        // Create the panel that will hold the view controls
        content = new GridContentPanel(this.getName(),2);

        //
        // Create the fields and put them on the view
        //

//        content.addHeadingBar("BackupRestoreHeading");
        content.addBlankLine();
        content.addTextLine("BackupRestoreDesc");
        content.addBlankLine();
        content.addTextLine("BackupDesc");
        backupContent = new GridContentPanel(2);
        backup_UIC = backupContent.addAction(null, new ConfigAction("Backup1", this, "doBackupAction"), "Backup1Desc");
        content.addSubPanel(backupContent);
        content.addBlankLine();
        content.addTextLine("RestoreDesc");
        restoreContent = new GridContentPanel(2);
        restoreFileName_UIC = restoreContent.addJTextField("RestoreLabel",null,300,null,0,false);
        browse_UIC = restoreContent.addAction(null, new ConfigAction("Browse", this, "doBrowseAction"), null,1,true);
        restore_UIC = restoreContent.addAction(null, new ConfigAction("Restore", this, "doRestoreAction"), null);
        content.addSubPanel(restoreContent);

        content.addVGlue();
    }


    /**
     * Backup data to a device configuration data file
     */
    public void doBackupAction() {
        SystemLog.debug("Backup!");
        // prompt a file save dialog to get the name of the file to save device settings to
        JFileChooser chooser = new JFileChooser();
        ExampleFileFilter filter = new ExampleFileFilter();
        filter.addExtension("dcd");
        filter.setDescription(ConfigResource.getUiRbString("BackupDlg.Description"));
        chooser.setFileFilter(filter);
        chooser.setDialogTitle(ConfigResource.getUiRbString("BackupDlg.Title"));
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setApproveButtonText(ConfigResource.getUiRbString("BackupDlg.Button"));
        chooser.setDialogType(JFileChooser.SAVE_DIALOG);
        int returnVal = chooser.showDialog(content, ConfigResource.getUiRbString("BackupDlg.Button"));
        if(returnVal == JFileChooser.APPROVE_OPTION) {
            try {
                String backupFileName = chooser.getSelectedFile().getCanonicalPath();
                if (!backupFileName.endsWith(".dcd")) {
                    backupFileName += ".dcd";
                }
                // refresh to get latest device settings?????
                // open save file and stream settings into it
                File backupFile = new File(backupFileName);
                if (backupFile.exists()) {
                    int reply = JOptionPane.showConfirmDialog(content,new JLabel("File '"+backupFileName+"' already exists. Are you sure you want to overwrite it?"),"Confirm overwrite", JOptionPane.YES_NO_OPTION);
                    if (reply==JOptionPane.NO_OPTION) {
                        SystemLog.log("Op1Cancelled", new Serializable[] {"Backup"});
                        return;
                    }
                }
                backupFile.createNewFile();
                FileOutputStream os = new FileOutputStream(backupFile);
                DataOutputStream dos = new DataOutputStream(os);
                StringBuffer outputBuffer = new StringBuffer();
                outputBuffer.append("<"+RciProtocol.BACKUP_TAG+" version=\""+RciProtocol.PROTOCOL_VERSION_TAG+"\">\n");
                // Grab a copy of the current device settings & remove the security information
                KvpNode backupSettings = device.getSettingTree();
                KvpNode securitySettings = backupSettings.getChild("simple_password");
                if (securitySettings!=null) {
                    securitySettings.removeChild("password");
                    securitySettings.removeChild("public_comm");
                    securitySettings.removeChild("private_comm");
                }
                backupSettings.toXml(outputBuffer,"",false);
                outputBuffer.append("</"+RciProtocol.BACKUP_TAG+">\n");
                dos.writeBytes(outputBuffer.toString());
                // close file
                dos.close();
                os.close();
                SystemLog.log("Op1Succ", new Serializable[] {"Backup"});
            } catch (Exception e) {
                SystemLog.log("Op1Fail", new Serializable[] {"Backup"}, e);
            }
        }
    }                   

    /**
     * Locate a device configuration data file
     */
    public void doBrowseAction() {
        SystemLog.debug("Browse!");
        JFileChooser chooser = new JFileChooser();
        ExampleFileFilter filter = new ExampleFileFilter();
        filter.addExtension("dcd");
        filter.setDescription(ConfigResource.getUiRbString("RestoreDlg.Description"));
        chooser.setFileFilter(filter);
        chooser.setDialogTitle(ConfigResource.getUiRbString("RestoreDlg.Description"));
        chooser.setDialogType(JFileChooser.OPEN_DIALOG);
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int returnVal = chooser.showOpenDialog(content);
        if(returnVal == JFileChooser.APPROVE_OPTION) {
            try {
                restoreFileName_UIC.setText(chooser.getSelectedFile().getCanonicalPath());
            } catch (Exception e) {
                SystemLog.log("Op1Fail", new Serializable[] {"Browse"}, e);
            }
        }
    }

    /**
     * Restore a device configuration data file
     */
    public void doRestoreAction() {
        SystemLog.debug("Restore!");
        String fileName = restoreFileName_UIC.getText();
        File restoreFile = new File(fileName);

        // if the file is not found and the dcd extension was not provided then try adding it
        if (!restoreFile.exists() && !fileName.endsWith(".dcd")) {  
            fileName += ".dcd";
            restoreFile = new File(fileName);
        }

        Busy.begin(ConfigResource.getUiRbString("SaveChangesStatus"));

        // Restore the file if it exists
        if (restoreFile.exists()) {
            try {
                // open the restore file and parse contents
                FileInputStream is = new FileInputStream(restoreFile);
                DataInputStream dis = new DataInputStream(is);
                DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
                // use DOM parser to read the file
                Document resultDocument = domBuilder.parse(dis);
                Node commandNode = resultDocument.getFirstChild();
                String command = commandNode.getNodeName();
                if (!command.equals(RciProtocol.BACKUP_TAG)) {
                    SystemLog.log("RestoreFileInvalidError", new Serializable[] {fileName});
                    return;
                }
                SystemLog.debug("Parsed rci_backup file. Extracting Settings");
                // construct the cluster from the COM tree
                KvpNode restoreCluster = new KvpNode(commandNode);

                // Determine what level of RCI this backup file was create with
                String version = restoreCluster.getAttribute("version");
                if (version==null) {
                    version = "1.0";
                }
                // Perform the restore - device handles processing old versions of backup data & refresh cached settings
                device.restoreBackupSettingTree(restoreCluster, version); 
                SystemLog.log("Op1Succ",new Serializable[]{ConfigResource.getUiRbString("RestoreMenu")});
            } catch (DeviceCommandException dce) {
                SystemLog.log("Op1Fail",new Serializable[]{ConfigResource.getUiRbString("RestoreMenu")},dce);
            } catch (DeviceValidationException dse) {
                // Find out what device fields are invalid
                SystemLog.debug("Invalid fields detected while saving to device", dse);
                KvpNode errorCluster = dse.getCluster();
                Collection errors = errorCluster.getErrors();
                StringBuffer msgBuff = new StringBuffer();
                for (Iterator i=errors.iterator(); i.hasNext();) {
                    RciCommandError error = (RciCommandError)i.next();
                    msgBuff.append(error.toString()+"\n");
                }
                // popup a dialog showing the errors 
                StringBuffer popupMsg = new StringBuffer();
                popupMsg.append(ConfigResource.getUiRbString("ValidationErrorDesc")+"\n");
                popupMsg.append(msgBuff);
                JOptionPane.showMessageDialog(this.content,
                                              popupMsg.toString(),
                                              ConfigResource.getUiRbString("ValidationErrorTitle"),
                                              JOptionPane.ERROR_MESSAGE);
                // Also add a log entry
                SystemLog.log("ValidationError", new Serializable[] {msgBuff.toString()});
            } catch (Exception e) {
                SystemLog.log("Op1Fail",new Serializable[]{ConfigResource.getUiRbString("RestoreMenu")},e);
            }
        } else {
            SystemLog.log("RestoreFileInvalidError", new Serializable[] {fileName});
        }
        Busy.end();
    }






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

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

    /** 
     * Returns the Component that displays the buttons below the view.
     * If this view has no buttons to display this method returns null.
     */
     public Component getViewButtons() {
         // We don't want buttons on this view so just return null
         return null;
     }


    /**
     * 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);
        refreshViewData();
        refreshViewControls();
        device.addSettingChangeListener(settingChangeListener);
    }

    /** 
     * Refreshes the local copy of the kvpGroup displayed in the view. The updated kvpGroup come
     * from those currently cached in the Device
     */
    private void refreshViewData() {
        viewSettingTree.clear();
    }

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




    /**
     * 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 BackupView");
    }

    /**
     * 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() {
        SystemLog.debug("Deactivating BackupView");
    }

    /**
     * Indicates if any changes have been made by the user that have not yet been
     * saved to the device(ie committed).
     */
    public boolean isChanged() {
        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) {
    }

    /**
     * Instructs the view to consider any user changes within the view as 
     * saved to the device (ie committed).
     */
    public void 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() {
    }


}

