/*
 * Created on 2005-04-13
 *
 * Part of the Symbian development plug-in for Eclipse
 * Copyright (C) Mikołaj Zalewski, 2005
 */
package pl.zalewski.mikolaj.symbdev.properties;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Properties;
import java.util.WeakHashMap;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;

import pl.zalewski.mikolaj.symbdev.SymbdevPlugin;

/**
 * <p>Access to the .symbbuild file in the project root folder which
 * contains the Symbian build-specific information which should be
 * copyed when e.g. exporting the project to a repository</p>
 * 
 * <p>This class is thread-safe</p> 
 * 
 * @author mikolaj
 */
public class SymbianPropertiesFile {

    public static final String BUILD_FILE_NAME=".symbbuild";
    
    static public synchronized SymbianPropertiesFile getForProject(IProject project)
    	throws CoreException
    {
        SymbianPropertiesFile file=(SymbianPropertiesFile)fProjectHash.get(project);
        if (file!=null)
            return file;
        file=new SymbianPropertiesFile(project);
        fProjectHash.put(project, file);
        return file;
    }
    
    protected SymbianPropertiesFile(IProject project)
    	throws CoreException
    {
        fProperties=new Properties();
        fBuildFile=project.getFile(BUILD_FILE_NAME);
        if (fBuildFile.exists()) {
            InputStream in=fBuildFile.getContents(true);
            try {
                fProperties.load(in);
            }
            catch (IOException e) {
                throw new CoreException(SymbdevPlugin
                        .createErrorStatus(SymbdevPlugin.ERROR_IO_ACCESS,
                                "Error accessing "+BUILD_FILE_NAME+" file"));
            }
        }
    }
    
    public synchronized String getProperty(String key, String defaultValue) {
        return fProperties.getProperty(key, defaultValue);
    }
    
    /**
     * Removes the property from the file
     * @param key The key
     * @return <code>true</code> if the key existed in the file
     */
    public synchronized boolean removeProperty(String key) {
        boolean ret=(fProperties.remove(key)!=null);
        setSavePending();
        return ret;
    }
    
    public String getProperty(String key) {
        return getProperty(key, null);
    }
    
    public String[] getProperties(String prefix) {
        LinkedList ret=new LinkedList();
        synchronized (this) {        
            Enumeration e=fProperties.propertyNames();
            while (e.hasMoreElements()) {
                String prop=(String)e.nextElement();
                if (prop.startsWith(prefix))
                    ret.add(prop);
            }
        }
        return (String[])ret.toArray(new String[ret.size()]);
    }

    public String[] getSubProperties(String prefix) {
        HashSet set=new HashSet();
        if (!prefix.endsWith("."))
            prefix=prefix+".";
        synchronized (this) {        
            Enumeration e=fProperties.propertyNames();
            while (e.hasMoreElements()) {
                String prop=(String)e.nextElement();
                if (prop.startsWith(prefix)) {
                    int end=prop.indexOf('.', prefix.length());
                    if (end==-1)
                        end=prop.length();
                    String element=prop.substring(prefix.length(), end);
                    set.add(element);
                }
            }
        }
        return (String[])set.toArray(new String[set.size()]);
    }
    
    public synchronized void setProperty(String key, String value) {
        fProperties.setProperty(key, value);
        setSavePending();
    }
    
    protected void setSavePending() {
        if (fUpdateWaiting)
            return;
        
        fUpdateWaiting=true;
        SymbdevPlugin.getStandardDisplay().asyncExec(
                new Runnable() {
                    public void run() {
                        storeProperties();
                    }
                });        
    }
        
    /**
     * This method is executed in the SWT thread.
     */
    protected void storeProperties()
    {
        CoreException ce=null;
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        synchronized (this) {
	        try  {
		        fProperties.store(out, "This file contains the Symbian " +
		        		"build-specific information which should be copied " +
		        		"when e.g. exporting the project to a repository");
	        }
	        catch (IOException e) {
	            ce=new CoreException(SymbdevPlugin.createErrorStatus(SymbdevPlugin.ERROR_IO_ACCESS,
	                    "Error storing the preferences file to memory", e));
	        }
	        finally {
		        fUpdateWaiting=false;            
	        }
        }
	        
        if (ce==null) {
	        InputStream in=new ByteArrayInputStream(out.toByteArray());
	        try {
	            if (fBuildFile.exists())
	                fBuildFile.setContents(in, true, true, null);
	            	else fBuildFile.create(in, true, null);
	        }
	        catch (CoreException e) {
	            ce=e;
	        }
        }
        
        if (ce!=null)
            SymbdevPlugin.showError(ce, "Error storing "+BUILD_FILE_NAME+" file", null);
    }
    
    static WeakHashMap fProjectHash=new WeakHashMap();
    Properties fProperties;
    boolean fUpdateWaiting;
    IFile fBuildFile;
}
