package kr.co.icontrols.ilp300_700.ftp;

import android.util.Log;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class HDCSFTPManager {

    String TAG = "HDCSFTPManager";

    boolean bLOG = true;   // true, false
    private void LOG(String log) {
        if (bLOG) Log.v(TAG, log);
    }
    boolean bLOG_DEBUG = false;   // true, false
    private void LOG_DEBUG(String log) {
        if (bLOG_DEBUG) Log.d(TAG, log);
    }
    boolean bLOG_INFO = true;   // true, false
    private void LOG_INFO(String log) {
        if (bLOG_INFO) {
            Log.d(TAG, log);
            //LogUtil.Log("", "HDCFTPManager API - " + log);
        }
    }

    FTPClient mFTPClient;
    FTPSClient mFTPSClient;

    public String ENCODING_TYPE_EUC_KR = "euc-kr";
    public String ENCODING_TYPE_UTF_8 = "utf-8";
    public int RECEIVE_BUFFERSIZE = 1024 * 512;

    boolean bFTPSUsage = true;   // true : FTPS, false : FTP

    /**
     * Declare a FTP client
     * Initiates the FTP client, as bFTPSUsage.
     */
    public HDCSFTPManager() {
        Log.d(TAG, "[HDCFTPManager] bFTPSUsage [" + bFTPSUsage+ "]");
        if (bFTPSUsage) mFTPSClient = new FTPSClient();
        else mFTPClient = new FTPClient();
    }

    /**
     * Connect the TFP server
     *
     * @param TargetIP - (String) IP address of FTP or FTP server (ex. 10.0.1.1)
     * @return (boolean) FTP server connecting result
     */
    public boolean connectFTP(String TargetIP) {
        try {
            if (bFTPSUsage)
            {
                if(mFTPSClient!=null) {
                    //mFTPSClient.connect(TargetIP, 20219);
                    mFTPSClient.connect(TargetIP, 2121);
                    mFTPSClient.execPBSZ (0);
                    mFTPSClient.execPROT("P");
                    //mFTPSClient.execPROT("C");
                }
            }
            else
            {
                if(mFTPClient!=null)
                    mFTPClient.connect(TargetIP);
            }
            LOG_INFO("[connectFTP] Connected to [" + TargetIP + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, "" + re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] connectFTP(TargetIP)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    /**
     * Check FTP server connection status
     *
     * @return (boolean) Connection status (true : connected, false : disconnected)
     */
    public boolean isFTPConnected() {
        try {
            if (bFTPSUsage) return mFTPSClient.isConnected();
            return mFTPClient.isConnected();
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] isFTPConnected()");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean changeWorkingDirectory(String path)
    {
        boolean result = false;
        try {
            if (bFTPSUsage) {
                if(mFTPSClient!=null)
                    result =  mFTPSClient.changeWorkingDirectory(path);
                LOG_INFO("[changeWorkingDirectory]  : [" +path + "]");
            }
            else {
                if(mFTPClient!=null)
                    result = mFTPClient.changeWorkingDirectory(path);
                LOG_INFO("[changeWorkingDirectory] : [" +path + "]");
            }
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);

        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] loginFTP(ID, PW)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
        }

        return result;
    }

    /**
     * Login the FTP server
     *
     * @param ID - (String) Account ID
     * @param PW - (String) Account Password
     * @return (boolean) Login result (true : success, false : failure)
     */
    public boolean loginFTP(String ID, String PW) {
        try {
            boolean bResult = false;
            if (bFTPSUsage) {
                for(int i =0; i< 1; i++) {
                    if(mFTPSClient!=null)
                        bResult = mFTPSClient.login(ID, PW);
                }
                LOG_INFO("[loginFTP] logged FTPS Server in : [" +bResult + "]");
            }
            else {
                for(int i =0; i< 1; i++) {
                    if(mFTPClient!=null)
                        bResult = mFTPClient.login(ID, PW);
                }
                LOG_INFO("[loginFTP] logged FTP Server in : [" +bResult + "]");
            }
            return bResult;
        } catch (RuntimeException re) {
            LOG_INFO("[loginFTP] LoginFaeil : [" +re.toString() + "]");
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] loginFTP(ID, PW)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    /**
     * Logout the FTP server
     *
     * @return (boolean) Logout result (true : success, false : failure)
     */
    public boolean logoutFTP() {
        try {
            boolean bResult = false;
            if (bFTPSUsage) {
                if (mFTPSClient!=null && mFTPSClient.isConnected()) {
                    bResult = mFTPSClient.logout();
                }
                else {
                    LOG_INFO("[logoutFTP] FTPS is not connected!!");
                }
            }
            else {
                if (mFTPSClient!=null && mFTPClient.isConnected()) {
                    bResult = mFTPClient.logout();
                }
                else {
                    LOG_INFO("[logoutFTP] FTP is not connected!!");
                }
            }
            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] logoutFTP()");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    /**
     * Disconnect the FTP server
     *
     * @return (boolean) Logout result (true : success, false : failure)
     */
    public boolean disconnectFTP() {
        try {
            if (bFTPSUsage) {
                mFTPClient.disconnect();
                LOG_INFO("[disconnectFTP] Disconnected FTPS");
            }
            else {
                mFTPClient.disconnect();
                LOG_INFO("[disconnectFTP] Disconnected FTP");
            }
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] disconnectFTP()");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    /**
     * Download a file from FTP server
     *
     * @param remoteFilepath - (String) Uri of file to download from the FTP server
     * @param localFilePath - (String) Uri of files to be stored on the device
     * @return (boolean) Download result (true : success, false : failure)
     */
    public boolean downloadFile(String remoteFilepath, String localFilePath) {
        try {
            LOG_INFO("[downloadFile] remoteFilepath [" + remoteFilepath + "], localFilePath [" + localFilePath + "]");
            boolean bResult = false;
            File mFile = new File(localFilePath);
            if (mFile.exists()) {
                LOG_INFO("[downloadFile] [" + localFilePath + "] is exist!!");
                if (FileDelete(mFile)) {
                    LOG_INFO("[downloadFile] [" + localFilePath + "] is deleted!!");
                }
                else {
                    LOG_INFO("[downloadFile] Fail to delete [" + localFilePath + "]");
                    return false;
                }
            }
            FileOutputStream FileOutStm = new FileOutputStream(mFile);
            BufferedOutputStream BufferedOutStm = new BufferedOutputStream(FileOutStm);
            if (bFTPSUsage) bResult = mFTPSClient.retrieveFile(remoteFilepath, BufferedOutStm);
            else bResult = mFTPClient.retrieveFile(remoteFilepath, BufferedOutStm);
            BufferedOutStm.flush();
            FileOutStm.flush();
            BufferedOutStm.close();
            FileOutStm.close();
            LOG_INFO("[downloadFile] bResult [" +bResult + "]");

            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] downloadFile(remoteFilepath, localFilePath)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            deleteFile(localFilePath);
            return false;
        }
    }

    public boolean retrieveFile(String remoteFilepath, OutputStream outputstream)
    {
        boolean bResult = false;

        try
        {
            if (bFTPSUsage) bResult = mFTPSClient.retrieveFile(remoteFilepath, outputstream);
            else bResult = mFTPClient.retrieveFile(remoteFilepath, outputstream);
            LOG_INFO("[retrieveFile] bResult [" +bResult + "]");

        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);

        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] retrieveFile(remoteFilepath, outputstream)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);

        }
        finally {

        }
        return  bResult;
    }


    public String getError()
    {
        return mFTPSClient.getReplyString();
    }

    public void logout()
    {
        try
        {
            if (bFTPSUsage) mFTPSClient.logout();
            else mFTPClient.logout();
            LOG_INFO("[logout]");

        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);

        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] logout()");
            Log.e(TAG, ""+e);
        }
    }


    public void quit()
    {
        try
        {
            if(mFTPClient!=null)
            {
                if (bFTPSUsage) mFTPSClient.quit();
                else mFTPClient.quit();
                LOG_INFO("[quit]");
            }
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);

        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] quit()");
            Log.e(TAG, ""+e);
        }
    }

    /**
     * Upload a file to FTP server
     *
     * @param remoteFilepath - (String) Uri of files uploaded to the FTP server
     * @param localFilePath - (String) Uri of file to upload to the FTP server
     * @return (boolean) Download result (true : success, false : failure)
     */
    public boolean uploadFile(String remoteFilepath, String localFilePath) {
        FileInputStream FileInStm = null;
        try {
            boolean bResult = false;
            File mFile = new File(localFilePath);
            if (!mFile.exists()) {
                LOG_INFO("[uploadFile] No FILE!! [" +localFilePath + "]");
                return false;
            }
            FileInStm = new FileInputStream(mFile);
            if (bFTPSUsage) bResult = mFTPSClient.storeFile(remoteFilepath, FileInStm);
            else bResult = mFTPClient.storeFile(remoteFilepath, FileInStm);
            LOG_INFO("[uploadFile] bResult [" +bResult + "]");
            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] uploadFile(remoteFilepath, localFilePath)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
        finally {
            if(FileInStm!=null) {
                try {
                    FileInStm.close();
                } catch (IOException e) {
                    Log.e(TAG, ""+e);//e.printStackTrace();
                }
                FileInStm = null;
            }
        }
    }

    /**
     * Check existence of the file on the device
     *
     * @param Filepath - (String) Uri of file to check existence
     * @return (boolean) result (true : existence, false : non-existence)
     */
    public boolean isFileexist(String Filepath) {
        try {
            boolean bResult = false;
            File mFile = new File(Filepath);
            bResult = mFile.exists();
            LOG_INFO("[isFileexist] bResult [" +bResult + "]");
            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] isFileexist(Filepath)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    /**
     * Delete a file
     *
     * @param Filepath - (String) uir of file to delete on the device
     * @return (boolean) result (true : existence, false : non-existence)
     */
    public boolean deleteFile(String Filepath) {
        try {
            boolean bResult = false;
            File mFile = new File(Filepath);
            if (mFile.exists()) {
                bResult =  FileDelete(mFile);// mFile.delete();
            }
            else {
                LOG_INFO("[deleteFile] There is no file = " +Filepath);
            }
            LOG_INFO("[deleteFile] bResult [" +bResult + "]");
            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] deleteFile(Filepath)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setReceieveDataSocketBufferSize(int BufferSize) {
        try {
            if (bFTPSUsage) mFTPSClient.setReceieveDataSocketBufferSize(BufferSize);
            else mFTPClient.setReceieveDataSocketBufferSize(BufferSize);
            LOG_INFO("[setReceieveDataSocketBufferSize] BufferSize [" + BufferSize + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setReceieveDataSocketBufferSize(BufferSize)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public int getReceiveDataSocketBufferSize()
    {
        int return_size = 0;
        try {
            if (bFTPSUsage)
            {
                return_size = mFTPSClient.getReceiveDataSocketBufferSize();
            }
            else
            {
                return_size =  mFTPClient.getReceiveDataSocketBufferSize();
            }
            LOG_INFO("[ReceiveDataSocketBufferSize] BufferSize [" + return_size + "]");

        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);

        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] ReceiveDataSocketBufferSize()");
            //e.printStackTrace();
            Log.e(TAG, ""+e);

        }
        return return_size;
    }


    public boolean setReceiveBufferSize(int BufferSize) {
        try {
            if (bFTPSUsage) mFTPSClient.setReceiveBufferSize(BufferSize);
            else mFTPClient.setReceiveBufferSize(BufferSize);
            LOG_INFO("[setReceiveBufferSize] BufferSize [" + BufferSize + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setReceiveBufferSize(BufferSize)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setCtrlEncoding(String Encode) {
        try {
            if (bFTPSUsage) {
                mFTPSClient.setControlEncoding(Encode);
                LOG_INFO("[setCtrlEncoding1] setControlEncoding [" + Encode + "]");
                return true;
                /*if (mFTPSClient.isConnected()) {
                    mFTPSClient.setControlEncoding(Encode);
                    LOG_INFO("[setCtrlEncoding1] setControlEncoding [" + Encode + "]");
                    return true;
                }
                else {
                    LOG_INFO("[setFTPEnvironment1] Not connected!!");
                    return false;
                }*/
            }
            else {
                if (mFTPClient.isConnected()) {
                    mFTPClient.setControlEncoding(Encode);
                    LOG_INFO("[setCtrlEncoding] setControlEncoding [" + Encode + "]");
                    return true;
                }
                else {
                    LOG_INFO("[setFTPEnvironment] Not connected!!");
                    return false;
                }
            }
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setCtrlEncoding(Encode)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setFileType(int FileType) {
        try {
            boolean bResult = false;
            if (bFTPSUsage) bResult = mFTPSClient.setFileType(FileType);
            else bResult = mFTPClient.setFileType(FileType);
            LOG_INFO("[setFileType] bResult [" +bResult + "]");
            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setFileType(FileType)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setPassiveMode() {
        try {
            if (bFTPSUsage) mFTPSClient.enterLocalPassiveMode();
            else mFTPClient.enterLocalPassiveMode();
            LOG_INFO("[setPassiveMode] Set LocalPassiveMode!!");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setPassiveMode()");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setActiveMode() {
        try {
            if (bFTPSUsage) mFTPSClient.enterLocalActiveMode();
            else mFTPClient.enterLocalActiveMode();
            LOG_INFO("[setPassiveMode] Set LocalActiveMode!!");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setActiveMode()");
            Log.e(TAG, ""+e);//e.printStackTrace();
            return false;
        }
    }

    public boolean setFileTransferMode(int Mode) {
        try {
            boolean bResult = false;
            if (bFTPSUsage) bResult = mFTPSClient.setFileTransferMode(Mode);
            else bResult = mFTPClient.setFileTransferMode(Mode);
            LOG_INFO("[setFileTransferMode] bResult [" +bResult + "]");
            return bResult;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setFileTransferMode(Mode)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setDefaultTimeout(int mSec) {
        try {
            if (bFTPSUsage) mFTPSClient.setDefaultTimeout(mSec);
            else mFTPClient.setDefaultTimeout(mSec);
            LOG_INFO("[setDefaultTimeout] Set Timeout [" + mSec + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setDefaultTimeout(Sec)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setConnectTimeout(int mSec) {
        try {
            if (bFTPSUsage) mFTPSClient.setConnectTimeout(mSec);
            else mFTPClient.setConnectTimeout(mSec);
            LOG_INFO("[setConnectTimeout] Set Timeout [" + mSec + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setConnectTimeout(Sec)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setSoTimeout(int mSec) {
        try {
            if (bFTPSUsage) mFTPSClient.setSoTimeout(mSec);
            else mFTPClient.setSoTimeout(mSec);
            LOG_INFO("[setSoTimeout] Set Timeout [" + mSec + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setSoTimeout(Sec)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    public boolean setDataTimeout(int mSec) {
        try {
            if (bFTPSUsage) mFTPSClient.setDataTimeout(mSec);
            else mFTPClient.setDataTimeout(mSec);
            LOG_INFO("[setDataTimeout] Set Timeout [" + mSec + "]");
            return true;
        } catch (RuntimeException re) {
            Log.e(TAG, ""+re);
            return false;
        }
        catch (Exception e) {
            Log.e(TAG, "[Exception] setDataTimeout(Sec)");
            //e.printStackTrace();
            Log.e(TAG, ""+e);
            return false;
        }
    }

    private synchronized boolean FileDelete(File file)
    {
        boolean result = false;
        if(file!=null && file.exists())
        {
            result = file.delete();
        }
        return result;
    }

}
