/*=========================================================================

Program:   Orbit Visualization Tool
Source:    $Source: /stor/devel/ovt2g/ovt/util/Settings.java,v $
Date:      $Date: 2001/04/13 18:55:11 $
Version:   $Revision: 1.10 $


Copyright (c) 2000 OVT Team (Kristof Stasiewicz, Mykola Khotyaintsev,
Yuri Khotyaintsev)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification is permitted provided that the following conditions are met:

 * No part of the software can be included in any commercial package without
written consent from the OVT team.

 * Redistributions of the source or binary code must retain the above
copyright notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT OR
INDIRECT DAMAGES  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE.

OVT Team (http://ovt.irfu.se)   K. Stasiewicz, M. Khotyaintsev, Y.
Khotyaintsev

=========================================================================*/

/*
 * Settings.java
 *
 * Created on November 17, 2000, 11:35 AM
 */

package ovt.util;

import ovt.*;
import ovt.beans.*;
import ovt.object.*;
import ovt.interfaces.*;
import ovt.datatype.*;
import ovt.gui.*;
import ovt.mag.*;
import ovt.util.*;
import ovt.event.*;

import java.beans.*;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;

import javax.swing.*;
import java.lang.*;

import javax.xml.parsers.*;  
import org.xml.sax.*;  
import com.sun.xml.tree.*;

import org.w3c.dom.*;



/**
 *
 * @author  ko
 * @version 
 */
public class Settings {

    public static final String OBJECT = "OBJECT";
    public static final String NAME = "name";
    private static final int DEBUG = 6;
    
    /** Creates new Settings */
    public Settings() {
    }

private static XmlDocument buildDom (OVTObject obj) throws ParserConfigurationException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        XmlDocument document = (XmlDocument)builder.newDocument();  // Create from whole cloth

        Element root = (Element)getNode(OBJECT, obj, document, true); 
        document.appendChild (root);
        return document;
}
    
private static Node getNode( OVTObject obj, Document document, boolean recursive) {
    return getNode(OBJECT, obj, document, recursive);
}
private static Node getNode(String nodeName, Object obj, Document document, boolean recursive) {
    Log.log("object='"+nodeName+"'", DEBUG);
        //String objName = Utils.repaceSpaces(obj.getName());
    Element root = (Element) document.createElement(Utils.replaceSpaces(nodeName));
        
    if (obj instanceof OVTObject) root.setAttribute(NAME, ((OVTObject)obj).getName());
        
        // set attributes
    if (obj instanceof DescriptorsSource ) {
        Descriptors desc = ((DescriptorsSource)obj).getDescriptors();
        if (desc != null) {
            Enumeration e = desc.elements();
            BasicPropertyDescriptor pd;
            String value;
            while (e.hasMoreElements()) {
                pd = (BasicPropertyDescriptor)e.nextElement();
                
                if (pd.isDerived()) continue; // skip derived properties
                
                try {
                    Log.log(pd.getName() + "=" + pd.getPropertyEditor().getAsText() + "', ", DEBUG);
                    value = Utils.replaceSpaces(pd.getPropertyEditor().getAsText());
                    if (value != null) root.setAttribute(pd.getName(), value);
                } catch (NullPointerException e2) { 
                    //Log.err("Property descriptor '"+ pd.getName() +"' has no editor", 0);
                    //System.out.println("---------------------SUXX!!!00000000000--------------------"+e2); 
                }
            }
        }
    }
        
    if (obj instanceof BeansSource) {
            BeansCollection beans = ((BeansSource)obj).getBeanDesriptors();
            if (beans != null) {
                Enumeration e = beans.elements();
                    while (e.hasMoreElements()) {
                        BasicBeanDescriptor bd = (BasicBeanDescriptor)e.nextElement();
                        try {
                            root.appendChild(getNode(bd.getName(), bd.getValue(obj), document, true));
                        } catch (IllegalAccessException e2) { e2.printStackTrace(); System.exit(-1); }
                    }
            }
        }
        
        
    if (recursive) {  
      if (obj instanceof ChildrenSource) {
        Children children = ((ChildrenSource)obj).getChildren();
        if (children != null) {
            Enumeration e = children.elements();
            while (e.hasMoreElements()) {
                try {
                    root.appendChild(getNode((OVTObject)e.nextElement(), document, true));
                } catch (ClassCastException e2) {System.err.println("Cannot create node. " + e2); }
            }
        }
      }
    }
    return root;
}

    
    public static void save(OVTObject obj, String xml_file) throws IOException {
        FileOutputStream out = new FileOutputStream(xml_file);
        try {
            buildDom(obj).write(out);
        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            System.out.println("Parser Error!" + pce);
            //pce.printStackTrace();
        }
        out.close();
    }
    
    
    

public static void load(String xml_file, OVTObject obj) throws IOException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    try {
           DocumentBuilder builder = factory.newDocumentBuilder();
           Document document = builder.parse( new File(xml_file) );
           // Cast to XmlDocument for write() operation
           // (Not defined until DOM Level 3.)
           XmlDocument xdoc = (XmlDocument) document;
           set(xdoc.getDocumentElement(), obj); // first child is OVT
           
         } catch (SAXParseException spe) {
           // Error generated by the parser
           System.out.println ("\n** Parsing error" 
              + ", line " + spe.getLineNumber ()
              + ", uri " + spe.getSystemId ());
           System.out.println("   " + spe.getMessage() );

           // Use the contained exception, if any
           Exception  x = spe;
           if (spe.getException() != null)
               x = spe.getException();
           x.printStackTrace();
           throw new IOException("Bad File Format : " + spe.getMessage());
        } catch (SAXException sxe) {
           // Error generated by this application
           // (or a parser-initialization error)
           Exception  x = sxe;
           if (sxe.getException() != null)
               x = sxe.getException();
               x.printStackTrace();
           throw new IOException("Bad File Format : " + sxe.getMessage());
        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();
            throw new IOException("Bad File Format : " + pce.getMessage());
        }
            
    }    

    
