/* DefaultWindowWrapper.java
 * =========================================================================
 * This file is part of the GrInvIn project - http://www.grinvin.org
 * 
 * Copyright (C) 2005-2008 Universiteit Gent
 * 
 * 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; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * 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.
 * 
 * A copy of the GNU General Public License can be found in the file
 * LICENSE.txt provided with the source distribution of this program (see
 * the META-INF directory in the source jar). This license can also be
 * found on the GNU website at http://www.gnu.org/licenses/gpl.html.
 * 
 * If you did not receive a copy of the GNU General Public License along
 * with this program, contact the lead developer, or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

package org.grinvin.workspace;

import java.awt.Rectangle;
import java.awt.Window;
import java.io.IOException;

import org.grinvin.io.IOFormatException;
import org.grinvin.io.SectionLoader;
import org.grinvin.io.SectionSaver;

import org.jdom.DataConversionException;
import org.jdom.Element;

/**
 * Common super class of all wrappers that manage a single window of
 * type <tt>W</tt>.
 */
public abstract class DefaultWindowWrapper<W extends Window> implements Wrapper<W> {
    
    /**
     * {@inheritDoc}<p>
     * This implementation disposes of the associated window.
     */
    public void dispose(W window) {
        window.dispose();
    }
    
    //
    public abstract W create();
    
    /**
     * General purpose routine which can be used to set bounds
     * and visbility of any window.
     */
    protected static void loadWindowProperties(Element element, Window window) throws IOFormatException {
        window.setBounds(elementToBounds(element));
        try {
            window.setVisible(
                    element.getAttribute("isvisible").getBooleanValue() );
        } catch (DataConversionException ex) {
            throw new IOFormatException("Incorrect boolean attribute value", ex);
        }
    }
    
    /**
     * General purpose routine which can be used to save the
     * bounds and visibility of any window.
     */
    protected static void saveWindowProperties(Element element, Window window) {
        Rectangle bounds = window.getBounds();
        element.addContent(boundsToElement(bounds));
        element.setAttribute("isvisible", Boolean.toString(window.isVisible()));
    }
    
    private static Element boundsToElement(Rectangle bounds) {
        Element element = new Element("bounds");
        
        element.setAttribute("x", Integer.toString(bounds.x));
        element.setAttribute("y", Integer.toString(bounds.y));
        
        element.setAttribute("height", Integer.toString(bounds.height));
        element.setAttribute("width", Integer.toString(bounds.width));
        
        return element;
    }
    
    private static Rectangle elementToBounds(Element element) throws IOFormatException {
        Element child = element.getChild("bounds");
        
        if (child == null)
            throw new IOFormatException("expected <bounds> element");
        
        int x = Integer.parseInt(child.getAttributeValue("x"));
        int y = Integer.parseInt(child.getAttributeValue("y"));
        int height = Integer.parseInt(child.getAttributeValue("height"));
        int width = Integer.parseInt(child.getAttributeValue("width"));
        
        return new Rectangle(x, y, width, height);
    }
    
    /**
     * {@inheritDoc}<p>This implementation creates the window using
     * {@link #create} and sets window bounds and visibility
     * from the information in the workspace XML-file.
     */
    public W load(Element element, SectionLoader sloader) throws IOException {
        W window = create();
        loadWindowProperties(element, window);
        return window;
    }
    
    /**
     * Create a JDOM-element that contains the version information.
     * Further attributes and contents should be added later.
     */
    protected final Element baseElement() {
        return new Element(getElementName());
    }
    
    /**
     * {@inheritDoc}<p>This implementation saves the information obtained
     * from the method {@link #baseElement} and {@link #saveWindowProperties} into <tt>parent</tt> and leaves
     * the directory alone.
     */
    public void save(W window, Element parent, SectionSaver ssaver) throws IOException {
        Element result = baseElement();
        saveWindowProperties(result, window);
        parent.addContent(result);
    }
    
}
