package org.greenstone.gsdl3.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;

import org.greenstone.gsdl3.util.GSParams;
import org.greenstone.util.GlobalProperties;

public class FileLoaderServlet extends LibraryServlet
{
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if (request.getMethod().equals("POST"))
		{

                  int sizeLimit = System.getProperties().containsKey("servlet.upload.filesize.limit") ? Integer.parseInt(System.getProperty("servlet.upload.filesize.limit")) : 20 * 1024 * 1024;

                  File tempDir = new File(GlobalProperties.getGSDL3Home() + File.separator + "tmp");
                  if (!tempDir.exists())
                  {
                    tempDir.mkdirs();
                  }
                  DiskFileItemFactory fileItemFactory =
                    DiskFileItemFactory.builder()
                    .setPath(tempDir.toPath())
                    .setThreshold(0)
                    .get();

                  JakartaServletDiskFileUpload uploadHandler = new JakartaServletDiskFileUpload(fileItemFactory);
                  uploadHandler.setMaxFileSize(sizeLimit);
                  
                  String storageLocation = "";
                  File uploadedFile = null;
                  Boolean ajaxUpload = false;
                  StringBuilder json = new StringBuilder("[");
                  try
                  {
                    List<DiskFileItem> items = uploadHandler.parseRequest(request);
                    for(DiskFileItem current : items) {
                      if (current.isFormField())
                      {
                        if (current.getFieldName().equals(GSParams.FILE_LOCATION))
                        {
                          storageLocation = current.getString(StandardCharsets.UTF_8);
                        }
                        
                        if (current.getFieldName().equals("ajaxUpload") && current.getString(StandardCharsets.UTF_8).equals("true"))
                        {
                          ajaxUpload = true;
                        }
                      }
                      else
                      {
                        File file = new File(GlobalProperties.getGSDL3Home() + File.separator + "tmp" + File.separator + current.getName());
                        
                        current.write(file.toPath());
                        
                        uploadedFile = file;
                        
                        if (!json.toString().equals("["))
                        {
                          json.append(",");
                        }
                        
                        json.append("{");
                        json.append("\"name\":\"" + file.getName() + "\",");
                        json.append("\"size\":\"" + file.length() + "\",");
                        json.append("\"url\":\"" + "tmp/" + current.getName() + "\",");
                        json.append("\"thumbnail_url\":\"" + "tmp/" + current.getName() + "\",");
                        json.append("\"delete_url\":\"\",");
                        json.append("\"delete_type\":\"\"");
                        json.append("}");
                      }
                    }
                    json.append("]");
                    
                    if (ajaxUpload)
                    {
                      response.setContentType("application/json");
                      PrintWriter writer = response.getWriter();
                      writer.write(json.toString());
                      writer.flush();
                      
                      return;
                    }
                    
                    if (!storageLocation.equals("") && uploadedFile != null)
                    {
                      String[] locations = storageLocation.split(":");
                      
                      for (String location : locations)
                      {
                        File toFile = new File(GlobalProperties.getGSDL3Home() + location);
                        if (toFile.exists())
                        {
                          File backupFile = new File(toFile.getAbsolutePath() + System.currentTimeMillis());
                          
                          logger.info("Backing up file (" + toFile.getAbsolutePath() + ") to " + backupFile.getAbsolutePath());
                          toFile.renameTo(backupFile);
                        }
                        
                        FileChannel source = null;
                        FileChannel destination = null;
                        try
                        {
                          logger.info("Moving uploaded file (" + uploadedFile.getAbsolutePath() + ") to " + toFile.getAbsolutePath());
                          source = new FileInputStream(uploadedFile).getChannel();
                          destination = new FileOutputStream(toFile).getChannel();
                          destination.transferFrom(source, 0, source.size());
                        }
                        finally
                        {
                          if (source != null)
                          {
                            source.close();
                          }
                          if (destination != null)
                          {
                            destination.close();
                          }
                        }
                        
                      }
                    }
                    }
                    catch (Exception e)
                    {
                      logger.error("Exception in LibraryServlet -> " + e.getMessage());
                    }
                  }
                  else
                  {
                        Map<String, String[]> queryMap = request.getParameterMap();
			Iterator<String> queryIter = queryMap.keySet().iterator();

			while (queryIter.hasNext())
			{
				String q = queryIter.next();
				if (q.equals("downloadFile"))
				{
					String fileLocation = queryMap.get(q)[0];
					File fileToGet = new File(GlobalProperties.getGSDL3Home() + File.separator + fileLocation);

					if (fileToGet.exists())
					{
						response.setContentType("application/octet-stream");
						response.addHeader("Content-Disposition", "attachment;filename=" + fileToGet.getName());
						FileInputStream fis = new FileInputStream(fileToGet);
						ServletOutputStream sos = response.getOutputStream();

						byte[] buffer = new byte[4096];
						int len;
						while ((len = fis.read(buffer)) != -1)
						{
							sos.write(buffer, 0, len);
						}
						sos.flush();
						fis.close();
						sos.close();

						return;
					}
				}
			}
		}

		super.doGet(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		doGet(request, response);
	}
}
