package com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.operator;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chenyang.nse.bussiness.entity.db.ColumnInfo;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.HdfsFileInfo;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.TableInfo;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.format.HdfsFileReader;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.format.HdfsItemIterator;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.format.HiveFileType;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.format.OrcFileReader;
import com.chenyang.nse.bussiness.tools.dataprocess.hive.hdfs.format.TextFileReader;
import com.chenyang.nse.bussiness.tools.http.HttpClientUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.hadoop.fs.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WebHdfsOperator extends HdfsOperator {
   private static final Logger LOGGER = LoggerFactory.getLogger(WebHdfsOperator.class);
   String baseUrl = "http://10.11.200.111:50070/webhdfs/v1";
   String nameService = "hdfs://nameservice1";
   String userName = "admin";
   String token = "fqK3dLNtFHUnknBoqXmi-TDH";
   static final String TEMP_TABLE_LOCATION = "temp_orc_table_location";

   public WebHdfsOperator(Connection connection, Properties properties, TableInfo table) {
      super(connection, properties, table);
      this.loadProperties();
   }

   public void prepare(String schema, String table) throws Exception {
      HiveFileType fileType = this.table.getFileType();
      if (fileType == HiveFileType.orc) {
         this.logger.info("文件格式为ORC格式。");
         String tableTempName = this.table.getTempTableName();
         String sql = "DROP TABLE IF EXISTS `" + schema + "`.`" + tableTempName + "`";
         Statement statement = this.connection.createStatement();
         Throwable col = null;

         try {
            statement.execute(sql);
         } catch (Throwable var31) {
            col = var31;
            throw var31;
         } finally {
            if (statement != null) {
               if (col != null) {
                  try {
                     statement.close();
                  } catch (Throwable var29) {
                     col.addSuppressed(var29);
                  }
               } else {
                  statement.close();
               }
            }

         }

         this.logger.info(sql);
         sql = "create table `" + schema + "`.`" + tableTempName + "` (";

         for(int i = 0; i < this.table.cols.size(); ++i) {
            ColumnInfo colNew = (ColumnInfo)this.table.cols.get(i);
            sql = sql + " " + colNew.getColumnname() + " " + colNew.getTypename();
            if (i != this.table.cols.size() - 1) {
               sql = sql + ",";
            }
         }

         sql = sql + ") ";
         sql = sql + "clustered BY (" + ((ColumnInfo)this.table.cols.get(0)).getColumnname() + ")";
         sql = sql + "INTO 2 buckets ROW format delimited fields terminated BY '\\t'";
         sql = sql + "stored AS textfile";
         statement = this.connection.createStatement();
         col = null;

         try {
            statement.execute(sql);
         } catch (Throwable var30) {
            col = var30;
            throw var30;
         } finally {
            if (statement != null) {
               if (col != null) {
                  try {
                     statement.close();
                  } catch (Throwable var28) {
                     col.addSuppressed(var28);
                  }
               } else {
                  statement.close();
               }
            }

         }

         this.logger.info(sql);
      }

   }

   private void loadProperties() {
      if (this.properties != null && this.properties.size() != 0) {
         String hdfsUrl = this.properties.getProperty("web.hdfs.url");
         if (hdfsUrl != null && hdfsUrl.length() > 0) {
            this.baseUrl = hdfsUrl;
            this.logger.info(hdfsUrl);
         }

         String hdfsNameService = this.properties.getProperty("web.hdfs.name-service");
         if (hdfsNameService != null && hdfsNameService.length() > 0) {
            this.nameService = hdfsNameService;
            this.logger.info(this.nameService);
         }

         String hdfsUsername = this.properties.getProperty("web.hdfs.username");
         if (hdfsUsername != null && hdfsUsername.length() > 0) {
            this.userName = hdfsUsername;
            this.logger.info(this.userName);
         }

         String hdfsToken = this.properties.getProperty("web.hdfs.token");
         if (hdfsToken != null && hdfsToken.length() > 0) {
            this.token = hdfsToken;
            this.logger.info(this.token);
         }

      }
   }

   public List<HdfsFileInfo> listFiles(String schema, String table, String location) throws Exception {
      if (location == null) {
         location = this.getTableLocation(schema, table);
      }

      this.logger.info(String.format("表%s.%s文件的存储位置为：%s", schema, table, location));
      if (location != null && location.length() != 0) {
         List<HdfsFileInfo> files = new ArrayList();
         this.listTableFiles(schema, table, location, files);
         return files;
      } else {
         return null;
      }
   }

   private void listTableFiles(String schema, String table, String location, List<HdfsFileInfo> output) throws IOException, URISyntaxException {
      location = this.wrapName(location);
      String url = this.baseUrl + location + "?op=LISTSTATUS";
      url = this.wrapRequest(url);
      this.logger.info(String.format("枚举表文件: %s.%s 请求 :%s", schema, table, url));
      String content = HttpClientUtils.doGet(url);
      this.logger.info(String.format("枚举表文件: %s.%s 请求 :%s,执行完成", schema, table, url));
      if (content != null && content.length() > 0) {
         JSONObject data = (JSONObject)JSON.parse(content);
         if (data != null) {
            JSONObject fileStatuses = (JSONObject)data.get("FileStatuses");
            if (fileStatuses != null) {
               JSONArray fileStatus = fileStatuses.getJSONArray("FileStatus");
               if (fileStatus != null && fileStatus.size() > 0) {
                  for(int i = 0; i < fileStatus.size(); ++i) {
                     JSONObject file = (JSONObject)fileStatus.get(i);
                     if (file != null) {
                        String name = (String)file.get("pathSuffix");
                        if (name != null && name.length() != 0) {
                           String type = (String)file.get("type");
                           if (type.equalsIgnoreCase("FILE")) {
                              HdfsFileInfo hinfo = new HdfsFileInfo();
                              hinfo.setName(name);
                              hinfo.setDir(location);
                              hinfo.setFullName(location + "/" + name);
                              hinfo.setGroup((String)file.get("group"));
                              hinfo.setOwner((String)file.get("owner"));
                              hinfo.setLength("" + file.get("length"));
                              hinfo.setBlockSize("" + file.get("blockSize"));
                              hinfo.setType((String)file.get("type"));
                              hinfo.setPermission((String)file.get("permission"));
                              this.logger.info(String.format("获取到表%s.%s文件：%s/%s", schema, table, location, name));
                              output.add(hinfo);
                           } else {
                              String subLocation = location + "/" + name;
                              this.listTableFiles(schema, table, subLocation, output);
                           }
                        }
                     }
                  }
               }
            }
         }
      }

   }

   public InputStream loadFile(String schema, String table, String location) {
      if (location != null && location.length() != 0) {
         location = this.wrapName(location);
         String url = this.baseUrl + location + "?op=OPEN";
         url = this.wrapRequest(url);
         this.logger.info(String.format("load %s.%s file %s from %s", schema, table, location, url));

         try {
            String content = HttpClientUtils.doGet(url);
            this.logger.info(String.format("load %s.%s file %s success from %s", schema, table, location, url));
            byte[] buffer = content.getBytes(StandardCharsets.UTF_8);
            ByteArrayInputStream input = new ByteArrayInputStream(buffer);
            return input;
         } catch (Exception e) {
            this.logger.error(String.format("load %s.%s file %s failed from %s", schema, table, location, url));
            e.printStackTrace();
            return null;
         }
      } else {
         return null;
      }
   }

   public HdfsItemIterator loadFileIter(String schema, String table, String location) throws IOException, URISyntaxException {
      if (location != null && location.length() != 0) {
         location = this.wrapName(location);
         String url = this.baseUrl + location + "?op=OPEN";
         url = this.wrapRequest(url);

         try {
            byte[] buffer = HttpClientUtils.doGetBuffer(url);
            HdfsFileReader reader = null;
            switch (this.table.getFileType()) {
               case orc:
                  String start = System.getProperty("user.dir");
                  Path p = new Path(location);
                  String name = p.getName();
                  String file = start + "/" + name + "_temp";
                  File orcLocal = new File(file);
                  if (orcLocal.exists()) {
                     orcLocal.delete();
                  }

                  FileOutputStream os = new FileOutputStream(file);
                  os.write(buffer);
                  os.flush();
                  os.close();
                  reader = new OrcFileReader(new Path(file), this.table.cols);
                  break;
               case text:
                  reader = new TextFileReader(this.table, buffer);
               case seq:
               case parquet:
            }

            if (reader != null) {
               reader.load();
            }

            return new HdfsItemIterator(reader);
         } catch (Exception e) {
            throw e;
         }
      } else {
         return null;
      }
   }

   public OutputStream createFile(String schema, String table, String location) throws Exception {
      if (location != null && location.length() != 0) {
         location = this.wrapName(location);
         HiveFileType fileType = this.table.getFileType();
         if (fileType == HiveFileType.orc) {
            String tempTable = this.table.getTempTableName();
            String tempLocation = super.getTableLocation(schema, tempTable);
            tempLocation = this.wrapName(tempLocation);
            tempLocation = tempLocation + "/" + table + ".txt";
            this.table.datas.put("temp_orc_table_location", tempLocation);
            new Path(tempLocation);
            location = tempLocation;
         }

         String url = this.baseUrl + location + "?op=CREATE&noredirect=false";
         url = this.wrapRequest(url);
         this.logger.info(String.format("开始创建表%s.%s的临时文件%s通过%s", schema, table, location, url));
         String content = HttpClientUtils.doPut(url);
         this.logger.info(String.format("开始创建表%s.%s的临时文件%s通过%s成功", schema, table, location, url));
         ByteArrayOutputStream output = new ByteArrayOutputStream();
         return output;
      } else {
         return null;
      }
   }

   public void saveBatch(String schema, String table, String location, OutputStream stream) throws Exception {
      location = this.wrapName(location);
      HiveFileType fileType = this.table.getFileType();
      if (fileType == HiveFileType.orc) {
         new Path(location);
         String tempPath = (String)this.table.datas.get("temp_orc_table_location");
         location = tempPath;
      }

      String url = this.baseUrl + location + "?op=APPEND&noredirect=false";
      url = this.wrapRequest(url);

      try {
         ByteArrayOutputStream output = (ByteArrayOutputStream)stream;
         if (output == null) {
            throw new Exception("错误的输出流");
         } else {
            byte[] buffer = output.toByteArray();
            this.logger.info(String.format("开始追加表%s.%s的临时文件数据%s通过%s", schema, table, location, url));
            String content = HttpClientUtils.doPost(url, buffer);
            this.logger.info(String.format("追加表%s.%s的临时文件数据%s通过%s成功", schema, table, location, url));
            if (fileType == HiveFileType.orc) {
               String tableFullName = "`" + schema + "`.`" + this.table.getTempTableName() + "`";
               String sql = "LOAD DATA INPATH '" + location + "' INTO TABLE " + tableFullName;
               Statement statement = this.connection.createStatement();
               this.logger.info(String.format("追加表%s.%s的临时文件到临时数据表采用%s", schema, table, location, sql));
               statement.execute(sql);
            }

            LOGGER.info(content);
            output.reset();
         }
      } catch (Exception e) {
         e.printStackTrace();
         LOGGER.error("提交文件失败:" + e.getMessage(), e);
         throw e;
      }
   }

   public void closeFile(String schema, String table, String location) throws Exception {
   }

   public void fininshed(String schema, String table) throws Exception {
      HiveFileType fileType = this.table.getFileType();
      if (fileType == HiveFileType.orc) {
         String location = (String)this.table.datas.get("temp_orc_table_location");
         String orcTable = "`" + schema + "`.`" + table + "`";
         String tempTable = "`" + schema + "`.`" + this.table.getTempTableName() + "`";
         String sql = null;
         boolean autoCommit = this.connection.getAutoCommit();

         try {
            this.connection.setAutoCommit(false);
            sql = "truncate table " + orcTable;
            Statement statement = this.connection.createStatement();
            Throwable e = null;

            try {
               this.logger.info(String.format("删除表%s.%s原始表的数据,采用%s", schema, table, sql));
               statement.execute(sql);
               this.logger.info(String.format("删除表%s.%s原始表的数据,采用%s,执行完成", schema, table, sql));
            } catch (Throwable var81) {
               e = var81;
               throw var81;
            } finally {
               if (statement != null) {
                  if (e != null) {
                     try {
                        statement.close();
                     } catch (Throwable var80) {
                        e.addSuppressed(var80);
                     }
                  } else {
                     statement.close();
                  }
               }

            }

            sql = "insert into table " + orcTable + " select * from " + tempTable;
            statement = this.connection.createStatement();
            e = null;

            try {
               this.logger.info(String.format("将临时表的数据插入表%s.%s,采用%s", schema, table, sql));
               statement.execute(sql);
               this.logger.info(String.format("将临时表的数据插入表%s.%s,采用%s，执行完成", schema, table, sql));
            } catch (Throwable var79) {
               e = var79;
               throw var79;
            } finally {
               if (statement != null) {
                  if (e != null) {
                     try {
                        statement.close();
                     } catch (Throwable var78) {
                        e.addSuppressed(var78);
                     }
                  } else {
                     statement.close();
                  }
               }

            }

            this.connection.commit();
         } catch (Exception var85) {
            this.connection.rollback();
         } finally {
            this.connection.setAutoCommit(autoCommit);
         }

         sql = "drop table " + tempTable;
         Statement statement = this.connection.createStatement();
         Throwable var96 = null;

         try {
            this.logger.info(String.format("DROP表%s.%s对应的临时表,采用%s", schema, table, sql));
            statement.execute(sql);
            this.logger.info(String.format("DROP表%s.%s对应的临时表,采用%s,执行完成", schema, table, sql));
         } catch (Throwable var77) {
            var96 = var77;
            throw var77;
         } finally {
            if (statement != null) {
               if (var96 != null) {
                  try {
                     statement.close();
                  } catch (Throwable var75) {
                     var96.addSuppressed(var75);
                  }
               } else {
                  statement.close();
               }
            }

         }

         location = this.wrapName(location);
         String url = this.baseUrl + location + "?op=DELETE&recursive=false";
         url = this.wrapRequest(url);

         try {
            this.logger.info(String.format("删除表%s.%s对应的临时文件%s", schema, table, url));
            String content = HttpClientUtils.doDelete(url);
            this.logger.info(String.format("删除表%s.%s对应的临时文件%s，执行完成", schema, table, url));
         } catch (Exception e) {
            e.printStackTrace();
            this.logger.info(String.format("删除表%s.%s对应的临时文件%s，执行异常%s", schema, table, url, e.toString()));
            throw e;
         }
      }

   }

   public void deleteFile(String schema, String table, String location) throws IOException, URISyntaxException {
      HiveFileType fileType = this.table.getFileType();
      if (fileType != HiveFileType.orc) {
         location = this.wrapName(location);
         String url = this.baseUrl + location + "?op=DELETE&recursive=false";
         url = this.wrapRequest(url);

         try {
            this.logger.info(String.format("删除表%s.%s对应的临时文件%s", schema, table, url));
            String content = HttpClientUtils.doDelete(url);
            this.logger.info(String.format("删除表%s.%s对应的临时文件%s，执行完成", schema, table, url));
            LOGGER.info(content);
         } catch (Exception e) {
            this.logger.info(String.format("删除表%s.%s对应的临时文件%s，执行异常%s", schema, table, url, e.toString()));
            e.printStackTrace();
            throw e;
         }
      }
   }

   public void rename(String schema, String table, String location, String newname) throws Exception {
      if (location != null && location.length() != 0) {
         if (newname != null && newname.length() != 0) {
            HiveFileType fileType = this.table.getFileType();
            if (fileType != HiveFileType.orc) {
               location = this.wrapName(location);
               String url = this.baseUrl + location + "?op=RENAME&destination=" + newname;
               url = this.wrapRequest(url);

               try {
                  this.logger.info(String.format("重命名%s.%s对应的临时文件为原始文件名通过%s", schema, table, url));
                  String content = HttpClientUtils.doPut(url);
                  this.logger.info(String.format("重命名%s.%s对应的临时文件为原始文件名通过%s，执行完成", schema, table, url));
               } catch (Exception e) {
                  this.logger.info(String.format("重命名%s.%s对应的临时文件为原始文件名通过%s，执行异常%s", schema, table, url, e.toString()));
                  throw e;
               }
            }
         } else {
            throw new Exception("修改后的文件名为空");
         }
      } else {
         throw new Exception("被修改的文件名为空");
      }
   }

   private String wrapRequest(String cmd) {
      if (cmd != null && cmd.length() != 0) {
         if (this.userName != null && this.userName.length() > 0) {
            cmd = cmd + "&user.name=" + this.userName;
         }

         if (this.token != null && this.token.length() > 0) {
            cmd = cmd + "&guardian_access_token=" + this.token;
         }

         return cmd;
      } else {
         return cmd;
      }
   }

   private String wrapName(String name) {
      if (name != null && name.length() != 0) {
         name = name.replaceFirst(this.nameService, "");
         return name;
      } else {
         return name;
      }
   }
}
