// ============================================================================
// This is a Servlet sample for the G-WAN Web Server (http://www.trustleap.com)
// ----------------------------------------------------------------------------
// loan.c: 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).
//
//       Tip: When using XMLHttpRequest (AJAX), Web browsers split POST in two
//            steps: they send headers and data separately.
//            As GET takes only one step then you can save a connection by not 
//            using POST in your forms -enhancing your web server scalability.
//            (this is an efficient way to boost AJAX graphic user interfaces)
//
//            Using AJAX here saves you from using mod_rewrite to have "normal"
//            search-friendly URLs while taking advantage of servlets.
//
//            One of the most important things to keep in mind here is to make 
//            sure that clients will not lock-up your code with bad input data.
//            The motto is 'filter'. You can also do it on the client side with
//            javascript -but don't count on it. Filter again in your servlets
//            because you just cannot trust what the network brings you (IPSec
//            and SSL make absolutely no difference in this matter).
//
//      Note: xbuf_xcat() will insert ',' every 3 digits if you use uppercase
//            formatters like: "%D", "%U", "%F" (instead of "%d", "%u", "%f").
//            To format (unsigned) __int64 values, use ("%llu" or) "%lld".
//
// ============================================================================
#include <math.h>
#include "xbuffer.h" // G-WAN dynamic buffers

// Top of our HTML page (so it can be called directly rather than as an insert)
static char 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>";

