Index: DefaultProject.java
===================================================================
--- DefaultProject.java	(revision 44087)
+++ DefaultProject.java	(revision 44088)
@@ -40,6 +40,7 @@
 import java.io.Serializable;
 import java.text.DateFormat;
 import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -55,6 +56,8 @@
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 import javax.imageio.ImageIO;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOUtils;
 
 import org.cresques.cts.IProjection;
@@ -186,6 +189,7 @@
         return preferences;
     }
 
+    @Override
     public void propertyChange(PropertyChangeEvent evt) {
         change.firePropertyChange(evt);
     }
@@ -206,6 +210,7 @@
      *
      * @return
      */
+    @Override
     public String getCreationDate() {
         return creationDate;
     }
@@ -215,6 +220,7 @@
         change.firePropertyChange("setCreationDate", null, null);
     }
 
+    @Override
     public Document createDocument(String type) {
         logger.info("createDocument('{}')", type);
         return ProjectManager.getInstance().createDocument(type);
@@ -225,6 +231,7 @@
      *
      * @return
      */
+    @Override
     public String getName() {
         return name;
     }
@@ -234,6 +241,7 @@
      *
      * @param string
      */
+    @Override
     public void setName(String name) {
         this.name = name;
         change.firePropertyChange("setName", null, null);
@@ -244,6 +252,7 @@
      *
      * @return comments
      */
+    @Override
     public String getComments() {
         return comments;
     }
@@ -253,6 +262,7 @@
      *
      * @param comments as string
      */
+    @Override
     public void setComments(String string) {
         comments = string;
         change.firePropertyChange("setComments", null, null);
@@ -263,6 +273,7 @@
      *
      * @return modification date as string
      */
+    @Override
     public String getModificationDate() {
         return modificationDate;
     }
@@ -277,6 +288,7 @@
      *
      * @return author as string
      */
+    @Override
     public String getOwner() {
         return owner;
     }
@@ -286,6 +298,7 @@
      *
      * @param author name as string
      */
+    @Override
     public void setOwner(String owner) {
         this.owner = owner;
         change.firePropertyChange("setOwner", null, null);
@@ -296,6 +309,7 @@
      *
      * @return
      */
+    @Override
     public Color getSelectionColor() {
         if (selectionColor == null) {
             selectionColor = getPreferences().getDefaultSelectionColor();
@@ -308,6 +322,7 @@
      *
      * @param selection color as string
      */
+    @Override
     public void setSelectionColor(String selectionColor) {
         this.setSelectionColor(StringUtilities.string2Color(selectionColor));
     }
@@ -317,12 +332,14 @@
      *
      * @param selection color as Color
      */
+    @Override
     public void setSelectionColor(Color selectionColor) {
         this.selectionColor = selectionColor;
         MapContext.setSelectionColor(selectionColor);
         change.firePropertyChange("selectionColor", null, selectionColor);
     }
 
+    @Override
     public IProjection getProjection() {
         if (projection == null) {
             projection = getPreferences().getDefaultProjection();
@@ -330,6 +347,7 @@
         return projection;
     }
 
+    @Override
     public void setProjection(IProjection projection) {
         this.projection = projection;
     }
@@ -341,6 +359,7 @@
      *
      * @param modified as boolean
      */
+    @Override
     public void setModified(boolean modified) {
         this.modified = modified;
         if (modified == false) {
@@ -351,6 +370,7 @@
         }
     }
 
+    @Override
     public boolean hasChanged() {
 		// we return true if the project is not empty (until we have a better
         // method...)
@@ -365,6 +385,7 @@
      *
      * @return documents as List of IProjectDocument
      */
+    @Override
     public List<Document> getDocuments() {
         return Collections.unmodifiableList(documents);
     }
@@ -376,6 +397,7 @@
      *
      * @return List of IProjectDocument
      */
+    @Override
     public List<Document> getDocuments(String type) {
         List<Document> docs = new ArrayList<Document>();
         if (type != null) {
@@ -393,10 +415,12 @@
      *
      * @param document as Document
      */
+    @Override
     public void add(Document document) {
         this.addDocument(document);
     }
 
+    @Override
     public void addDocument(Document document) {
         logger.info("add('{}')", document.toString());
 
@@ -414,10 +438,12 @@
         change.firePropertyChange("addDocument", null, document);
     }
 
+    @Override
     public void remove(Document doc) {
         this.removeDocument(doc);
     }
 
+    @Override
     public void removeDocument(Document doc) {
         logger.info("remove('{}')", doc.toString());
         if (notifyObservers(ProjectNotification.BEFORE_REMOVE_DOCUMENT, doc).isProcessCanceled()) {
@@ -430,10 +456,12 @@
         notifyObservers(ProjectNotification.AFTER_REMOVE_DOCUMENT, doc);
     }
 
+    @Override
     public Iterator<Document> iterator() {
         return documents.iterator();
     }
 
+    @Override
     public boolean isEmpty() {
         return documents.isEmpty();
     }
@@ -448,6 +476,7 @@
      * @throws RuntimeException Si la capa que se pasa como par�metro no se
      * encuentra en ninguna vista
      */
+    @Override
     public String getViewName(FLayer layer) {
         List<Document> views = getDocuments(ViewManager.TYPENAME);
         for (int v = 0; v < views.size(); v++) {
@@ -476,16 +505,19 @@
         return false;
     }
 
+    @Override
     public void addExtent(ProjectExtent arg1) {
         extents.add(arg1);
         change.firePropertyChange("addExtent", null, null);
     }
 
+    @Override
     public ProjectExtent removeExtent(int arg0) {
         change.firePropertyChange("delExtent", null, null);
         return extents.remove(arg0);
     }
 
+    @Override
     public ProjectExtent[] getExtents() {
         return (ProjectExtent[]) extents.toArray(new ProjectExtent[0]);
     }
@@ -500,6 +532,7 @@
      *
      * @return Documento
      */
+    @Override
     public Document getDocument(String name, String type) {
         if (type == null) {
             for (int i = 0; i < documents.size(); i++) {
@@ -520,6 +553,7 @@
         return null;
     }
 
+    @Override
     public Document getDocument(String name) {
         return this.getDocument(name, null);
     }
@@ -556,6 +590,7 @@
         }
     }
 
+    @Override
     public void saveState(File out) throws PersistenceException {
         FileOutputStream fout;
         if (notifyObservers(ProjectNotification.BEFORE_SAVE_TO_FILE, out).isProcessCanceled()) {
@@ -565,12 +600,15 @@
             fout = new FileOutputStream(out);
             saveState(fout, new File(out.getParent()));
         } catch (FileNotFoundException e) {
+            createProjectCopy(true);
             throw new PersistenceException(e);
         }
         if( !isValidZIP(out) ) {
             throw new PersistenceException(new ZipException());
         }
         this.fname = out;
+        //sacar copia al bak
+        createProjectCopy(false);
         notifyObservers(ProjectNotification.AFTER_SAVE_TO_FILE, out);
     }
 
@@ -580,6 +618,7 @@
             zipfile = new ZipFile(file);
             return true;
         } catch (IOException e) {
+            //sacar copia. 
             return false;
         } finally {
             try {
@@ -625,11 +664,16 @@
                 throw new ZipException("Invalid project file '"+file.getAbsolutePath()+"'");
             }
             this.fname = file;
+            if (file.exists()) {
+                createProjectCopy(false);
+            }
         } catch (Exception ex) {
-            throw new RuntimeException("Can't write project in '"+file.getAbsolutePath()+".",ex);
+            createProjectCopy(true);
+            throw new RuntimeException("Can't write project in '" + file.getAbsolutePath() + ".", ex);
         } finally {
             IOUtils.closeQuietly(zout);
-            IOUtils.closeQuietly(fout);            
+            IOUtils.closeQuietly(fout);
+
         }
     }
     
@@ -651,13 +695,75 @@
         }
         manager.saveState(state, out, true);
         if (state.getContext().getErrors() != null) {
+            createProjectCopy(true);
             throw state.getContext().getErrors();
         }
         this.fname = null;
         notifyObservers(ProjectNotification.AFTER_SAVE_TO_STREAM, rootFolder);
     }
+    
+    private File getNameFileForProject(File actualProjectFile, boolean error) {
+        // if there is a error, creates a file with a unique timecode
+        // not error: return path with .gvsproj.bak extension that could exists
+               
+        if (actualProjectFile==null) {
+            LOG.info("Doesn't have previous project to create a bak");
+            return null;
+        }
+        String noExt = FilenameUtils.removeExtension(actualProjectFile.getAbsolutePath());
+        String timeCode = new SimpleDateFormat("_MMddHHmmss").format(new Date());
+        String ext = ".gvsproj.bak";
 
+        int code = 0;
+        if (noExt.length() > 230) {
+            noExt = noExt.substring(0, 229);
+        }
+        
+        File bakProjectFile;
+        if (error) {
+            bakProjectFile = new File(noExt + timeCode + ext);
+            while (bakProjectFile.exists()) {
+                code = code + 1;
+                bakProjectFile = new File(noExt + timeCode + "_" + code + ext);
+            }
+        } else {
+            bakProjectFile = new File(noExt + ext);
+        }
+        return bakProjectFile;
+    }
+    public File createProjectCopy(boolean error) {
+        File actualProjectFile = ApplicationLocator.getProjectManager().getCurrentProject().getFile();
+        File bakProjectFile = getNameFileForProject(actualProjectFile, error);
+        if (bakProjectFile==null){
+            return null;
+        }
+        if (!error){
+            try {
+                if (bakProjectFile.exists()){
+                    FileUtils.deleteQuietly(bakProjectFile);
+                }
+            } catch (Exception ex) {
+                LOG.error("Not possible to delete file", ex);
+            }
+            try {
+                FileUtils.copyFile(actualProjectFile, bakProjectFile);
+            } catch (IOException ex) {
+                LOG.error("Can't create bak copy from project", ex);
+            }
+        } else {
+            File bakProjectFile2 = getNameFileForProject(actualProjectFile, false);
+            try {
+                FileUtils.moveFile(bakProjectFile2, bakProjectFile);
+            } catch (IOException ex) {
+                LOG.error("Can't rename file", ex);
+            }
+        }
+        
+        return bakProjectFile;
+    }
+
     @Deprecated
+    @Override
     public void loadState(InputStream in) {
         loadState(in, null);
     }
@@ -744,7 +850,11 @@
         } catch (FileNotFoundException e) {
             LOG.info("Can't load project to stream", e);
         }
-        this.fname = in;
+        if ("bak".equals(FilenameUtils.getExtension(in.getAbsolutePath()))) {
+            this.fname =  null;
+        } else {
+            this.fname = in;
+        }
         notifyObservers(ProjectNotification.AFTER_LOAD_FROM_FILE, in);
     }
 
@@ -819,6 +929,7 @@
         notifyObservers(ProjectNotification.AFTER_LOAD_FROM_STATE, state);
     }
 
+    @Override
     public void saveToState(PersistentState state) throws PersistenceException {
         state.set("version", VERSION);
         state.set("comments", getComments());
@@ -864,14 +975,17 @@
 
     }
 
+    @Override
     public Object getProperty(Object key) {
         return this.propertiesHelper.getProperty(key);
     }
 
+    @Override
     public void setProperty(Object key, Object obj) {
         this.propertiesHelper.setProperty(key, obj);
     }
 
+    @Override
     public Map getExtendedProperties() {
         return this.propertiesHelper.getExtendedProperties();
     }
@@ -1133,25 +1247,30 @@
         throw new UnsupportedOperationException("This method is not supported");
     }
 
+    @Override
     public boolean canImportDocuments(String data, String doctype) {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public String exportDocumentsAsText(List<Document> documents) {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void importDocuments(String data, String doctype) {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public Document getActiveDocument() {
         return this.getActiveDocument((Class<? extends Document>)null);
     }
 
+    @Override
     public Document getActiveDocument(String documentTypeName) {
         ApplicationManager application = ApplicationLocator.getManager();
 
@@ -1187,6 +1306,7 @@
         return null;
     }
 
+    @Override
     public Document getActiveDocument(Class<? extends Document> documentClass) {
         ApplicationManager application = ApplicationLocator.getManager();
 
@@ -1222,14 +1342,17 @@
         return null;
     }
 
+    @Override
     public void addObserver(Observer o) {
         observableHelper.addObserver(o);
     }
 
+    @Override
     public void deleteObserver(Observer o) {
         observableHelper.deleteObserver(o);
     }
 
+    @Override
     public void deleteObservers() {
         observableHelper.deleteObservers();
     }
