// jTDS JDBC Driver for Microsoft SQL Server and Sybase
// Copyright (C) 2004 The jTDS Project
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
package net.sourceforge.jtds.jdbc;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.UnknownHostException;

import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbNamedPipe;

/**
 * This class implements inter-process communication (IPC) to the
 * database server using named pipes.
 *
 * @todo Extract abstract base class SharedIpc from <code>SharedSocket</code> and this class.
 * @todo Implement connection timeouts for named pipes.
 *
 * @author David D. Kilzer
 * @version $Id: SharedNamedPipe.java,v 1.19 2007/07/12 20:34:47 bheineman Exp $
 */
public class SharedNamedPipe extends SharedSocket {
    /**
     * The shared named pipe.
     */
    private SmbNamedPipe pipe;

    /**
     * Creates a new instance of <code>SharedNamedPipe</code>.
     *
     * @param connection
     * @throws IOException if the named pipe or its input or output streams do
     *                     not open
     * @throws UnknownHostException if host cannot be found for the named pipe
     */
    public SharedNamedPipe(ConnectionJDBC2 connection) throws IOException {
        super(connection.getBufferDir(), connection.getTdsVersion(), connection.getServerType());

        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(
                connection.getDomainName(), connection.getUser(), connection.getPassword());

        StringBuffer url = new StringBuffer(32);

        url.append("smb://");
        url.append(connection.getServerName());
        url.append("/IPC$");

        final String instanceName = connection.getInstanceName();
        if (instanceName != null && instanceName.length() != 0) {
            url.append("/MSSQL$");
            url.append(instanceName);
        }

        String namedPipePath = DefaultProperties.getNamedPipePath(connection.getServerType());
        url.append(namedPipePath);

        setPipe(new SmbNamedPipe(url.toString(), SmbNamedPipe.PIPE_TYPE_RDWR, auth));

        setOut(new DataOutputStream(getPipe().getNamedPipeOutputStream()));

        final int bufferSize = Support.calculateNamedPipeBufferSize(
                connection.getTdsVersion(), connection.getPacketSize());
        setIn(new DataInputStream(
                new BufferedInputStream(
                        getPipe().getNamedPipeInputStream(), bufferSize)));
    }

    /**
     * Get the connected status of this socket.
     *
     * @return true if the underlying socket is connected
     */
    boolean isConnected() {
        return getPipe() != null;
    }

    /**
     * Close the socket (noop if in shared mode).
     */
    void close() throws IOException {
        super.close();
        getOut().close();
        getIn().close();
        //getPipe().close();
    }

    /**
     * Force close the socket causing any pending reads/writes to fail.
     * <p/>
     * Used by the login timer to abort a login attempt.
     */
    void forceClose() {
        try {
            getOut().close();
        }
        catch (IOException e) {
            // Ignore
        }
        finally {
            setOut(null);
        }

        try {
            getIn().close();
        }
        catch (IOException e) {
            // Ignore
        }
        finally {
            setIn(null);
        }

        setPipe(null);
    }


    /**
     * Getter for {@link SharedNamedPipe#pipe} field.
     *
     * @return {@link SmbNamedPipe} used for communication
     */
    private SmbNamedPipe getPipe() {
        return pipe;
    }


    /**
     * Setter for {@link SharedNamedPipe#pipe} field.
     *
     * @param pipe {@link SmbNamedPipe} to be used for communication
     */
    private void setPipe(SmbNamedPipe pipe) {
        this.pipe = pipe;
    }


    /**
     * Set the socket timeout.
     * <p/>
     * Noop for now; timeouts are not implemented for SMB named pipes.
     *
     * @param timeout timeout value in milliseconds
     */
    protected void setTimeout(int timeout) {
        // FIXME - implement timeout functionality
    }
}
