/* JFox, the OpenSource J2EE Application Server
 *
 * Distributable under GNU LGPL license by gun.org
 * more details please visit http://www.huihoo.org/jfox
 */

package org.jfox.jdbc.xa;

import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.XAConnection;
import javax.sql.XADataSource;

/**
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public abstract class AbstractXADataSource implements XADataSource {
    protected XADataSource xads = null;

    private String url;

    public AbstractXADataSource(String url) {
        this.url = url;
        xads = init(url);
    }

    /**
     * build the really xa datasource
     *
     * @param url
     * @return
     */
    protected abstract XADataSource init(String url);

    public String getUrl() {
        return url;
    }

    public int getLoginTimeout() throws SQLException {
        return xads.getLoginTimeout();
    }

    public void setLoginTimeout(int seconds) throws SQLException {
        xads.setLoginTimeout(seconds);
    }

    public PrintWriter getLogWriter() throws SQLException {
        return xads.getLogWriter();
    }

    public void setLogWriter(PrintWriter out) throws SQLException {
        xads.setLogWriter(out);
    }

    public XAConnection getXAConnection() throws SQLException {
        return xads.getXAConnection();
    }

    public XAConnection getXAConnection(String user, String password) throws SQLException {
        return xads.getXAConnection(user, password);
    }


    public void setUrl(XADataSource xads, String url) throws Exception {
        xads.getClass().getMethod("setURL", new Class[]{String.class})
                .invoke(xads, new Object[]{url});
    }

    protected static URLProperties parseSqlURL(String url) {
        // url example: jdbc:microsoft:sqlserver://localhost:1433;user=x;password=y;databaseName=db;
        int biasIndex = url.indexOf("://");
        int semicolonIndex = url.indexOf(";");

        String serverNameAndPortNumber = url.substring(biasIndex + 3, semicolonIndex);
        String urlProperties = url.substring(semicolonIndex + 1);

        URLProperties urlProp = new URLProperties();
        parseSqlServerNameAndPort(serverNameAndPortNumber, urlProp);
        parseSqlProperties(urlProperties, urlProp);
        return urlProp;
    }

    protected static void parseSqlProperties(String urlProperties, URLProperties urlProp) {
        int pre_semicolonIndex = -1;
        int post_semicolonIndex = pre_semicolonIndex;
        while((post_semicolonIndex = urlProperties.indexOf(";", pre_semicolonIndex + 1)) > 0) {
            String kv = urlProperties.substring(pre_semicolonIndex + 1, post_semicolonIndex);
            int equalsIndex = kv.indexOf("=");
            if(equalsIndex > 0) {
                urlProp.setProperty(kv.substring(0, equalsIndex).trim(), kv.substring(equalsIndex + 1).trim());
            }
            pre_semicolonIndex = post_semicolonIndex;
        }
        if(pre_semicolonIndex + 1 != urlProperties.length()) {
            String kv = urlProperties.substring(pre_semicolonIndex + 1);
            int equalsIndex = kv.indexOf("=");
            if(equalsIndex > 0) {
                urlProp.setProperty(kv.substring(0, equalsIndex).trim(), kv.substring(equalsIndex + 1).trim());
            }
        }
    }

    protected static void parseSqlServerNameAndPort(String serverNameAndPortNumber, URLProperties urlProp) {
        int colonIndex = serverNameAndPortNumber.indexOf(":");
        if(colonIndex > 0) {
            urlProp.setProperty("serverName", serverNameAndPortNumber.substring(0, colonIndex));
            urlProp.setProperty("portNumber", serverNameAndPortNumber.substring(colonIndex + 1));
        }
        else {
            urlProp.setProperty("serverName", serverNameAndPortNumber);
        }
    }

    static protected class URLProperties {
        private Properties prop = new Properties();

        public String getProperty(String key) {
            return prop.getProperty(key.toUpperCase());
        }

        public synchronized Object setProperty(String key, String value) {
            Object old = prop.getProperty(key.toUpperCase());
            prop.setProperty(key.toUpperCase(), value);
            return old;
        }

        public synchronized boolean containsKey(Object key) {
            return prop.containsKey(((String) key).toUpperCase());
        }
    }

    public static void main(String[] args) {

    }
}

