
package com.trs.digital.module.manager.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;

import com.xingyuv.http.util.StringUtil;
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.FTPFileFilter;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;

@Resource
public class FTPClientRetried {

	private int connectTimeout = -1;
	private int soTimeout = -1;
	private int dataTimeout = -1;
	private FTPClient client;
	private int retryCount;
	private int reConnectTryCount;

    @Value("${sourcename.ftp1.host}")
    private String host_1;
    @Value("${sourcename.ftp1.ftpuser}")
    private String user_1;
    @Value("${sourcename.ftp1.password}")
    private String pwd_1;



	/** 删除指定的目录，如果发生错误，重试，连续错误数达到重连次数，则重连客户端。 */
	public boolean removeDirectory(String pathname) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				return client.removeDirectory(pathname);
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	/** 删除指定的文件，如果发生错误，重试，连续错误数达到重连次数，则重连客户端。 */
	public boolean deleteFile(String pathname) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				return client.deleteFile(pathname);
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	/** 文件重命名，如果发生错误，重试，连续错误数达到重连次数，则重连客户端。 */
	public boolean rename(String from, String to) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				return client.rename(from, to);
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	public boolean changeWorkingDirectory(String pathname) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				return client.changeWorkingDirectory(pathname);
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	public boolean makeDirectory(String pathname) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				makeDir(pathname);
				return true;
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	private void makeDir(String pathname) throws IOException {
		client.changeWorkingDirectory("/"); //$NON-NLS-1$
		try {
			String[] split = pathname.split("/"); //$NON-NLS-1$
			for (String str : split) {
				if (StringUtil.isEmpty(str)) {
					continue;
				}
				if (!client.changeWorkingDirectory(str)) {
					client.makeDirectory(str);
					client.changeWorkingDirectory(str);
				}
			}
		} finally {
			client.changeWorkingDirectory("/"); //$NON-NLS-1$
		}
	}

	public FTPFile[] listFiles(String pathname) throws IOException {
		return listFiles(pathname, new FTPFileFilter() {

			@Override
			public boolean accept(FTPFile arg0) {
				if (arg0.isDirectory() && (".".equalsIgnoreCase(arg0.getName()) || "..".equalsIgnoreCase(arg0.getName()))) { //$NON-NLS-1$ //$NON-NLS-2$
					return false;
				}
				return true;
			}

		});
	}

	public FTPFile[] listFiles(String pathname, FTPFileFilter filter) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				return client.listFiles(pathname, filter);
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return null;
	}

	public boolean storeFile(String remote, InputStream local) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				boolean ret = client.storeFile(remote, local);
				if (ret) {
					return true;
				} else if (count >= retryCount) {
					throw new IOException(client.getReplyString());
				}
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	public boolean storeUniqueFile(String remote, InputStream local) throws IOException {
		int count = 0;
		while (count < retryCount) {
			count++;
			try {
				boolean ret = client.storeUniqueFile(remote, local);
				if (ret) {
					return true;
				} else if (count >= retryCount) {
					throw new IOException(client.getReplyString());
				}
			} catch (IOException e) {
				if (count >= retryCount) {
					throw e;
				}
				if (count % reConnectTryCount == 0) {
					try {
						client.disconnect();
					} catch (IOException e1) {}
					try {
						connect();
					} catch (IOException e1) {}
				} else {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e1) {}
				}
			}
		}
		return false;
	}

	public boolean retrieveFile(String remote, OutputStream local) throws IOException {
		int retry = 1;
		int reconnect = 0;
		while (true) {
			try {
				boolean ret = client.retrieveFile(remote, local);
				if (ret) {
					return true;
				} else if (retry >= retryCount) {
					throw new IOException(client.getReplyString());
				} else {
					retry++;
					try {
						Thread.sleep(50);
					} catch (InterruptedException ignored) {}
				}
			} catch (IOException e) {
				if (reconnect >= reConnectTryCount) {
					throw e;
				} else {
					reconnect++;
					retry = 1;
					try {
						client.disconnect();
					} catch (IOException ignored) {}
					try {
						connect();
					} catch (IOException ignored) {}
				}
			}
		}
	}

	public void connect() throws IOException {
		client = new FTPClient();
		client.setControlEncoding("UTF-8");
		client.connect(host_1, 21);
		if (false) {
			client.enterLocalPassiveMode();
		}
		if (FTPReply.isPositiveCompletion(client.getReplyCode())) {
			String userName = user_1;
			String password = pwd_1;
			if (StringUtil.isEmpty(userName)) {
				userName = "anonymous"; //$NON-NLS-1$
				password = ""; //$NON-NLS-1$
			}
			if (!client.login(userName, password)) {
				throw new IOException("user name or password is not correct, please check it."); //$NON-NLS-1$
			}
			client.setBufferSize(1024 * 1024);
			client.setFileType(FTP.BINARY_FILE_TYPE);
			if (connectTimeout >= 0) {
				client.setConnectTimeout(connectTimeout);
			}
			if (soTimeout >= 0) {
				client.setSoTimeout(soTimeout);
			}
			if (dataTimeout >= 0) {
				client.setDataTimeout(dataTimeout);
			}
		}
	}

	public boolean isConnected() {
		return client.isConnected();
	}

	public InetAddress getRemoteAddress() {
		return client.getRemoteAddress();
	}

	public int getRemotePort() {
		return client.getRemotePort();
	}

	public void disconnect() throws IOException {
		client.disconnect();
	}

	public String getReplyString() {
		return client.getReplyString();
	}
}
