package cn.stylefeng.guns.zjxlUtil;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;

import cn.stylefeng.guns.zjxlUtil.FastDFSClientPool;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.ProtoCommon;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * FastDFS 客户端工具.
 *
 * @author szx
 */
public class FastDFSUtil {
    public final static String GroupField = "groupName";
    public final static String RemoteFileField = "remoteFileName";
    public final static String FileIdField = "fid";
    public final static String FileUrlField = "fileUrl";

    //    static TrackerClient tracker;
//    static TrackerServer trackerServer;
//    static StorageServer storageServer;
//    static StorageClient client;
//
//    static {
//        try {
//            XEnvironmentOption environmentOption = ServiceFactory.getService(Services.EnvironmentOption);
//            String basePath = FastDFSUtil.class.getResource("/").getPath();
//            String configFile = basePath + environmentOption.getOption(EnvironmentOptions.FastDFSConfig);
//
//            ClientGlobal.init(configFile);
//
//            tracker = new TrackerClient();
//            trackerServer = tracker.getConnection();
//            storageServer = null;
//            client = new StorageClient(trackerServer, storageServer);
//        } catch (FileNotFoundException e) {
//            LogService.getLogger(FastDFSUtil.class).fatal("FastDFS配置文件打开失败: " + e.getMessage());
//        } catch (IOException e) {
//            LogService.getLogger(FastDFSUtil.class).fatal("FastDFS初始化失败: " + e.getMessage());
//        } catch (MyException e) {
//            LogService.getLogger(FastDFSUtil.class).fatal("FastDFS初始化失败: " + e.getMessage());
//        }
//    }

    final static int BUFFER_SIZE = 4096;

