//---------------------------------------------------------------------------
//
// MODULE NAME:     main.cpp
//
// COPYRIGHT:       Copyright (c) 2013, GladeSoft, Inc.
//                  All Rights Reserved.
//
//                  NOTICE: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF
//                  GLADESOFT, INC., AND SHALL NOT BE REPRODUCED, COPIED
//                  IN WHOLE OR IN PART ADAPTED, MODIFIED, OR
//                  DISSEMINATED WITHOUT THE EXPRESS WRITTEN CONSENT
//                  OF GLADESOFT, INC. ANY REDISTRIBUTION OR
//                  PUBLICATION TO UNAUTHORIZED PERSONS IS STRICTLY
//                  PROHIBITED BY U.S. AND INTERNATIONAL COPYRIGHT LAW.
//
// DESCRIPTION:     Another example program using the Seminole embedded 
//                  web server.
//
// AUTHOR:          S. Conner
//
// CREATION DATE:   Feb  5, 2004
//
//---------------------------------------------------------------------------
//
// HISTORY OF CHANGE  
//
// -----+--------+------------------------------------------+------+---------
// VERS | DATE   | DESCRIPTION OF CHANGE                    | INIT | PR#
// =====+========+==========================================+======+=========
//  001 |02/05/04| File creation.                           | SPC  |
// -----+--------+------------------------------------------+------+---------
//  002 |06/12/09| Const correctness.                       | RAH  |
// -----+--------+------------------------------------------+------+---------
//---------------------------------------------------------------------------

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#if HTTPD_HAVE_CLOCK
# include <time.h>
#endif

#include "seminole.h"

//**********************************************************************

class DemoHelloWorldHandler : public HttpdHandler
{
public:
  DemoHelloWorldHandler(const char *prefix);
  ~DemoHelloWorldHandler();
  virtual bool Handle(HttpdRequest *p_req);
};

class DemoTimeHandler : public HttpdHandler
{
private:
  const bool mTimeOrDate;
    
public:
  DemoTimeHandler(const char *p_prefix, bool time_or_date = false);
  ~DemoTimeHandler();
  virtual bool Handle(HttpdRequest *p_req);
};

static const char  gServername[] = "localhost";
static const int   gServerport   = 8080;
static Httpd      *gpWebServer;

//**********************************************************************

