/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2002-2006, Geotools Project Managment Committee (PMC)
 *
 *    This library 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 2.1 of the License, or (at your option) any later version.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 */
package org.geotools.data.ogr;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.gdal.ogr.DataSource;
import org.gdal.ogr.Driver;
import org.gdal.ogr.ogr;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.data.FileDataStoreFactorySpi;


/**
 * Implementation of the DataStore service provider interface for OGR.
 *
 * @author Andrea Aime, TOPP
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/ogr/src/main/java/org/geotools/data/ogr/OGRDataStoreFactory.java $
 * @version $Id: OGRDataStoreFactory.java 25075 2007-04-09 19:20:46Z desruisseaux $
 */
public class OGRDataStoreFactory
    implements DataStoreFactorySpi {
    public static final Param OGR_NAME = new Param("OGRName", String.class,
        "Name of the file, or data source to try and open", true);
    
    public static final Param OGR_DRIVER_NAME = new Param("OGRDriverName", String.class,
    "Name of the OGR driver to be used. Required to create a new data source, optional when opening an existing one", false);
    
    public static final Param NAMESPACEP = new Param("namespace", URI.class,
    "uri to a the namespace",false); //not required
    
    static {
		// perform OGR format registration once
		if(ogr.GetDriverCount() == 0)
			ogr.RegisterAll();
	}
    
    /** 
     * Caches opened data stores. 
     * TODO: is this beneficial or problematic? It's a static cache, so opening a lot of
     * datastore (thousands, hundreds of thousands...) may become a memory problem.
     * Plus OGR is not designed to be thread safe.
     */
    private Map liveStores=new HashMap();
    
    public boolean canProcess(Map params) {
        boolean accept = false;
        String ogrName = null;
        String ogrDriver = null;
        try {
            ogrName = (String) OGR_NAME.lookUp(params);
        } catch (IOException ioe) {
            // yes, I am eating this
        }
        try {
            ogrDriver = (String) OGR_DRIVER_NAME.lookUp(params);
        } catch (IOException ioe) {
            // yes, I am eating this
        }
        
        accept = canProcess(ogrName, ogrDriver);
        return accept;
    }

    public DataStore createDataStore(Map params) throws IOException {
    	DataStore ds = null;
    	if ( !liveStores.containsKey(params) ){
	
	        URL url = null;
	        try {
	        	ds=createNewDataStore(params);
	            liveStores.put(params,ds);
	        } catch (MalformedURLException mue) {
	            throw new DataSourceException("Unable to attatch datastore to "
	                + url, mue);
	        } 
    	}else
    		ds=(DataStore) liveStores.get(params);
        return ds;
    }

    /**
     * Not implemented yet.
     *
     * @param params
     *
     * @throws IOException 
     *
     * @throws IOException DOCUMENT ME!
     * @throws UnsupportedOperationException
     */
    public DataStore createNewDataStore(Map params) throws IOException{

        DataStore ds = null;
       
    	String ogrName = (String) OGR_NAME.lookUp(params);
        String ogrDriver = (String) OGR_DRIVER_NAME.lookUp(params);
        URI namespace = (URI) NAMESPACEP.lookUp(params);  
        ds = new OGRDataStore(ogrName, ogrDriver, namespace);
 
        return ds;
    }

    public String getDisplayName() {
        return "Shapefile";
    }
    /**
     * Describes the type of data the datastore returned by this factory works
     * with.
     *
     * @return String a human readable description of the type of restore
     *         supported by this datastore.
     */
    public String getDescription() {
        return "ESRI(tm) Shapefiles (*.shp)";
    }

//    public DataSourceMetadataEnity createMetadata( Map params )
//            throws IOException {
//        
//        URL url = (URL) URLP.lookUp(params);
//        Boolean mm = (Boolean) MEMORY_MAPPED.lookUp(params);
//        
//        String server;
//        String name;
//        if( url.getProtocol().equals("file")){
//            server = "localhost";
//            name = url.getPath();
//        }
//        else {
//            server = url.getHost()+":"+url.getPort();
//            name = url.getFile();
//        }
//        return new DataSourceMetadataEnity( server, name, "Shapefile access for "+url );
//    }
    /**
     * Test to see if this datastore is available, if it has all the
     * appropriate libraries to construct a datastore.  This datastore just
     * returns true for now.
     *
     * @return <tt>true</tt> if and only if this factory is available to create
     *         DataStores.
     *
     * @task REVISIT: I'm just adding this method to compile, maintainer should
     *       revisit to check for any libraries that may be necessary for
     *       datastore creations.
     */
    public boolean isAvailable() {
        return true;
    }

    /**
     * Describe parameters.
     *
     *
     * @see org.geotools.data.DataStoreFactorySpi#getParametersInfo()
     */
    public Param[] getParametersInfo() {
        return new Param[] { OGR_NAME};
    }

    /**
     * @see org.geotools.data.dir.FileDataStoreFactorySpi#getFileExtensions()
     */
    public String[] getFileExtensions() {
        return new String[] {".shp",};
    }

    /**
     * Assume we can process an ogrName if the ogrName exists and can be opened, or if
     * the specified driver does exist.
     * @param ogrName
     * @param driver
     * @return
     */
    public boolean canProcess(String ogrName, String driver) {
        DataSource ds =  ogr.OpenShared(ogrName, OGRDataStore.FALSE);
        if(ds != null) {
        	ds.delete();
        	return true;
        }
        
        Driver dr = ogr.GetDriverByName(driver);
        if(dr != null) {
        	dr.delete();
        	return true;
        }
        
        return false;
        
    }

	public Map getImplementationHints() {
		return Collections.EMPTY_MAP;
	}


    


}