    /**
     * 以输入流的方式上传文件
     * InputStream in = new FileInputStream("C://Desert.jpg");
     * ObjectNode msg = FileUtil.upload(in,"jpg", "沙漠");
     * in.close();
     *
     * @param in                输入流
     * @param fileExtension   文件扩展名，不要带“.”
     * @param description             文件名称（中文）
     * @return 返回值的格式如下:
     * {
     *      "groupName": "healthArchiveGroup",
     *      "remoteFileName": "/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg",
     *      "fid": "group1/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg",
     *      "fileURL": "http://172.19.103.13/healthArchiveGroup/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg"
     * }
     *
     * groupName 及 remoteFileName 可以用于查询在 fastDFS 中文件的信息，如果只是图片显示，可以忽略这两个值。
     * fid 保存了在 fastDFS 上的完整路径，为了避免将来服务器域名发生变更，最好使用本值.服务器的域名另外配置。
     * fileURL 保存了完整的 web 访问路径，为了避免将来服务器域名发生变更，最好不要直接使用本值。
     * 如果需要在下载时，可以显示原始文件名，请在访问file_url时，增加 attname 参数，如：
     *
     * http://host/healthArchiveGroup/M00/00/00/rBFuH1XdIseAUTZZAA1rIuRd3Es062.jpg?attname=a.jpg
     *
     * @throws Exception
     */
    public static ObjectNode upload(InputStream in, String fileExtension,
                                    String description) throws Exception {
        System.out.println("FastDFSUtil→InputStream === "+in);
        StorageClient client = FastDFSClientPool.getInstance().getStorageClient();
        try {
            NameValuePair[] fileMetaData;
            fileMetaData = new NameValuePair[1];
            fileMetaData[0] = new NameValuePair("description", description == null ? "" : description);

            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode message = objectMapper.createObjectNode();

            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            byte[] buff = new byte[BUFFER_SIZE]; //buff用于存放循环读取的临时数据
            int rc = 0;
            while ((rc = in.read(buff, 0, BUFFER_SIZE)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            byte[] fileBuffer = swapStream.toByteArray(); //in_b为转换之后的结果

            TrackerServer trackerServer = FastDFSClientPool.getInstance().getTrackerServer();

            String[] results = client.upload_file(fileBuffer, fileExtension, fileMetaData);
            if (results != null) {
                String fileId;
                int ts;
                String token;
                String fileURl;
                InetSocketAddress socketAddress;

                String groupName = results[0];
                String remoteFile = results[1];
                message.put(GroupField, groupName);
                message.put(RemoteFileField, remoteFile);

                fileId = groupName + StorageClient1.SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + remoteFile;
                message.put(FileIdField, fileId);

                socketAddress = trackerServer.getInetSocketAddress();
                fileURl = "http://" + socketAddress.getAddress().getHostAddress();
                if (ClientGlobal.g_tracker_http_port != 80) {
                    fileURl += ":" + ClientGlobal.g_tracker_http_port;
                }

                fileURl += "/" + fileId;
                if (ClientGlobal.g_anti_steal_token) {
                    ts = (int) (System.currentTimeMillis() / 1000);
                    token = ProtoCommon.getToken(fileId, ts, ClientGlobal.g_secret_key);
                    fileURl += "?token=" + token + "&ts=" + ts;
                }

                message.put(FileUrlField, fileURl);


                return message;
            } else {
                return null;
            }
        }finally {
            FastDFSClientPool.getInstance().releaseStorageClient(client);
        }
    }

    /**
     * 上传本地文件
     * ObjectNode  a = FileUtil.upload("C://Desert.jpg", "沙漠");
     * System.out.println(a.toString());
     *
     * @param fileName 本地文件的绝对路径，如 C://Desert.jpg
     * @param description    文件备注, 可以为空
     * @return {"groupName":"group1","remoteFileName":"/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg"
     * {
     *      "groupName": "healthArchiveGroup",
     *      "remoteFileName": "/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg",
     *      "fid": "group1/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg",
     *      "fileURL": "http://172.19.103.13/healthArchiveGroup/M00/00/24/rBFuH1XdQC6AP3CDAAzodQCbVVc052.jpg"
     * }
     *
     * groupName 及 remoteFileName 可以用于查询在 fastDFS 中文件的信息，如果只是图片显示，可以忽略这两个值。
     * fid 保存了在 fastDFS 上的完整路径，为了避免将来服务器域名发生变更，最好使用本值.服务器的域名另外配置。
     * fileURL 保存了完整的 web 访问路径，为了避免将来服务器域名发生变更，最好不要直接使用本值。
     * 如果需要在下载时，可以显示原始文件名，请在访问file_url时，增加 attname 参数，如：
     *
     * http://host/healthArchiveGroup/M00/00/00/rBFuH1XdIseAUTZZAA1rIuRd3Es062.jpg?attname=a.jpg
     *
     * @throws Exception
     */
    public static ObjectNode upload(String fileName, String description) throws Exception {
        StorageClient client = FastDFSClientPool.getInstance().getStorageClient();
        try {
            NameValuePair[] meta_list;
            meta_list = new NameValuePair[1];
            meta_list[0] = new NameValuePair("description", description == null ? "" : description);

            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode message = objectMapper.createObjectNode();
            String fileExtName = "";
            if (fileName.contains(".")) {
                fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
            } else {
                throw new RuntimeException("上传失败, 文件缺失扩展名.");
            }


            TrackerServer trackerServer = FastDFSClientPool.getInstance().getTrackerServer();


            String[] results = client.upload_file(fileName, fileExtName, meta_list);
            if (results != null) {
                String fileId;
                int ts;
                String token;
                String fileUrl;
                InetSocketAddress inetSockAddr;

                String groupName = results[0];
                String remoteFileName = results[1];
                message.put(GroupField, groupName);
                message.put(RemoteFileField, remoteFileName);

                fileId = groupName + StorageClient1.SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + remoteFileName;
                message.put(FileIdField, fileId);

                inetSockAddr = trackerServer.getInetSocketAddress();
                fileUrl = "http://" + inetSockAddr.getAddress().getHostAddress();
                if (ClientGlobal.g_tracker_http_port != 80) {
                    fileUrl += ":" + ClientGlobal.g_tracker_http_port;
                }
                fileUrl += "/" + fileId;
                if (ClientGlobal.g_anti_steal_token) {
                    ts = (int) (System.currentTimeMillis() / 1000);
                    token = ProtoCommon.getToken(fileId, ts, ClientGlobal.g_secret_key);
                    fileUrl += "?token=" + token + "&ts=" + ts;
                }

                message.put(FileUrlField, fileUrl);


                return message;
            } else {
                return null;
            }
        }finally {
            FastDFSClientPool.getInstance().releaseStorageClient(client);
        }
    }

    /**
     * 下载文件, 返回文件字节数组.
     *
     * @param groupName      在fastdfs上的卷名
     * @param remoteFileName 在fastdfs上的路径
     * @return 文件的字节码
     * @throws Exception
     */
    public static byte[] download(String groupName, String remoteFileName) throws Exception {
        StorageClient client = FastDFSClientPool.getInstance().getStorageClient();
        try {
            byte[] b = client.download_file(groupName, remoteFileName);

            return b;
        }
        finally {
            FastDFSClientPool.getInstance().releaseStorageClient(client);
        }
    }

    /**
     * 下载文件到本地路径上.
     *
     * @param groupName          在 fastDFS 上的卷名
     * @param remoteFileName    在 fastDFS 上的路径
     * @param localPath          本地路径
     *
     * @return 是否下载成功
     */
    public static String download(String groupName, String remoteFileName, String localPath) throws IOException, MyException {
        StorageClient client = FastDFSClientPool.getInstance().getStorageClient();
        try {
            String localFileName = localPath + "\\" + remoteFileName.replaceAll("/", "_");


            client.download_file(groupName, remoteFileName, 0, 0, localFileName);

            return localFileName;
        }finally {
            FastDFSClientPool.getInstance().releaseStorageClient(client);
        }
    }

    /**
     * 删除文件。
     *
     * @param groupName
     * @param remoteFileName
     */
    public static void delete(String groupName, String remoteFileName) throws IOException, MyException {

        StorageClient client = FastDFSClientPool.getInstance().getStorageClient();
        try {
            client.delete_file(groupName, remoteFileName);
        }finally {
            FastDFSClientPool.getInstance().releaseStorageClient(client);
        }
    }
}
