package xso.timewriter.webserver;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class TestWebServer
{

  public static void main( String[] args )
  {
    try
    {
      Server jettyServer = new Server();

      ServletContextHandler contextHandler = new ServletContextHandler( ServletContextHandler.SESSIONS );

      HandlerList handlers = new HandlerList();
      handlers.setHandlers( new Handler[] { contextHandler } );
      jettyServer.setHandler( handlers );

      contextHandler.addServlet( new ServletHolder( new FilesServlet() ), "/html/*" ); //$NON-NLS-1$

      // Changed SocketConnector to ServerConnector due to upgrade of Jetty 9.4.5 (from 8.1.4)
      //SocketConnector _httpConnector = new SocketConnector();
      //_httpConnector.setPort( 80 );
      //_JettyServer.addConnector( _httpConnector );

      ServerConnector _httpConnector = new ServerConnector( jettyServer );
      _httpConnector.setPort( 80 );
      jettyServer.addConnector( _httpConnector );

      jettyServer.start();
      jettyServer.join();

      _httpConnector.close();
    }
    catch ( Exception e )
    {
      e.printStackTrace();
    }
  }

  @SuppressWarnings( "serial" )
  public static class FilesServlet extends HttpServlet
  {
    private final String PATH = "/html/";

    @Override
    protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
    {
      String pathInfo = request.getPathInfo();
      if ( pathInfo == null )
      {
        sendNotFound( response );
        return;
      }

      String requestFileName = pathInfo.substring( 1 ); // pathInfo starts with a slash
      requestFileName = PATH + requestFileName;

      if ( requestFileName.isEmpty() || requestFileName.endsWith( "/" ) ) //$NON-NLS-1$
      {
        requestFileName += "index.html"; //$NON-NLS-1$
      }

      System.out.println( "requestFileName: " + requestFileName );

      String fileName = requestFileName.replace( "\\", File.separator ); //$NON-NLS-1$
      fileName = fileName.replace( "/", File.separator ); //$NON-NLS-1$

      boolean invalid = fileName.contains( ":" ) || fileName.contains( ".." ) || fileName.startsWith( "." ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

      if ( fileName.startsWith( File.separator ) )
        fileName = fileName.substring( 1 );

      fileName = "." + File.separator + fileName; //$NON-NLS-1$

      File entry = new File( fileName );
      if ( invalid || !entry.exists() )
      {
        sendNotFound( response );
      }
      else
      {
        String lowerCase = fileName.toLowerCase();

        if ( lowerCase.endsWith( ".txt" ) || lowerCase.endsWith( ".log" ) || lowerCase.endsWith( ".ini" ) ) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          response.setContentType( "text/plain" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".html" ) || lowerCase.endsWith( ".htm" ) ) //$NON-NLS-1$ //$NON-NLS-2$
          response.setContentType( "text/html" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".xml" ) ) //$NON-NLS-1$
          response.setContentType( "text/xml" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".wsdl" ) ) //$NON-NLS-1$
          response.setContentType( "text/xml" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".xsd" ) ) //$NON-NLS-1$
          response.setContentType( "text/xml" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".jar" ) ) //$NON-NLS-1$        
          response.setContentType( "application/x-java-archive" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".css" ) ) //$NON-NLS-1$
          response.setContentType( "text/css" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".js" ) ) //$NON-NLS-1$
          response.setContentType( "text/javascript" ); //$NON-NLS-1$
        else if ( lowerCase.endsWith( ".pdf" ) ) //$NON-NLS-1$
          response.setContentType( "application/pdf" ); //$NON-NLS-1$
        else if ( lowerCase.indexOf( ".xls" ) > -1 ) //$NON-NLS-1$
          response.setContentType( "application/vnd.ms-excel" ); //$NON-NLS-1$
        else
          response.setContentType( "application/octet-stream" ); //$NON-NLS-1$

        response.setStatus( HttpServletResponse.SC_OK );
        OutputStream outputStream = response.getOutputStream();
        outputStream = new BufferedOutputStream( outputStream, 2 * 1024 * 1024 );
        sendFile( fileName, outputStream );
        outputStream.close();
      }
    }

    protected void sendFile( String fileName, OutputStream outputStream ) throws IOException
    {
      System.out.println( "sending: " + fileName );

      InputStream inputStream = new FileInputStream( fileName );
      inputStream = new BufferedInputStream( inputStream, 2 * 1024 * 1024 );
      byte[] buffer = new byte[4 * 1024 * 1024];
      int bytesRead;
      while ( ( bytesRead = inputStream.read( buffer ) ) > 0 )
        outputStream.write( buffer, 0, bytesRead );
      inputStream.close();

      System.out.println( fileName + " send" );
    }

    protected void sendNotFound( HttpServletResponse response ) throws IOException
    {
      response.setStatus( HttpServletResponse.SC_NOT_FOUND );
      response.setContentType( "text/html;charset=UTF-8" ); //$NON-NLS-1$
      PrintWriter pw = response.getWriter();
      try
      {
        String content = "<html>"
            + "<head><title>Test</title></head>"
            + "<body><br><h1>Page not found</h1></body>"
            + "</html>";
        pw.println( content );
        response.flushBuffer();
      }
      finally
      {
        pw.close();
      }
    }
  }

}
