/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.ftpserver.impl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;

import org.apache.ftpserver.ftplet.DataConnection;
import org.apache.ftpserver.ftplet.DataType;
import org.apache.ftpserver.ftplet.FtpSession;
import org.apache.ftpserver.usermanager.impl.TransferRateRequest;
import org.apache.ftpserver.util.IoUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <strong>Internal class, do not use directly.</strong>
 * 
 * An active open data connection, used for transfering data over the data
 * connection.
 *
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
 */
public class IODataConnection implements DataConnection {

    private final Logger LOG = LoggerFactory
    .getLogger(IODataConnection.class);

    
    private static final byte[] EOL = System.getProperty("line.separator").getBytes();
    
    private final FtpIoSession session;

    private final Socket socket;

    private final ServerDataConnectionFactory factory;

    public IODataConnection(final Socket socket, final FtpIoSession session,
            final ServerDataConnectionFactory factory) {
        this.session = session;
        this.socket = socket;
        this.factory = factory;
    }

    /**
     * Get data input stream. The return value will never be null.
     */
    private InputStream getDataInputStream() throws IOException {
        try {

            // get data socket
            Socket dataSoc = socket;
            if (dataSoc == null) {
                throw new IOException("Cannot open data connection.");
            }

            // create input stream
            InputStream is = dataSoc.getInputStream();
            if (factory.isZipMode()) {
                is = new InflaterInputStream(is);
            }
            return is;
        } catch (IOException ex) {
            factory.closeDataConnection();
            throw ex;
        }
    }

    /**
     * Get data output stream. The return value will never be null.
     */
    private OutputStream getDataOutputStream() throws IOException {
        try {

            // get data socket
            Socket dataSoc = socket;
            if (dataSoc == null) {
                throw new IOException("Cannot open data connection.");
            }

            // create output stream
            OutputStream os = dataSoc.getOutputStream();
            if (factory.isZipMode()) {
                os = new DeflaterOutputStream(os);
            }
            return os;
        } catch (IOException ex) {
            factory.closeDataConnection();
            throw ex;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.apache.ftpserver.FtpDataConnection2#transferFromClient(java.io.
     * OutputStream)
     */
    public final long transferFromClient(FtpSession session,
            final OutputStream out) throws IOException {
        TransferRateRequest transferRateRequest = new TransferRateRequest();
        transferRateRequest = (TransferRateRequest) session.getUser()
                .authorize(transferRateRequest);
        int maxRate = 0;
        if (transferRateRequest != null) {
            maxRate = transferRateRequest.getMaxUploadRate();
        }

        InputStream is = getDataInputStream();
        try {
            return transfer(session, false, is, out, maxRate);
        } finally {
            IoUtils.close(is);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.io.InputStream
     * )
     */
    public final long transferToClient(FtpSession session, final InputStream in)
            throws IOException {
        TransferRateRequest transferRateRequest = new TransferRateRequest();
        transferRateRequest = (TransferRateRequest) session.getUser()
                .authorize(transferRateRequest);
        int maxRate = 0;
        if (transferRateRequest != null) {
            maxRate = transferRateRequest.getMaxDownloadRate();
        }

        OutputStream out = getDataOutputStream();
        try {
            return transfer(session, true, in, out, maxRate);
        } finally {
            IoUtils.close(out);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.lang.String
     * )
     */
    public final void transferToClient(FtpSession session, final String str)
            throws IOException {
        OutputStream out = getDataOutputStream();
        Writer writer = null;
        try {
            writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            writer.write(str);

            // update session
            if (session instanceof DefaultFtpSession) {
                ((DefaultFtpSession) session).increaseWrittenDataBytes(str
                        .getBytes(StandardCharsets.UTF_8).length);
            }
        } finally {
            if (writer != null) {
                writer.flush();
            }
            IoUtils.close(writer);
        }

    }

    private final long transfer(FtpSession session, boolean isWrite,
            final InputStream in, final OutputStream out, final int maxRate)
            throws IOException {
        long transferredSize = 0L;

        boolean isAscii = session.getDataType() == DataType.ASCII;
        long startTime = System.currentTimeMillis();
        byte[] buff = new byte[4096];

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = IoUtils.getBufferedInputStream(in);

            bos = IoUtils.getBufferedOutputStream(out);

            DefaultFtpSession defaultFtpSession = null;
            if (session instanceof DefaultFtpSession) {
                defaultFtpSession = (DefaultFtpSession) session;
            }

            byte lastByte = 0;
            while (true) {

                // if current rate exceeds the max rate, sleep for 50ms
                // and again check the current transfer rate
                if (maxRate > 0) {

                    // prevent "divide by zero" exception
                    long interval = System.currentTimeMillis() - startTime;
                    if (interval == 0) {
                        interval = 1;
                    }

                    // check current rate
                    long currRate = (transferredSize * 1000L) / interval;
                    if (currRate > maxRate) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException ex) {
                            break;
                        }
                        continue;
                    }
                }

                // read data
                int count = bis.read(buff);

                if (count == -1) {
                    break;
                }

                // update MINA session
                if (defaultFtpSession != null) {
                    if (isWrite) {
                        defaultFtpSession.increaseWrittenDataBytes(count);
                    } else {
                        defaultFtpSession.increaseReadDataBytes(count);
                    }
                }

                // write data
                // if ascii, replace \n by \r\n
                if (isAscii) {
                    for (int i = 0; i < count; ++i) {
                        byte b = buff[i];
                        if(isWrite) {
                            if (b == '\n' && lastByte != '\r') {
                                bos.write('\r');
                            }
    
                            bos.write(b);
                        } else {
                            if(b == '\n') {
                                // for reads, we should always get \r\n
                                // so what we do here is to ignore \n bytes 
                                // and on \r dump the system local line ending.
                                // Some clients won't transform new lines into \r\n so we make sure we don't delete new lines
                                if (lastByte != '\r'){
                                    bos.write(EOL);
                                }
                            } else if(b == '\r') {
                                bos.write(EOL);
                            } else {
                                // not a line ending, just output
                                bos.write(b);
                            }
                        }
                        // store this byte so that we can compare it for line endings
                        lastByte = b;
                    }
                } else {
                    bos.write(buff, 0, count);
                }

                transferredSize += count;

                notifyObserver();
            }
        } catch(IOException e) {
            LOG.warn("Exception during data transfer, closing data connection socket", e);
            factory.closeDataConnection();
            throw e;
        } catch(RuntimeException e) {
            LOG.warn("Exception during data transfer, closing data connection socket", e);
            factory.closeDataConnection();
            throw e;
        } finally {
            if (bos != null) {
                bos.flush();
            }
        }

        return transferredSize;
    }

    /**
     * Notify connection manager observer.
     */
    protected void notifyObserver() {
        session.updateLastAccessTime();

        // TODO this has been moved from AbstractConnection, do we need to keep
        // it?
        // serverContext.getConnectionManager().updateConnection(this);
    }
}
