eu.hydrologis.jgrass.geonotes.GeonotesHandler.java Source code

Java tutorial

Introduction

Here is the source code for eu.hydrologis.jgrass.geonotes.GeonotesHandler.java

Source

/*
 * JGrass - Free Open Source Java GIS http://www.jgrass.org 
 * (C) HydroloGIS - www.hydrologis.com 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.hydrologis.jgrass.geonotes;

import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.DEFAULTBACKGROUNDCOLORS;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.DEFAULT_GEONOTE_HEIGHT;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.DEFAULT_GEONOTE_TITLE;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.DEFAULT_GEONOTE_TYPE;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.DEFAULT_GEONOTE_WIDTH;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.DRAWING_EXTENTION;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.GEONOTE_BIN_DRAWINGS;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.GEONOTE_BIN_PROPERTIES;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.GEONOTE_BIN_TEXT;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.MEDIA_FOLDER;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.PINIMAGE_HEIGHT;
import static eu.hydrologis.jgrass.geonotes.GeonoteConstants.PINIMAGE_WIDTH;
import static org.hibernate.criterion.Order.asc;
import static org.hibernate.criterion.Restrictions.between;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.refractions.udig.mapgraphic.MapGraphic;
import net.refractions.udig.project.IMap;
import net.refractions.udig.project.ui.ApplicationGIS;
import net.refractions.udig.ui.ExceptionDetailsDialog;
import net.refractions.udig.ui.PlatformGIS;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.widgets.Display;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Restrictions;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

import eu.hydrologis.jgrass.beegisutils.BeegisUtilsPlugin;
import eu.hydrologis.jgrass.beegisutils.database.annotatedclasses.GeonotesDrawareaTable;
import eu.hydrologis.jgrass.beegisutils.database.annotatedclasses.GeonotesMediaboxBlobsTable;
import eu.hydrologis.jgrass.beegisutils.database.annotatedclasses.GeonotesMediaboxTable;
import eu.hydrologis.jgrass.beegisutils.database.annotatedclasses.GeonotesTable;
import eu.hydrologis.jgrass.beegisutils.database.annotatedclasses.GeonotesTextareaTable;
import eu.hydrologis.jgrass.beegisutils.database.annotatedclasses.GpsLogTable;
import eu.hydrologis.jgrass.beegisutils.jgrassported.DressedStroke;
import eu.hydrologis.jgrass.database.DatabasePlugin;
import eu.hydrologis.jgrass.geonotes.GeonoteConstants.NOTIFICATION;

/**
 * Wrapper class for {@link GeonotesTable}.
 * 
 * <p>
 * The class handles all the needed issues around a Geonote, from listeners 
 * to the persistence part. 
 * </p>
 * <p>
 * Two constructors are available:
 * <ul>
 *  <li>one which will create a new default note 
 *      and save it to the database</li>
 *  <li>one that takes an id, which will extract the necessary 
 *      infos from the database as needed</li>
 * </ul>
 * This assures an id to be always defined and properly persisted to database.
 * </p>
 * 
 * @author Andrea Antonello (www.hydrologis.com)
 */
@SuppressWarnings({ "unchecked", "nls" })
public class GeonotesHandler {

    private static final String GEONOTESMEDIA_NAME_FIELD = "mediaName";
    private static final String GEONOTESMEDIA_EXTERNAL_KEY_ID = "mediaboxId";
    private static final String GEONOTESTABLE_ID_FIELD = "id";
    private static final String GEONOTESTABLE_EXTERNAL_KEY_ID = "geonotesId";

    private List<GeonotesObserver> observers = new ArrayList<GeonotesObserver>();

    private Long id;
    private GeonotesTable geonoteTable;
    private GeonotesTextareaTable geonotesTextareaTable;
    private GeonotesDrawareaTable geonotesDrawareaTable;
    private List<GeonotesMediaboxTable> geonotesMediaboxTables;
    private Color color;

    private GeometryFactory gF = new GeometryFactory();

