<!-- This is a Java benchmark servlet for the G-WAN Application server

 loan.jsp: An AJAX Web application to help people calculate the cost of loans

            When clients use the loan.html form, we use the form fields to
            build new content which is then inserted into the original page
            (the javascript code in loan.html will tell you how AJAX works).

            GET and POST forms are processed with the SAME code (the server
            does the URL/Entity parsing for servlets).

            POST is often prefered to GET because the parameters are passed
            in the URL (so they are visible) while POST is using the request
            entity. This difference is *not* relevant in our case because we
            use AJAX to process the query (as a result, the URL is not seen
            by end-users in the Web browser 'address' field).

      Note: Some Java fans claimed that this (Java) code sucks. For their
            information, it has been submitted to the SUN GlassFish team one 
            month before the test has been published. 
            
            And, unlike MSFT, SUN replied that they were interested in by 
            performances. By working with the GlassFish team (who knows a
            thing or two about Java) we have made GlassFish (not loan.jsp) 
            work twice as fast.

     This code is released into the public domain.

     Yes, we know that a jsp should not use printf(). This is done here to
     put each scripting engine (C, C#, Java, PHP) on an equal basis as the
     goal is more about comparing efficiency than style.
 -->

<?xml version = "1.0"?>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@ page import="javax.servlet.*" %>
<%@ page import="javax.servlet.http.*" %>
<%@ page import="java.text.*" %>
<%@ page import="java.math.*" %>
<%@ page import="java.io.*" %>
<%@ page session="false" %>

<%
   // the default 'out' does not support printf()...
   PrintWriter m_out = response.getWriter();

   // ---- requests without parameters trigger a redirect to the input form
   // (not functional here, we just implement the test)
   if(request.getParameter("name") == null)
   {
      String redir="HTTP/1.1 302 Found\r\n"
      + "Content-type:text/html\r\n"
      + "Location: loan.html\r\n\r\n"
      + "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
      + "<html><head><title>Redirect</title></head>"
      + "<body>Click <a href=\"loan.html\">HERE</A> for redirect.</body>"
      + "</html>";
      m_out.println(redir);
   }
   else
   {
      // ---- process a GET query with parameters
      long start = System.currentTimeMillis();
	   double payment, interest, principal, cost, amount, rate, term;
	   int    month=0, year=1, lastpayment=1;
      String[] Months={"January","February","March","April","May","June",
               "July", "August","September","October","November","December"};

      // the form field "names" we want to find values for
      String szName="-", Name="", Amount="0.0", Rate="0.0", Term="0.0";

      // get the form field values (note the ending '=' name delimiter)
      Name   = (String)request.getParameter("name");
      Amount = (String)request.getParameter("amount");
      Rate   = (String)request.getParameter("rate");
      Term   = (String)request.getParameter("term");

      // set default values if a parameter is missing
      if(Name   == null) Name   ="-";
      if(Amount == null) Amount ="100000.0";
      if(Rate   == null) Rate   ="3.5";
      if(Term   == null) Term   ="10.0";

      // all litteral strings provided by a client must be escaped this way
      // if you inject them into an HTML page
      //public static String escape_html(String Name)
      {
          int len = Name.length();
          StringBuffer sb = new StringBuffer(len);
          boolean lastWasBlankChar = false;
          int c;

          for(int i=0; i<len; i++)
          {
              c = Name.charAt(i);
              if(c == ' ')  sb.append("&#32;");  else
              if(c == '"')  sb.append("&quot;"); else
              if(c == '&')  sb.append("&amp;");  else
              if(c == '<')  sb.append("&lt;");   else
              if(c == '>')  sb.append("&gt;");   else
              if(c == '\n') sb.append("&lt;br/&gt;");
              else
              {
                 c = c&0xffff; // unicode
                 if(c < 32 || c > 127)
                 {
                    sb.append("&#");
                    sb.append(new Integer(c).toString());
                    sb.append(';');
                 }
                 else
                    sb.append(c);
              }
          }
          //return sb.toString();
          szName = sb.toString();
      }

      // filter input data to avoid all the useless or nasty cases
      amount = Double.parseDouble(Amount);
      if(amount < 1.0)
         amount = 1.0;

      rate = Double.parseDouble(Rate);
      if(rate > 19.0)
         rate = 20.0;

      if(rate > 1.0)
         rate = rate/100.0;
      else
      if(rate < 1.0)
         rate  = 1.0/100.0;

      term = Double.parseDouble(Term);
	   if(term < 0.1)
	      term = 1.0/12.0;
      // do not do this in production...
	   //else
	   //if(term > 90.0)
      //   term = 90.0;

      // calculate the monthly payment amount
      payment = amount*rate/12*Math.pow(1+rate/12, term*12)
              /               (Math.pow(1+rate/12, term*12)-1);
      cost    = (term*12*payment)-amount;

      // build the top of our HTML page
      String top="<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
      + "<html lang=\"en\"><head><title>Loan Calculator</title><meta "
      + "http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
      + "<link href=\"imgs/style.css\" rel=\"stylesheet\" type=\"text/css\">"
      + "</head><body><h2>Dear %s, your loan goes as follows:</h2>";

      m_out.printf(top, (szName.length()<2 || szName.charAt(0)=='-')
                   ?"client":szName);

      // DecimalFormat is rounding, don't know how to prevent this...
      DecimalFormat df;
      df = new DecimalFormat("0.00");
      df.setGroupingUsed(true);
      df.setGroupingSize(3);

      m_out.printf("<br><table class=\"clean\" width=240px>"
                +"<tr><th>loan</th><th>details</th></tr>"
                +"<tr class=\"d1\"><td>Amount</td><td>%s"
                +"</td></tr><tr class=\"d0\"><td>Rate</td><td>"
                +"%s%%</td></tr><tr class=\"d1\"><td>Term</td><td>"
                +"%d %s(s)</td></tr><tr class=\"d0\"><td>Cost</td><td>"
                +"%s (%3.2f%%)</td></tr></table>",
                 df.format(amount),
                 df.format(rate*100),
                 (int)(((int)term>0)?term:Math.ceil(12*term)),
                 ((int)term>0)?"year":"month",
                 df.format(cost),
                 100/(amount/cost), 2);

	   m_out.printf("<br><table class=\"clean\" width=112px>"
                +"<tr class=\"d1\"><td><b>YEAR %d"
                +"</b></td></tr></table>"
                +"<table class=\"clean\" width=550px>"
                +"<tr><th>month</th><th>payment</th><th>interest</th>"
                +"<th>principal</th><th>balance</th></tr>",
                 year);

      // output monthly payments
	   for(;;)
	   {
		   month    = month+1;
   	       interest = (amount*rate)/12;
		   if(amount>payment)
         {
            amount    = (amount-payment)+interest;
		      principal = payment-interest;
         }
         else
         {
            // calculate last payment
            if(lastpayment>0)
            {
               lastpayment = 0;
               payment     = amount;
               principal   = amount-interest;
               amount      = 0;
            }
            else
            {
               // all payments are done, just padd the table
               amount    = 0;
               payment   = 0;
               interest  = 0;
               principal = 0;
            }
         }

         m_out.printf("<tr class=\"d%d\"><td>%s</td><td>%s</td><td>%s"
                     +"</td><td>%s</td><td>%s</td></tr>",
                      month&1, Months[month-1],
                      df.format(payment),
                      df.format(interest),
                      df.format(principal),
                      df.format(amount));

		   if(month==12)
		   {
            if(amount>0)
            {
			      month=0; year=year+1;
	            m_out.printf("</table><br><table class=\"clean\" width=112px>"
                           +"<tr class=\"d1\"><td><b>YEAR %d"
                           +"</b></td></tr></table>"
                           +"<table class=\"clean\" width=550px>"
                           +"<tr><th>month</th><th>payment</th><th>interest"
                           +"</th><th>principal</th><th>balance</th></tr>",
                            year);
            }
            else
            {
               break;
            }
         }

      }

      // time the process and close the HTML page
      long end=System.currentTimeMillis();
      m_out.printf("</table><br>This page was generated in %s ms."
                +"<br>(on a 3GHz CPU 1 ms = 3,000,000 cycles)"
                +"<br></body></html>",
                 df.format(end-start));

   }

   m_out.close();  // complete the page
%>
