//---------------------------------------------------------------------------
//
// 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:   Mar  5, 2004
//
//---------------------------------------------------------------------------
//
// HISTORY OF CHANGE  
//
// -----+--------+------------------------------------------+------+---------
// VERS | DATE   | DESCRIPTION OF CHANGE                    | INIT | PR#
// =====+========+==========================================+======+=========
//  001 |03/05/04| File creation.                           | SPC  |
// -----+--------+------------------------------------------+------+---------
//  002 |06/12/09| Const correctness.                       | RAH  |
// -----+--------+------------------------------------------+------+---------
//---------------------------------------------------------------------------

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "seminole.h"
#include "sem_template.h"

#include "sitedata.h"

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

class DemoHandler : public HttpdFileHandler
{
private:
  int  mHits;
  bool mIndexPage;
    
protected:
  bool TranslateUri(RequestState &state);
  void DoFile(RequestState &state);

public:
  DemoHandler(HttpdFileSystem *p_filesys,
              const char      *p_root,
              const char      *p_prefix);
};

class DemoSymbolTable : public HttpdSymbolTable
{
private:
  size_t mLoopCount;
  int    mHits;

public:
  DemoSymbolTable(int hits) 
    : mLoopCount(0), mHits(hits) 
    {}

  virtual int HandleEval(HttpdEvalCommand        *p_eval);
  virtual int HandleLoop(HttpdLoopCommand        *p_loop);
  virtual int HandleCond(HttpdConditionalCommand *p_cond);
};

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

static const char *const gLoopText[] =
{
  "one" , "two"   , "three" , "four" , "five" , 
  "six" , "seven" , "eight" , "nine" , "ten"
};

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

//---------------------------------------------------------------------------
//
// NAME:           DemoHandler::DemoHandler
//
// DESCRIPTION:    Construct the request handler.
//
// AUTHOR:         S. Conner
// CREATED:        Apr 13, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
DemoHandler::DemoHandler
 (
   HttpdFileSystem *p_filesys,
   const char      *p_root,
   const char      *p_prefix
 )
 : HttpdFileHandler(p_filesys, p_root, p_prefix),
   mHits(0)
{}

//---------------------------------------------------------------------------
//
// NAME:           DemoHandler::TranslateUri
//
// DESCRIPTION:    Handle URI translation.
//
// RETURNS:        True if the URI was translated, false otherwise.
//
// REMARKS:        This is an unconventional way to hook template
//                 processing into the file request handlers. It
//                 illustrates how the filesystem can be hidden and
//                 instead how the template engine can generate
//                 radically different content for the same file.
//
// AUTHOR:         S. Conner
// CREATED:        Apr 13, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
bool DemoHandler::TranslateUri(RequestState &state)
{
  //---------------------------------------------------------
  // everything is going to be fed through default.thtm, but
  // decode the URI since it will be used later
  //---------------------------------------------------------
  
  state.mpDecodedUri = HttpdUtilities::UriDecode(state.mpReqPath);
  state.mpFilePath   = HttpdUtilities::SaveString("/default.thtm");

  return ((state.mpDecodedUri != NULL) && (state.mpFilePath != NULL));
}

//---------------------------------------------------------------------------
//
// NAME:           DemoHandler::DoFile
//
// DESCRIPTION:    Handle file processing.
//
// REMARKS:        Since we always translate the URI to point to the same
//                 file we can avoid any further processing.
//
// AUTHOR:         S. Conner
// CREATED:        Apr 13, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
void DemoHandler::DoFile(RequestState &state)
{
  //----------------------------------------------------------------
  // this should always be true, but just in case ... 
  //----------------------------------------------------------------
  
  if (strcmp(state.mFileInfo.MimeType(), "x-server-internal/template") == 0)
  {
    DemoSymbolTable symbols(++mHits);
    (void )HttpdFSTemplateShell::Execute(state, &symbols);
  }
  else
    state.mpRequest->Respond(HTTPD_RESP_SRV_ERROR);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoSymbolTable::HandleEval
//
// DESCRIPTION:    Handle evaluation requests in our symbol table.
//
// RETURNS:        Status code.
//
// AUTHOR:         S. Conner
// CREATED:        Apr 13, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
int DemoSymbolTable::HandleEval(HttpdEvalCommand *p_eval)
{
  assert(p_eval != NULL);
  
  const char    *p_name   = p_eval->Name();
  HttpdWritable *p_output = p_eval->Output();
  
  if (strcmp(p_name, "evaltest") == 0)
    return (p_output->Printf("%s at %s (%d hits)",
                             __DATE__,
                             __TIME__,
                             mHits));
  else if (strcmp(p_name, "looptest") == 0)
    return (p_output->Printf("%s", gLoopText[mLoopCount]));
  else
    return (HTTPD_TEMPLATE_UNKNOWN_NAME);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoSymbolTable::HandleLoop
//
// DESCRIPTION:    Handle looping requests in our symbol table.
//
// RETURNS:        Status code.
//
// AUTHOR:         S. Conner
// CREATED:        Apr 13, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
int DemoSymbolTable::HandleLoop(HttpdLoopCommand *p_loop)
{
  assert(p_loop != NULL);
  
  if (strcmp(p_loop->Name(), "looptest") == 0)
  {
    for(mLoopCount = 0; mLoopCount < HTTPD_NUMELEM(gLoopText); mLoopCount++)
    {
      int rc;
      
      rc = p_loop->Iterate();
      if (rc != 0)
        return (rc);
    }

    return (0);
  }
  else
    return (HTTPD_TEMPLATE_UNKNOWN_NAME);
}

//---------------------------------------------------------------------------
//
// NAME:           DemoSymbolTable::HandleCond
//
// DESCRIPTION:    Handle conditional requests in our symbol table.
//
// RETURNS:        Status code.
//
// AUTHOR:         S. Conner
// CREATED:        Apr 13, 2004
// LAST MODIFIED:  N/A           BY:  N/A
//
//--------------------------------------------------------------------------
int DemoSymbolTable::HandleCond(HttpdConditionalCommand *p_cond)
{
  assert(p_cond != NULL);

  const char *p_name = p_cond->Name();
  
  if (strcmp(p_name, "even") == 0)
    return (ReturnBool((mHits % 2) == 0));
  else if (strcmp(p_name, "first") == 0)
    return (ReturnBool(mHits == 1));
  else if (strcmp(p_name, "two") == 0)
    return (ReturnBool((mHits % 2) == 0));
  else if (strcmp(p_name, "three") == 0)
    return (ReturnBool((mHits % 3) == 0));
  else if (strcmp(p_name, "five") == 0)
    return (ReturnBool((mHits % 5) == 0));
  else
    return (HTTPD_TEMPLATE_UNKNOWN_NAME); 
}

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

//---------------------------------------------------------------------------
//
// 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()");

  static HttpdMemoryDataSource builtin(SemWeb, sizeof(SemWeb));
  static HttpdRomFileSystem    romfs;
  if (romfs.Mount(&builtin) != 0)
    failure(__FILE__, __LINE__, "HttpdRomFileSystem::Mount()");
    
  static DemoHandler hand(&romfs, "/", "/");
  gpWebServer->Install(&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);
}