//---------------------------------------------------------------------------
//
// NAME:           DemoHelloWorldHandler::DemoHelloWorldHandler
//
// DESCRIPTION:    Construct a simple request handler.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
DemoHelloWorldHandler::DemoHelloWorldHandler(const char *p_prefix)
{
  mpPrefix = HttpdUtilities::SaveString(p_prefix);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoHelloWorldHandler::~DemoHelloWorldHandler
//
// DESCRIPTION:    Destroy a simple request handler.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
DemoHelloWorldHandler::~DemoHelloWorldHandler()
{
  HttpdOpSys::Free((char *)mpPrefix);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoHelloWorldHandler::Handle
//
// DESCRIPTION:    Process the request.
//
// RETURNS:        True if the request was handled by this handler,
//                 false if no processing has been performed.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
bool DemoHelloWorldHandler::Handle(HttpdRequest *p_req)
{
  assert(p_req != NULL);
  
  if (IsMe(p_req))
  {
    bool is_head = p_req->IsHeadRequest();

    HttpdDynamicOutput output(p_req, is_head);
    p_req->Respond(HTTPD_RESP_OK);
    output.Header("Content-Type", "text/html");
    output.HeaderComplete();
    
    output.Body()->Printf(
                          "<html>\n"
                          "<head>\n"
                          "  <title>Hello World!</title>\n"
                          "</head>\n"
                          "<body>\n"
                          "  <h1>Hello World!<h1>\n"
                          "</body>\n"
                          "</html>\n"
                          "\n"
                         );

    return (true);
  }

  return (false);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoTimeHandler::DemoTimeHandler
//
// DESCRIPTION:    Construct a request handler to report the current time.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
DemoTimeHandler::DemoTimeHandler(const char *p_prefix, bool time_or_date)
  : mTimeOrDate(time_or_date)
{
  mpPrefix = HttpdUtilities::SaveString(p_prefix);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoTimeHandler::~DemoTimeHandler
//
// DESCRIPTION:    Destroy the time reporting handler.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
DemoTimeHandler::~DemoTimeHandler()
{
  HttpdOpSys::Free((char *)mpPrefix);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoTimeHandler::Handle
//
// DESCRIPTION:    Process the request.
//
// RETURNS:        True if the request was handled by this handler,
//                 false if no processing has been performed.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
bool DemoTimeHandler::Handle(HttpdRequest *p_req)
{
  assert(p_req != NULL);
          
  if (IsMyPath(p_req))
  {
#if HTTPD_HAVE_CLOCK
    char         gmt_time[48];
    char         local_time[48];
    time_t       now;
    struct tm   *p_tm;
    const char  *p_title;
    bool         is_head;

    is_head = p_req->IsHeadRequest();
    HttpdDynamicOutput output(p_req, is_head);
    p_req->Respond(HTTPD_RESP_OK);
    output.Header("Content-Type", "text/html");
    output.HeaderComplete();

    now = time(NULL);
    if (mTimeOrDate)
    {
      p_tm = gmtime(&now);
      strftime(gmt_time, sizeof(gmt_time),
               "GMT Date: %A, %B %d, %Y", p_tm);
      p_tm = localtime(&now);
      strftime(local_time, sizeof(local_time),
               "Local Date: %A, %B %d, %Y", p_tm);
      p_title = "The Date";
    }
    else
    {
      p_tm = gmtime(&now);
      strftime(gmt_time, sizeof(gmt_time),
               "GMT Time: %H:%M:%S", p_tm);
      p_tm = localtime(&now);
      strftime(local_time, sizeof(local_time),
               "Local Time: %H:%M:%S", p_tm);
      p_title = "The Time";
    }
              
    output.Body()->Printf
    (
      "<html>\n"
      "<head>\n"
      "  <title>%s</title>\n"
      "</head>\n"
      "<body>\n"
      "  <h1>%s</h1>\n"
      "  <p>%s</p>\n"
      "  <p>%s</p>\n"
      "</body>\n"
      "</html>\n"
      "\n",
      p_title, p_title, gmt_time, local_time
    ); 
#else // No clock supported.
    p_req->Respond(HTTPD_RESP_SRV_ERROR);
#endif

    return (true);
  }

  return (false);
}

//***********************************************************************

//---------------------------------------------------------------------------
//
// NAME:           failure
//
// DESCRIPTION:    Handle a fatal error.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
static void failure(const char *p_file, int line,const char *p_msg)
{
  assert(p_file != NULL);
  assert(line   >  0);
  assert(p_msg  != NULL);
  
  fprintf(stderr, "%s:%d Call to %s failed\n", p_file, line, p_msg);
  exit(EXIT_FAILURE);
}

//---------------------------------------------------------------------------
//
// NAME:           Initialize_The_Web_Server
//
// DESCRIPTION:    Start and configure Seminole.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
static void Initialize_The_Web_Server()
{
  //-------------------------------------------------------
  // Initialize the environment.
  //-------------------------------------------------------
  
  if (Httpd::Init() != 0)
    failure(__FILE__, __LINE__, "Httpd::Init()");
  
  //--------------------------------------------------------
  // Create the webserver instance.  This just initializes
  // the object --- it doesn't start it up.
  //--------------------------------------------------------
    
  gpWebServer = new Httpd(gServername, gServerport);
  if (gpWebServer == NULL)
    failure(__FILE__, __LINE__, "Httpd::Httpd()");

  //---------------------------------------------------------
  // Install the Hello World handler as the root.
  //---------------------------------------------------------
  
  static DemoHelloWorldHandler hand("/");
  gpWebServer->Install(&hand);

  //-----------------------------------------------------------
  // Create and install the time handler, this one prints the 
  // time.
  //-----------------------------------------------------------
  
  static DemoTimeHandler time_hand("/time");
  gpWebServer->Install(&time_hand);
  
  //------------------------------------------------------------
  // Create and install a second time handler, this time it
  // prints out the date.
  //-------------------------------------------------------------
  
  static DemoTimeHandler date_hand("/date", true);
  gpWebServer->Install(&date_hand);

  printf("Server started on host %s port %d\n", gServername, gServerport);
}

//---------------------------------------------------------------------------
//
// NAME:           main
//
// DESCRIPTION:    Entry point for the demo.
//
// AUTHOR:         S. Conner
// CREATED:        Mar  6, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
int main(int argc, const char *const *argv)
{
  char buf[4];

  Initialize_The_Web_Server();
  gpWebServer->Start();
  
  printf("Press <ENTER> to stop.\n");
  fgets(buf, sizeof(buf), stdin);
  
#if HTTPD_INC_SHUTDOWN
  gpWebServer->Stop(HARD);
#endif

  return (EXIT_SUCCESS);
}