private static void setAttributes(NamedNodeMap map, Object obj) {
    if (obj instanceof DescriptorsSource) {
        Descriptors desc = ((DescriptorsSource)obj).getDescriptors();
        if (desc != null) {
            for (int i=0; i<map.getLength(); i++) {
                Attr attr = (Attr)map.item(i);
                String propertyName = attr.getNodeName();
                String value = Utils.replaceUnderlines(attr.getValue());
                
                if (propertyName.equals(NAME)) continue; //map.removeNamedItem(nodeName);
                Log.log("Setting '"+propertyName+"' to '"+value+"'", DEBUG);
                
                BasicPropertyDescriptor pd = desc.getDescriptor(propertyName);
                if (pd != null) {
                    if (value != null  || value != "null") {
                        try {
                            pd.getPropertyEditor().setAsText(value);
                        } catch (PropertyVetoException e2) { 
                            Log.err("Error setting " + propertyName + " in " + getName(obj) +
                                " : " + e2.getMessage(), 0);
                        }
                    } else 
                    Log.err("Property '" + propertyName + "' doesnt exist in " + getName(obj), 0);
                }
            }
       }
    }
}

private static void set(Element node, Object obj) {
    //System.out.println(getName(obj)); 
    setAttributes(node.getAttributes(), obj);
    
    if (obj instanceof ChildrenSource) {
        NodeList nodeList = node.getChildNodes();
        Object childObj = null; 
        ChildrenSource mama = (ChildrenSource)obj;
        for (int i=0; i<nodeList.getLength(); i++) {
            try {
                Element childNode = (Element)nodeList.item(i);
                String nodeName = childNode.getNodeName(); 
                Log.log("Node Name : '"+nodeName, DEBUG);
                if (nodeName.equals(OBJECT)) {// node is a child
                    
                    try { 
                        childObj = mama.getChildren().get(childNode.getAttribute(NAME));
                        set(childNode, childObj);
                    } catch (NullPointerException e2) {}
                    
                } else {// node is a bean-field tipo OVTCore.timeSettings
                    try {
                        Log.log("Field : '"+nodeName+"' in "+obj, DEBUG);
                        BeansCollection bc =  ((BeansSource)obj).getBeanDesriptors();
                        BasicBeanDescriptor bd = bc.getDescriptor(nodeName);
                        set(childNode, bd.getValue(obj));
                    } catch (IllegalAccessException e2) { e2.printStackTrace();System.exit(-1);
                    } catch (NullPointerException e3) { e3.printStackTrace();
                    }
                }
            } catch (ClassCastException ignore) {}
        }
    }
    
    if (obj instanceof FireChangeMethodSource) {
        Method method = ((FireChangeMethodSource)obj).getFireChangeMethod();
        try {
            method.invoke(obj, null);
        } catch (IllegalAccessException e2) {
        } catch (InvocationTargetException e3) { e3.printStackTrace();
        }
    }
}
    

public static String showSaveDialog(JFrame frameOwner, File defaultFile) {
    JFileChooser chooser = new JFileChooser(defaultFile); 
        chooser.setDialogTitle("Save Settings");
        chooser.setApproveButtonText("Save");
        if (!defaultFile.isDirectory()) chooser.setSelectedFile(defaultFile);
    	
    OvtExtensionFileFilter filter = new OvtExtensionFileFilter(); 
        filter.addExtension(".xml"); 
        filter.setDescription("OVT Config File (*.xml)"); 
        
    chooser.setFileFilter(filter);
    chooser.addChoosableFileFilter(filter);
	
    int returnVal = chooser.showSaveDialog(frameOwner);
	
    if (returnVal == JFileChooser.APPROVE_OPTION) {
        String fname = chooser.getSelectedFile().getAbsolutePath();
        javax.swing.filechooser.FileFilter fileFilter = chooser.getFileFilter();
        // fileFilter can be (*.*). It is not OVTExtensionFilter
        // to avoid ClassCastException - if case ;-)
        if (fileFilter instanceof OvtExtensionFileFilter) {   
            String ext = ((OvtExtensionFileFilter)fileFilter).getExtension();
            if (!fname.endsWith(ext)) fname += ext;
        }
	return fname;
    }
    return null;
}


/** Shows Open Dialog and returns selected filename or <CODE>null</CODE> */
public static String showOpenDialog(JFrame frameOwner, File defaultFile) {
    JFileChooser chooser = new JFileChooser(defaultFile); 
        chooser.setDialogTitle("Load Settings");
        chooser.setApproveButtonText("Load");
        if (!defaultFile.isDirectory()) chooser.setSelectedFile(defaultFile);
	
    OvtExtensionFileFilter filter = new OvtExtensionFileFilter(); 
        filter.addExtension(".xml"); 
        filter.setDescription("OVT Config File (*.xml)"); 
        chooser.setFileFilter(filter);
        chooser.addChoosableFileFilter(filter);
	
    chooser.setLocation(frameOwner.getLocation().x + 100,frameOwner.getLocation().y + 100);
	
    int returnVal = chooser.showOpenDialog(frameOwner);
	
    if(returnVal == JFileChooser.APPROVE_OPTION) {
        String fname = chooser.getSelectedFile().getAbsolutePath();
        return fname;
	
    }
    return null;
}

private static String getName(Object obj) {
    if (obj instanceof NamedObject) return ((NamedObject)obj).getName();
    else return obj.toString();
}

} // end of class