    private Session openSession() {
        try {
            return DatabasePlugin.getDefault().getActiveDatabaseConnection().openSession();
        } catch (Exception e) {
            String message = "An error occurred while connecting to the database";
            ExceptionDetailsDialog.openError(null, message, IStatus.ERROR, GeonotesPlugin.PLUGIN_ID, e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Constructs a new Geonote, making it immediatly persistent to database.
     * 
     * @param east easting coordinate in {@link DefaultGeographicCRS#WGS84}.
     * @param north northing coordinate in {@link DefaultGeographicCRS#WGS84}.
     * @param title a short title for the geonote or <code>null</code>.
     * @param info an information text or <code>null</code>.
     * @param type an id for the note type. Can currently be one of:
     *                  <br><ul>
     *                          <li>{@link #NORMAL} </li>
     *                          <li>{@link #GPS} </li>
     *                          <li>{@link #PHOTO} </li>
     *                      </ul>
     * @param creationTime the {@link DateTime} of creation of the geonote.
     * @param azimut the azimut value if the geonote has directionality or <code>null</code>.
     * @param color a color for the note in format r:g:b:a integers or <code>null</code>.
     * @param width a width for the geonote or <code>null</code>.
     * @param height a height for the geonote or <code>null</code>.
     * @throws Exception
     */
    public GeonotesHandler(Double east, Double north, String title, String info, Integer type,
            DateTime creationTime, Double azimut, String color, Integer width, Integer height) throws Exception {
        if (east == null) {
            throw new IllegalArgumentException("The east coordinate is a mandatory parameter to create a geonote.");
        }
        if (north == null) {
            throw new IllegalArgumentException("The west coordinate is a mandatory parameter to create a geonote.");
        }
        if (creationTime == null) {
            throw new IllegalArgumentException("The creationtime is a mandatory parameter to create a geonote.");
        }
        if (title == null) {
            title = DEFAULT_GEONOTE_TITLE;
        }
        if (info == null) {
            String dateString = creationTime.toString(BeegisUtilsPlugin.dateTimeFormatterYYYYMMDDHHMM);
            info = "Date:" + dateString + "\nN:" + north + "\nE:" + east;
        }
        if (type == null) {
            type = DEFAULT_GEONOTE_TYPE;
        }
        if (width == null) {
            width = DEFAULT_GEONOTE_WIDTH;
        }
        if (height == null) {
            height = DEFAULT_GEONOTE_HEIGHT;
        }
        if (color == null) {
            color = DEFAULTBACKGROUNDCOLORS[0][0] + ":" + DEFAULTBACKGROUNDCOLORS[0][1] + ":"
                    + DEFAULTBACKGROUNDCOLORS[0][2] + ":255";
        }

        Session session = openSession();
        try {
            Transaction transaction = session.beginTransaction();
            geonoteTable = new GeonotesTable();
            geonoteTable.setEast(east);
            geonoteTable.setNorth(north);
            geonoteTable.setType(type);
            geonoteTable.setTitle(title);
            geonoteTable.setInfo(info);
            geonoteTable.setCreationDateTime(creationTime);
            geonoteTable.setColor(color);
            geonoteTable.setWidth(width);
            geonoteTable.setHeight(height);
            if (azimut != null) {
                geonoteTable.setAzimut(azimut);
            }
            id = (Long) session.save(geonoteTable);
            geonoteTable.setTitle(geonoteTable.getTitle() + " - " + id);
            session.update(geonoteTable);
            transaction.commit();
        } finally {
            session.close();
        }
    }

    /**
     * Extracts a geonote from the database for a given id.
     * 
     * @param id the id of the geonote to search for.
     * @throws Exception
     */
    public GeonotesHandler(Long id) throws Exception {
        Session session = openSession();
        try {
            Criteria criteria = session.createCriteria(GeonotesTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_ID_FIELD, id));
            Object result = criteria.uniqueResult();
            if (result != null) {
                geonoteTable = (GeonotesTable) result;
                this.id = id;
            } else {
                throw new IOException("Couldn't retrieve a geonote with id: " + id);
            }
        } finally {
            session.close();
        }
    }

    /**
     * Wraps a geonote.
     * 
     * @param geonotesTable the {@link GeonotesTable}.
     */
    public GeonotesHandler(GeonotesTable geonotesTable) {
        this.geonoteTable = geonotesTable;
        this.id = geonotesTable.getId();
    }

    /**
     * Getter for the geonote's unique id.
     * 
     * @return the geonote's unique id.
     */
    public Long getId() {
        return id;
    }

    public Integer getType() {
        return geonoteTable.getType();
    }

    public Coordinate getPosition() {
        return new Coordinate(geonoteTable.getEast(), geonoteTable.getNorth());
    }

    public Double getAzimut() {
        return geonoteTable.getAzimut();
    }

    public DateTime getCreationDate() {
        return geonoteTable.getCreationDateTime();
    }

    public String getTitle() {
        return geonoteTable.getTitle();
    }

    public void setTitle(String title) {
        geonoteTable.setTitle(title);
        notifyObservers(NOTIFICATION.TITLECHANGED);
    }

    public String getInfo() {
        return geonoteTable.getInfo();
    }

    public void setInfo(String info) {
        geonoteTable.setInfo(info);
        notifyObservers(NOTIFICATION.TITLECHANGED);
    }

    public Integer getWidth() {
        return geonoteTable.getWidth();
    }

    public void setWidth(Integer width) {
        geonoteTable.setWidth(width);
        notifyObservers(NOTIFICATION.SIZECHANGED);
    }

    public Integer getHeight() {
        return geonoteTable.getHeight();
    }

    public void setHeight(Integer height) {
        geonoteTable.setHeight(height);
        notifyObservers(NOTIFICATION.SIZECHANGED);
    }

    public Color getColor(Display display) {
        if (color == null) {
            String[] colorSplit = geonoteTable.getColor().split(":");
            int[] colorRGB = new int[] { Integer.parseInt(colorSplit[0]), Integer.parseInt(colorSplit[1]),
                    Integer.parseInt(colorSplit[2]) };
            color = new Color(display, colorRGB[0], colorRGB[1], colorRGB[2]);
        }
        return color;
    }

    public String getColorString() {
        return geonoteTable.getColor();
    }

    public void setColor(Display display, String colorString) {
        if (color != null) {
            color.dispose();
        }
        geonoteTable.setColor(colorString);
        String[] colorSplit = colorString.split(":");
        int[] colorRGB = new int[] { Integer.parseInt(colorSplit[0]), Integer.parseInt(colorSplit[1]),
                Integer.parseInt(colorSplit[2]) };
        color = new Color(display, colorRGB[0], colorRGB[1], colorRGB[2]);

        notifyObservers(NOTIFICATION.STYLECHANGED);
    }

    public CoordinateReferenceSystem getCrs() {
        return geonoteTable.getGeonoteCrs();
    }

    /**
     * Extracts the {@link GeonotesTextareaTable} for this geonote from the database.
     * 
     * @return the {@link GeonotesTextareaTable} of the current geonote or null if none was found.
     */
    public GeonotesTextareaTable getGeonotesTextareaTable() {
        if (geonotesTextareaTable != null) {
            return geonotesTextareaTable;
        }
        Session session = openSession();
        try {
            Criteria criteria = session.createCriteria(GeonotesTextareaTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_EXTERNAL_KEY_ID, geonoteTable));
            List<GeonotesTextareaTable> resultsList = criteria.list();
            if (resultsList != null && resultsList.size() > 0) {
                geonotesTextareaTable = resultsList.get(0);
                return geonotesTextareaTable;
            }
            return null;
        } finally {
            session.close();
        }
    }

    /**
     * Extracts the {@link GeonotesDrawareaTable} for this geonote from the database.
     * 
     * @return the {@link GeonotesDrawareaTable} for this geonote.
     */
    public GeonotesDrawareaTable getGeonotesDrawareaTable() {
        if (geonotesDrawareaTable != null) {
            return geonotesDrawareaTable;
        }
        Session session = openSession();
        try {
            Criteria criteria = session.createCriteria(GeonotesDrawareaTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_EXTERNAL_KEY_ID, geonoteTable));
            List<GeonotesDrawareaTable> resultsList = criteria.list();
            if (resultsList != null && resultsList.size() > 0) {
                geonotesDrawareaTable = resultsList.get(0);
                return geonotesDrawareaTable;
            }
            return null;
        } finally {
            session.close();
        }
    }

    /**
     * Extracts the {@link GeonotesMediaboxTable}s for this geonote from the database.
     * 
     * @param mediaName the mediaName for which to retrieve the 
     *                  {@link GeonotesMediaboxTable} or null to get them all.
     * @return the {@link GeonotesMediaboxTable}s for this geonote.
     * @throws Exception
     */
    public List<GeonotesMediaboxTable> getGeonotesMediaboxTables(String mediaName) throws Exception {
        Session session = openSession();
        try {
            Criteria criteria = session.createCriteria(GeonotesMediaboxTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_EXTERNAL_KEY_ID, geonoteTable));
            if (mediaName != null) {
                criteria.add(Restrictions.eq(GEONOTESMEDIA_NAME_FIELD, mediaName));
            }
            geonotesMediaboxTables = criteria.list();
            return geonotesMediaboxTables;
        } finally {
            session.close();
        }
    }

    /**
     * Extracts the {@link GeonotesMediaboxBlobsTable} for the supplied {@link GeonotesMediaboxTable}.
     * 
     * @return the {@link GeonotesMediaboxBlobsTable} for the supplied {@link GeonotesMediaboxTable}.
     */
    public GeonotesMediaboxBlobsTable getGeonotesMediaboxBlobsTable(GeonotesMediaboxTable geonotesMediaboxTable) {
        Session session = openSession();
        try {
            Criteria criteria = session.createCriteria(GeonotesMediaboxBlobsTable.class);
            criteria.add(Restrictions.eq(GEONOTESMEDIA_EXTERNAL_KEY_ID, geonotesMediaboxTable));
            List<GeonotesMediaboxBlobsTable> resultsList = criteria.list();
            if (resultsList != null && resultsList.size() > 0) {
                GeonotesMediaboxBlobsTable geonotesMediaboxBlobsTable = resultsList.get(0);
                return geonotesMediaboxBlobsTable;
            }
            return null;
        } finally {
            session.close();
        }
    }

    /**
     * Persist everything needed and set to database.
     * 
     * <p>
     * Only the {@link GeonotesTable} needs to be persisted, since everything 
     * else is persisted as it comes in.
     * </p>
     */
    public void persistNote() {
        Session session = openSession();
        try {
            Transaction transaction = session.beginTransaction();
            session.saveOrUpdate(geonoteTable);
            transaction.commit();
        } finally {
            session.close();
        }
    }

    /**
     * Removes the current geonote and all related records from the database.
     * @throws Exception 
     */
    public void deleteNote() throws Exception {
        // delete mediaboxes
        List<GeonotesMediaboxTable> geonotesMediaboxTables = getGeonotesMediaboxTables(null);
        for (GeonotesMediaboxTable geonotesMediaboxTable : geonotesMediaboxTables) {
            String mediaName = geonotesMediaboxTable.getMediaName();
            deleteMedia(mediaName);
        }

        Session session = openSession();
        try {
            // start batch delete
            Transaction transaction = session.beginTransaction();
            // remove drawarea
            Query query = session.createQuery(
                    "delete " + GeonoteConstants.DRAWAREATABLE_NAME + " gda where gda.geonotesId = :geonotesId");
            query.setLong(GEONOTESTABLE_EXTERNAL_KEY_ID, id);
            query.executeUpdate();
            // remove properties
            query = session.createQuery(
                    "delete " + GeonoteConstants.TEXTAREATABLE_NAME + " gta where gta.geonotesId = :geonotesId");
            query.setLong(GEONOTESTABLE_EXTERNAL_KEY_ID, id);
            query.executeUpdate();

            // remove the geonote itself
            query = session
                    .createQuery("delete " + GeonoteConstants.GEONOTESTABLE_NAME + " g where g.id = :geonotesId");
            query.setLong(GEONOTESTABLE_EXTERNAL_KEY_ID, id);
            query.executeUpdate();

            transaction.commit();
        } finally {
            session.close();
        }
        notifyObservers(NOTIFICATION.NOTEREMOVED);
    }

    /**
     * Set the text of the {@link GeonotesTextareaTable} to a supplied value.
     * 
     * <p>If the textarea is not existing, it is created.</p>
     * 
     * @param text the text to save.
     */
    public void setTextarea(String text) {
        if (text == null) {
            throw new IllegalArgumentException("text can't be null.");
        }

        GeonotesTextareaTable textareaTable = getGeonotesTextareaTable();
        if (textareaTable == null) {
            textareaTable = new GeonotesTextareaTable();
            textareaTable.setGeonotesId(geonoteTable);
        }
        textareaTable.setText(text);

        Session session = openSession();
        try {
            Transaction transaction = session.beginTransaction();
            session.saveOrUpdate(textareaTable);
            transaction.commit();
        } finally {
            session.close();
        }

    }

    /**
     * Set the drawings of the {@link GeonotesDrawareaTable} to a supplied value.
     * 
     * <p>If the drawarea is not existing, it is created.</p>
     * 
     * @param drawings the drawings to save.
     */
    public void setDrawarea(ArrayList<DressedStroke> drawings) {
        if (drawings == null) {
            throw new IllegalArgumentException("drawings can't be null.");
        }

        GeonotesDrawareaTable drawareaTable = getGeonotesDrawareaTable();
        Session session = openSession();
        try {
            Transaction transaction = session.beginTransaction();
            if (drawareaTable == null) {
                drawareaTable = new GeonotesDrawareaTable();
                drawareaTable.setGeonotesId(geonoteTable);
            }
            drawareaTable.setDrawings(drawings);
            session.saveOrUpdate(drawareaTable);

            transaction.commit();
        } finally {
            session.close();
        }

    }

    /**
     * Add a media into the database.
     * 
     * @param mediaFile the file containing the media.
     * @param mediaName the name to use for lists.
     * @throws Exception
     */
    public void addMedia(File mediaFile, String mediaName) throws Exception {

        if (mediaFile.isDirectory()) {
            // we do not store folders
            return;
        }

        Session session = openSession();
        Transaction transaction = session.beginTransaction();
        try {
            // create mediabox
            GeonotesMediaboxTable newMediaBox = new GeonotesMediaboxTable();
            newMediaBox.setGeonotesId(geonoteTable);
            newMediaBox.setMediaName(mediaName);

            // create media blobs
            GeonotesMediaboxBlobsTable newMediaBlobs = new GeonotesMediaboxBlobsTable();
            // add dummy drawings
            ArrayList<DressedStroke> dummyDrawings = new ArrayList<DressedStroke>();
            newMediaBlobs.setDrawings(dummyDrawings);
            newMediaBlobs.setMediaboxId(newMediaBox);
            newMediaBlobs.saveFileToMediabox(mediaFile);

            session.save(newMediaBox);
            session.save(newMediaBlobs);
            transaction.commit();
        } finally {
            session.close();
        }
    }

    /**
     * Move a media from one geonote to this.
     * 
     * @param mediaName the name to use for lists.
     * @param srcGeonoteTableId the geonote id from which to take the media file.
     * @throws Exception
     */
    public void moveMedia(String mediaName, long srcGeonoteTableId) throws Exception {

        Session session = openSession();
        Transaction transaction = session.beginTransaction();
        try {
            Criteria criteria = session.createCriteria(GeonotesTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_ID_FIELD, srcGeonoteTableId));
            GeonotesTable srcGeonoteTable = (GeonotesTable) criteria.uniqueResult();
            if (srcGeonoteTable == null) {
                throw new IOException("Couldn't retrieve a geonote with id: " + id);
            }

            // extract media box
            criteria = session.createCriteria(GeonotesMediaboxTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_EXTERNAL_KEY_ID, srcGeonoteTable));
            criteria.add(Restrictions.eq(GEONOTESMEDIA_NAME_FIELD, mediaName));
            GeonotesMediaboxTable geonotesMediaboxTable = (GeonotesMediaboxTable) criteria.uniqueResult();

            // and simply change its parent
            geonotesMediaboxTable.setGeonotesId(geonoteTable);

            session.update(geonotesMediaboxTable);
            transaction.commit();
        } finally {
            session.close();
        }
    }

    /**
     * Delete a media from the database.
     * 
     * @param dndF the handler to the media.
     * @throws Exception
     */
    public void deleteMedia(DndFile dndF) throws Exception {
        String mediaName = dndF.name;
        deleteMedia(mediaName);
    }

    /**
     * Delete a media from the database.
     * 
     * @param name the name of the media.
     * @throws Exception
     */
    public void deleteMedia(String mediaName) throws Exception {
        Session session = openSession();
        try {
            Transaction transaction = session.beginTransaction();
            Criteria criteria = session.createCriteria(GeonotesMediaboxTable.class);
            criteria.add(Restrictions.eq(GEONOTESTABLE_EXTERNAL_KEY_ID, geonoteTable));
            criteria.add(Restrictions.eq(GEONOTESMEDIA_NAME_FIELD, mediaName));
            List<GeonotesMediaboxTable> resultList = criteria.list();
            GeonotesMediaboxTable mediabox = resultList.get(0);
            Long mediaboxId = mediabox.getId();
            // delete mediabox
            session.delete(mediabox);

            // delete blob
            Query query = session.createQuery("delete " + GeonoteConstants.MEDIABOXBLOBSTABLE_CLASSNAME
                    + " gb where gb.mediaboxId = :mediaboxId");
            query.setLong(GEONOTESMEDIA_EXTERNAL_KEY_ID, mediaboxId);
            query.executeUpdate();

            transaction.commit();
        } finally {
            session.close();
        }
    }

    /**
     * Set the drawings connected to a particular media.
     * 
     * @param drawings the drawings.
     * @param mediaName the name of the media to set the drawing of. This has 
     *              to refer to an existing media. 
     * @throws Exception
     */
    public void setMediaDrawings(ArrayList<DressedStroke> drawings, String mediaName) throws Exception {
        if (drawings == null || mediaName == null) {
            throw new IllegalArgumentException("drawings/mediaName can't be null.");
        }

        List<GeonotesMediaboxTable> mediaboxTables = getGeonotesMediaboxTables(mediaName);
        if (mediaboxTables == null || mediaboxTables.size() == 0) {
            throw new IllegalArgumentException("Couldn't retrieve any mediabox for the name: " + mediaName);
        }

        GeonotesMediaboxBlobsTable mediaboxBlobsTable = getGeonotesMediaboxBlobsTable(mediaboxTables.get(0));
        mediaboxBlobsTable.setDrawings(drawings);

        Session session = openSession();
        try {
            Transaction transaction = session.beginTransaction();
            session.saveOrUpdate(mediaboxBlobsTable);
            transaction.commit();
        } finally {
            session.close();
        }
    }

    /**
     * The method to extract the files that are stored in a database.
     * 
     * @param folder the folder into which extract the media. 
     *                      If null, tmp is used
     * @param mediaName the name of the media to extract, as given by 
     *                      {@link GeonotesHandler#getMediaNames()}
     * @param drawingList the drawing objects, if there are any, are 
     *                      copied into this list. Can be null, in which case 
     *                      the drawings are not considered.
     * @return the {@link File} to the extracted media.
     */
    public File extractMediaToPath(File folder, String mediaName, List<DressedStroke> drawingList)
            throws Exception {
        if (folder == null) {
            // extract to tmp
            String tmpDirPath = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
            folder = new File(tmpDirPath);
        }
        File file = new File(folder, mediaName);
        List<GeonotesMediaboxTable> mediaboxTables = getGeonotesMediaboxTables(mediaName);
        GeonotesMediaboxBlobsTable mediaboxBlobsTable = getGeonotesMediaboxBlobsTable(mediaboxTables.get(0));
        mediaboxBlobsTable.getFromMediaboxToFile(file);
        List<DressedStroke> drawings = mediaboxBlobsTable.getDrawings();
        drawingList.addAll(drawings);
        return file;
    }

    /**
     * Creates a boundary Envelope for the Geonote and its icon in the {@link MapGraphic}.
     * 
     * @param destinationCrs the {@linkplain CoordinateReferenceSystem crs} in which 
     *                      the envelope is needed.
     * @return the {@linkplain ReferencedEnvelope envelope} for the geonote.
     */
    public ReferencedEnvelope getBoundsAsReferenceEnvelope(CoordinateReferenceSystem destinationCrs) {

        Coordinate position = new Coordinate(geonoteTable.getEast(), geonoteTable.getNorth());
        CoordinateReferenceSystem noteCrs = geonoteTable.getGeonoteCrs();

        Coordinate reprojectedCoordinate = position;

        if (!CRS.equalsIgnoreMetadata(noteCrs, destinationCrs)) {
            try {
                // transform coordinates before check
                MathTransform transform = CRS.findMathTransform(noteCrs, destinationCrs, true);
                // jts geometry
                com.vividsolutions.jts.geom.Point pt = gF.createPoint(new Coordinate(position.x, position.y));
                Geometry targetGeometry = JTS.transform(pt, transform);
                reprojectedCoordinate = targetGeometry.getCoordinate();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // I need to reconstruct the pin size (16x16)
        Coordinate pixelSize = ApplicationGIS.getActiveMap().getViewportModel().getPixelSize();
        double pixelWidth = pixelSize.x;
        double pixelHeight = pixelSize.y;

        double deltaX = pixelWidth * (double) PINIMAGE_WIDTH;
        double deltaY = pixelHeight * (double) PINIMAGE_HEIGHT;
        Coordinate lowerLeft = new Coordinate(reprojectedCoordinate.x - deltaX, reprojectedCoordinate.y - deltaY);
        Coordinate upperRight = new Coordinate(reprojectedCoordinate.x + deltaX, reprojectedCoordinate.y + deltaY);
        ReferencedEnvelope refEnvelope = new ReferencedEnvelope(new Envelope(lowerLeft, upperRight),
                destinationCrs);

        return refEnvelope;
    }

    /**
     * Dump the contents of a geonote to disk.
     * 
     * @param folderPath the folder into which dump the geonotes data structure.
     * @param drawAreaImage 
     * @throws Exception
     */
    public void dumpNote(final String folderPath, final Image drawAreaImage) throws Exception {

        IRunnableWithProgress operation = new IRunnableWithProgress() {

            public void run(IProgressMonitor pm) throws InvocationTargetException, InterruptedException {

                try {
                    pm.beginTask("Dump geonote to disk.", 2);
                    File folderFile = new File(folderPath);
                    if (!folderFile.exists()) {
                        throw new InterruptedException("The supplied folder " + folderPath
                                + " doesn't exist. Can't dump the geonote into it.");
                    }

                    String title = geonoteTable.getTitle();
                    title = title.replace(' ', '_');
                    File mainDir = new File(folderFile.getAbsolutePath() + File.separator + title);
                    if (!mainDir.exists() && !mainDir.mkdir()) {
                        throw new InterruptedException("Coudn't create folder: " + mainDir.getAbsolutePath());
                    }

                    // dump info text
                    try {
                        File textFile = new File(mainDir.getAbsolutePath() + File.separator + "geonote_info.txt");
                        BufferedWriter bW = new BufferedWriter(new FileWriter(textFile));

                        StringBuilder msgBuilder = new StringBuilder();
                        msgBuilder.append("Geonote id: ");
                        msgBuilder.append(id);
                        msgBuilder.append("\n\n");
                        msgBuilder.append("Geonote title: ");
                        msgBuilder.append(title);
                        msgBuilder.append("\n\n");
                        msgBuilder.append("Geonote color: ");
                        String colorString = getColorString();
                        msgBuilder.append("r:g:b:a = ");
                        msgBuilder.append(colorString);
                        msgBuilder.append("\n\n");
                        msgBuilder.append("Geonote type: ");
                        msgBuilder.append(getType());
                        msgBuilder.append("\n\n");
                        msgBuilder.append("Creation date: ");
                        DateTime creationDateTime = geonoteTable.getCreationDateTime();
                        msgBuilder
                                .append(creationDateTime.toString(BeegisUtilsPlugin.dateTimeFormatterYYYYMMDDHHMM));
                        msgBuilder.append("\n\n");
                        msgBuilder.append("Position (WGS 84 lat/long): ");
                        Coordinate position = new Coordinate(geonoteTable.getEast(), geonoteTable.getNorth());
                        msgBuilder.append(position.x);
                        msgBuilder.append(" / ");
                        msgBuilder.append(position.y);
                        msgBuilder.append("\n\n");

                        IMap activeMap = ApplicationGIS.getActiveMap();
                        if (activeMap != null) {
                            CoordinateReferenceSystem mapCrs = activeMap.getViewportModel().getCRS();
                            String crsName = mapCrs.getName().toString();
                            msgBuilder.append("Position (" + crsName + "): ");
                            MathTransform mathTransform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, mapCrs,
                                    true);
                            Coordinate newPosition = JTS.transform(position, null, mathTransform);
                            msgBuilder.append(newPosition.x);
                            msgBuilder.append(" / ");
                            msgBuilder.append(newPosition.y);
                            msgBuilder.append("\n\n");
                        }
                        bW.write(msgBuilder.toString());
                        bW.close();
                        pm.worked(1);
                    } catch (Exception e) {
                        e.printStackTrace();
                        GeonotesPlugin.log("GeonotesPlugin problem: eu.hydrologis.jgrass.geonotes##run", e); //$NON-NLS-1$
                    }

                    // dump text
                    try {
                        File textFile = new File(
                                mainDir.getAbsolutePath() + File.separator + "geonote_textbox.txt");
                        BufferedWriter bW = new BufferedWriter(new FileWriter(textFile));
                        GeonotesTextareaTable textareaTable = getGeonotesTextareaTable();
                        String text = "";
                        if (textareaTable != null) {
                            String tmptext = textareaTable.getText();
                            if (text != null) {
                                text = tmptext;
                            }
                        }
                        bW.write(text);
                        bW.close();
                        pm.worked(1);
                    } catch (Exception e) {
                        e.printStackTrace();
                        GeonotesPlugin.log("GeonotesPlugin problem: eu.hydrologis.jgrass.geonotes##run", e); //$NON-NLS-1$
                    }

                    try {
                        // dump image
                        File imageFile = new File(
                                mainDir.getAbsolutePath() + File.separator + "geonote_paintbox.png");
                        if (drawAreaImage != null) {
                            OutputStream out = new FileOutputStream(imageFile);
                            ImageLoader imageLoader = new ImageLoader();
                            imageLoader.data = new ImageData[] { drawAreaImage.getImageData() };
                            imageLoader.save(out, SWT.IMAGE_PNG);
                            out.close();
                        }

                        pm.worked(1);
                    } catch (Exception e) {
                        e.printStackTrace();
                        GeonotesPlugin.log("GeonotesPlugin problem: eu.hydrologis.jgrass.geonotes##run", e); //$NON-NLS-1$
                    }
                    pm.done();

                    // dump media box
                    File mediaDir = new File(mainDir.getAbsolutePath() + File.separator + "geonote_mediabox");
                    if (!mediaDir.exists() && !mediaDir.mkdir()) {
                        throw new InterruptedException("Coudn't create folder: " + mediaDir.getAbsolutePath());
                    }

                    List<GeonotesMediaboxTable> mediaboxTables = getGeonotesMediaboxTables(null);
                    pm.beginTask("Dump media box to disk.", mediaboxTables.size());
                    for (GeonotesMediaboxTable mediaboxTable : mediaboxTables) {
                        GeonotesMediaboxBlobsTable mediaboxBlobsTable = getGeonotesMediaboxBlobsTable(
                                mediaboxTable);
                        String mediaName = mediaboxTable.getMediaName();

                        File file = new File(mediaDir, mediaName);
                        mediaboxBlobsTable.getFromMediaboxToFile(file);

                        pm.worked(1);
                    }
                    pm.done();
                } catch (Exception e) {
                    GeonotesPlugin.log("GeonotesPlugin problem: eu.hydrologis.jgrass.geonotes##run", e); //$NON-NLS-1$
                    e.printStackTrace();
                    throw new InterruptedException(e.getLocalizedMessage());
                }

            }

        };

        PlatformGIS.runInProgressDialog("Dump geonote", true, operation, true);

    }

    /**
     * Dump the contents of a geonote to disk in binary mode, usefull for sending or exporting.
     * 
     * <p>
     * When a geonote is dumped in binary mode, the following folder structure is created:
     * <pre>
     * geonotes(_nn)       (where _nn is added as index if the folder exists at dump time)
     *      |
     *      |- 0    (for first note)
     *      |  |-- geonote.bin (binary geonote serialized file see BinaryGeonote)
     *      |  `-- media
     *      |       |-- media1
     *      |       |-- media1.drawing (if it is an image and has drawing
     *      |       |-- media2
     *      |       |-- media3
     *      |       |-- ...
     *      |       `-- median
     *      |
     *      |- 1    (for second note)
     *      |  |-- geonote.bin 
     *      |  `-- media
     *      |       |-- media1
     *      |       |-- media1.drawing (if it is an image and has drawing
     *      |       `-- ...
     *      |...
     *      |
     *      `- n
     * </pre>
     * and the folder is then compressed.
     * </p>
     * 
     * @param folderPath the folder into which dump the geonotes data structure.
     */
    public void dumpBinaryNote(final String folderPath) throws Exception {

        IRunnableWithProgress operation = new IRunnableWithProgress() {

            public void run(IProgressMonitor pm) throws InvocationTargetException, InterruptedException {

                try {

                    File folderFile = new File(folderPath);
                    if (!folderFile.exists()) {
                        throw new InterruptedException("The supplied folder " + folderPath
                                + " doesn't exist. Can't dump the geonote into it.");
                    }

                    /*
                     * dump note to disk
                     */
                    GeonotesTextareaTable textareaTable = getGeonotesTextareaTable();
                    String text = "";
                    if (textareaTable != null) {
                        String tmp = textareaTable.getText();
                        if (tmp != null) {
                            text = tmp;
                        }
                    }
                    GeonotesDrawareaTable drawareaTable = getGeonotesDrawareaTable();
                    DressedStroke[] drawingArray = new DressedStroke[0];
                    if (drawareaTable != null) {
                        List<DressedStroke> drawing = drawareaTable.getDrawings();
                        drawingArray = (DressedStroke[]) drawing.toArray(new DressedStroke[drawing.size()]);
                    }

                    // the geonote
                    File dumpFile = new File(folderFile, GEONOTE_BIN_PROPERTIES);
                    FileOutputStream fos = new FileOutputStream(dumpFile);
                    ObjectOutputStream out = new ObjectOutputStream(fos);
                    out.writeObject(geonoteTable);
                    out.close();
                    fos.close();

                    // dressedstrokes
                    dumpFile = new File(folderFile, GEONOTE_BIN_DRAWINGS);
                    fos = new FileOutputStream(dumpFile);
                    out = new ObjectOutputStream(fos);
                    out.writeObject(drawingArray);
                    out.close();
                    fos.close();
                    pm.worked(1);

                    // text
                    dumpFile = new File(folderFile, GEONOTE_BIN_TEXT);
                    BufferedWriter bW = new BufferedWriter(new FileWriter(dumpFile));
                    bW.write(text);
                    bW.close();

                    /*
                     * dump media content to disk
                     */
                    List<GeonotesMediaboxTable> mediaboxTables = getGeonotesMediaboxTables(null);

                    if (mediaboxTables != null) {
                        pm.beginTask("Export geonote: " + getTitle(), mediaboxTables.size() + 1);
                        File mediaFolder = new File(folderFile, MEDIA_FOLDER);
                        if (mediaFolder.mkdir()) {
                            for (GeonotesMediaboxTable mediaBox : mediaboxTables) {
                                List<DressedStroke> drawingList = new ArrayList<DressedStroke>();

                                // TODO change the following method
                                String mediaName = mediaBox.getMediaName();
                                extractMediaToPath(mediaFolder, mediaName, drawingList);

                                // dump drawings on media if they exist
                                if (drawingList.size() > 0) {
                                    DressedStroke[] drawingsArray = (DressedStroke[]) drawingList
                                            .toArray(new DressedStroke[drawingList.size()]);
                                    File drawingFile = new File(mediaFolder, mediaName + DRAWING_EXTENTION);
                                    FileOutputStream foStream = new FileOutputStream(drawingFile);
                                    ObjectOutputStream outStream = new ObjectOutputStream(foStream);
                                    outStream.writeObject(drawingsArray);
                                    outStream.close();
                                    foStream.close();
                                }
                            }
                            pm.worked(1);
                        }
                        pm.done();
                    }
                } catch (Exception e) {
                    GeonotesPlugin.log("GeonotesPlugin problem: eu.hydrologis.jgrass.geonotes##dumpBinaryNote", e); //$NON-NLS-1$
                    e.printStackTrace();
                    throw new InterruptedException(e.getLocalizedMessage());
                }

            }

        };

        PlatformGIS.runInProgressDialog("Export geonote", true, operation, false);

    }

    /**
     * @return all the {@link GeonotesTable}s wrapped in {@link GeonotesHandler}s.
     */
    public static List<GeonotesHandler> getGeonotesHandlers() {
        Session session = null;
        try {
            session = DatabasePlugin.getDefault().getActiveDatabaseConnection().openSession();
            List<GeonotesHandler> geonotesHandlers = new ArrayList<GeonotesHandler>();
            Criteria criteria = session.createCriteria(GeonotesTable.class);
            List<GeonotesTable> resultsList = criteria.list();
            for (int i = 0; i < resultsList.size(); i++) {
                geonotesHandlers.add(new GeonotesHandler(resultsList.get(i)));
            }
            return geonotesHandlers;
        } catch (Exception e) {
            String message = "An error occurred while connecting to the database";
            ExceptionDetailsDialog.openError(null, message, IStatus.ERROR, GeonotesPlugin.PLUGIN_ID, e);
            e.printStackTrace();
            return Collections.EMPTY_LIST;
        } finally {
            session.close();
        }
    }

    /**
     * @return all the {@link GeonotesTable}s.
     * @throws Exception 
     */
    public static List<GeonotesTable> getGeonotesTables() throws Exception {
        Session session = null;
        try {
            session = DatabasePlugin.getDefault().getActiveDatabaseConnection().openSession();
            Criteria criteria = session.createCriteria(GeonotesTable.class);
            List<GeonotesTable> resultsList = criteria.list();
            return resultsList;
        } finally {
            session.close();
        }
    }

    /**
     * Fetches a gps coordinate from the database nearest to a supplied time and date.
     * 
     * @param dateTime the time to search for.
     * @return the coordinate of the nearest time.
     * @throws Exception
     */
    public static Coordinate getGpsCoordinateForTimeStamp(DateTime dateTime, int minutesThreshold)
            throws Exception {
        DateTime from = dateTime.minusMinutes(minutesThreshold);
        DateTime to = dateTime.plusMinutes(minutesThreshold);

        Session session = null;
        try {
            session = DatabasePlugin.getDefault().getActiveDatabaseConnection().openSession();
            Criteria criteria = session.createCriteria(GpsLogTable.class);
            String utcTimeStr = "utcTime";
            criteria.add(between(utcTimeStr, from, to));
            criteria.addOrder(asc(utcTimeStr));

            List<GpsLogTable> resultsList = criteria.list();
            for (int i = 0; i < resultsList.size() - 1; i++) {

                GpsLogTable gpsLog1 = resultsList.get(i);
                GpsLogTable gpsLog2 = resultsList.get(i + 1);

                DateTime utcTimeBefore = gpsLog1.getUtcTime();
                DateTime utcTimeAfter = gpsLog2.getUtcTime();

                Interval interval = new Interval(utcTimeBefore, utcTimeAfter);
                if (interval.contains(dateTime)) {
                    // take the nearest
                    Interval intervalBefore = new Interval(utcTimeBefore, dateTime);
                    Interval intervalAfter = new Interval(dateTime, utcTimeAfter);
                    long beforeMillis = intervalBefore.toDurationMillis();
                    long afterMillis = intervalAfter.toDurationMillis();
                    if (beforeMillis < afterMillis) {
                        Coordinate coord = new Coordinate(gpsLog1.getEast(), gpsLog1.getNorth());
                        return coord;
                    } else {
                        Coordinate coord = new Coordinate(gpsLog2.getEast(), gpsLog2.getNorth());
                        return coord;
                    }
                }

            }
        } finally {
            session.close();
        }
        return null;
    }

    public void addObserver(GeonotesObserver observer) {
        if (!observers.contains(observer)) {
            observers.add(observer);
        }
    }

    public void removeObserver(GeonotesObserver observer) {
        if (observers.contains(observer)) {
            observers.remove(observer);
        }
    }

    public void notifyObservers(Object arg) {
        for (GeonotesObserver observer : observers) {
            observer.updateFromGeonotes(this, arg);
        }
    }

    public boolean equals(Object obj) {
        if (obj instanceof GeonotesHandler) {
            GeonotesHandler geonoteHandler = (GeonotesHandler) obj;
            return getId().equals(geonoteHandler.getId());
        }
        return false;
    }

    public int hashCode() {
        return getId().intValue();
    }

    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("Geonote ID: ");
        stringBuilder.append(getId());
        stringBuilder.append("\n");
        stringBuilder.append("Title: ");
        stringBuilder.append(getTitle());
        stringBuilder.append("\n");
        stringBuilder.append("Easting: ");
        stringBuilder.append(geonoteTable.getEast());
        stringBuilder.append("\n");
        stringBuilder.append("Northing: ");
        stringBuilder.append(geonoteTable.getNorth());
        stringBuilder.append("\n");
        stringBuilder.append("Info: ");
        stringBuilder.append(getInfo());
        stringBuilder.append("\n");
        stringBuilder.append("type: ");
        stringBuilder.append(geonoteTable.getType());
        stringBuilder.append("\n");
        stringBuilder.append("Has color RGBA: ");
        stringBuilder.append(getColorString());
        String str = stringBuilder.toString();
        return str;
    }
}