// ----------------------------------------------------------------------------
// imported functions:
//   get_reply(): get a pointer on the 'reply' dynamic buffer from the server
//   set_reply(): send back the 'reply' dynamic buffer's pointer to the server
//   xbuf_ncat(): like strncat(), but in the specified dynamic buffer 
//   xbuf_xcat(): formatted strcat() (a la printf) in a given dynamic buffer 
//     get_arg(): get the specified form field value
// escape_html(): translate HTML tags into harmless escaped sequences
// ----------------------------------------------------------------------------
// like atof() -but here you can *filter* input strings
// ----------------------------------------------------------------------------
double atod(char *p)
{
   double val=0.;
   if(p && *p)
   {  
      int valM=0, valm=0, scale=1, sign=0, i=11;
      while(*p && *p==' ') p++;               // filter spaces, if any
      switch(*p)
      {
        case '-': sign=1;
        case '+': p++;
      }
      while(i && *p && *p>='0' && *p<='9')    // convert the integral part
         valM=valM*10+(*p++-'0'), i--;
      if(*p=='.')                             // pass the decimal point
      {
         p++; i=2;
         while(i && *p && *p>='0' && *p<='9') // convert the decimal part
            valm=valm*10+(*p++-'0'), scale*=10, i--;
      }
      // convert the Major and minor integers into a double
      val=(double)valM+((double)valm/(double)(scale));
      val=sign?-val:val;
   }
   return val;
}
// ----------------------------------------------------------------------------
// return the smallest integer greater than x (this one doesn't use modf)
// ----------------------------------------------------------------------------
__inline unsigned int uceil(double x) // yes, you can use __inline
{
   unsigned int ipart=(int)x;
   if(x-ipart) return(x<0.0)?ipart:ipart+1;
   else        return(ipart);
}
// ----------------------------------------------------------------------------
// main() is receiving the query parameters ("csp?arg1&arg2&arg3...") in argv[]
// ----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
   // create a dynamic buffer and get a pointer on the server response buffer
   xbuf_ctx reply; get_reply(argv, &reply);

   // ---- no query parameters were provided, redirect client to "loan.html"
   if(argc<2)
   {
      static char 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>";

      xbuf_ncat(&reply, redir, sizeof(redir)-1);
      // confirm the reply's dynamic buffer address and size to the server
      // (they have changed when more memory is allocated during formatting)
      set_reply(argv, &reply); return(302); // return an HTTP code (302:'Found')
   }
   else // ---- if we have query parameters, we process a GET/POST form
   {
      char   Months[][10]={
             "January","February","March","April","May","June","July",
             "August","September","October","November","December"};
      char   szName[400]={0};
	   double amount, rate, term, payment, interest, principle, cost;
	   int    month=0, year=1, lastpayment=1;

      // the form field "names" we want to find values for 
      char *Name="", *Amount="0", *Rate="0", *Term="0";
      __int64 start=cycles64(); // current CPU clock cycles' counter

      // get the form field values (note the ending '=' name delimiter)
      get_arg("name=",   &Name,   argc, argv);
      get_arg("amount=", &Amount, argc, argv);
      get_arg("rate=",   &Rate,   argc, argv);
      get_arg("term=",   &Term,   argc, argv); 

      // all litteral strings provided by a client must be escaped this way
      // if you inject them into an HTML page
      escape_html(szName, Name, sizeof(szName)-1);

      // filter input data to avoid all the useless/nasty cases
      amount = atod(Amount); if(amount<1) amount=1;
      rate   = atod(Rate);   if(rate> 19) rate  =19;     else 
                             if(rate  >1) rate /=100;    else 
                             if(rate  <1) rate  =1./100.;
	   term   = atod(Term);   if(term<0.1) term  =1./12.; else 
                             if(term>100) term  =30;

      // calculate the monthly payment amount
      payment = amount*rate/12*pow(1+rate/12, term*12)
              /               (pow(1+rate/12, term*12)-1);
      cost    = (term*12*payment)-amount;

      // build the top of our HTML page
      xbuf_xcat(&reply, top, (*szName && *szName!='-')?szName:"client");
      xbuf_xcat(&reply, "<br><table class=\"clean\" width=240px>"
               "<tr><th>loan</th><th>details</th></tr>"
               "<tr class=\"d1\"><td>Amount</td><td>%.2F</td></tr>"
               "<tr class=\"d0\"><td>Rate</td><td>%.2F%%</td></tr>"
               "<tr class=\"d1\"><td>Term</td><td>%u %s(s)</td></tr>"
               "<tr class=\"d0\"><td>Cost</td><td>%.2F (%.2F%%)</td></tr>"
               "</table>", amount, rate*100, 
               ((unsigned int)term)?((unsigned int)term):uceil(12*term),
               ((unsigned int)term)?"year":"month",
               cost, 100/(amount/cost));

	   xbuf_xcat(&reply, "<br><table class=\"clean\" width=112px>"
               "<tr class=\"d1\"><td><b>YEAR %u</b></td></tr></table>"
               "<table class=\"clean\" width=550px>"
               "<tr><th>month</th><th>payment</th><th>interest</th>"
               "<th>principle</th><th>balance</th></tr>",
               year);

	   for(;;) // output monthly payments
	   {
		   month++;
   	   interest = (amount*rate)/12;
		   if(amount>payment)
         {
            amount = (amount-payment)+interest;
		      principle = payment-interest;
         }
         else // calculate last payment
         {
            if(lastpayment)
            {
               lastpayment = 0;
               payment     = amount;
               principle   = amount-interest;
               amount      = 0;
            }
            else // all payments are done, just padd the table
            {
               amount    = 0;
               payment   = 0;
               interest  = 0;
               principle = 0;
            }
         }

         xbuf_xcat(&reply, 
                  "<tr class=\"d%u\"><td>%s</td><td>%.2F</td><td>%.2F</td>"
                  "<td>%.2F</td><td>%.2F</td></tr>",
                  month&1, Months[month-1], 
                  payment, interest, principle, amount);

		   if(month==12)
		   {
            if(amount)
            {
			      month=0; year++;
	            xbuf_xcat(&reply, 
                        "</table><br><table class=\"clean\" width=112px>"
                        "<tr class=\"d1\"><td><b>YEAR %u</b></td></tr></table>"
                        "<table class=\"clean\" width=550px>"
                        "<tr><th>month</th><th>payment</th><th>interest</th>"
                        "<th>principle</th><th>balance</th></tr>",
                        year);
            }
            else
               break;
         }
      }
      // time the process and close the HTML page
      xbuf_xcat(&reply,
               "</table><br>This page was generated in %llU cpu clock cycles."
               "<br>(on a 3GHz CPU 1 ms = 3,000,000 cycles)"
               "<br></body></html>",
               cycles64()-start);
   }
   // confirm the reply's dynamic buffer address and size to the server
   // (they have changed when more memory is allocated during formatting)
   set_reply(argv, &reply); return(200); // return an HTTP code (200:'OK')
}
// ============================================================================
// End of Source Code
// ============================================================================
