/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium

  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
#include "../cmCacheManager.h"
#include "../cmSystemTools.h"
#include "../cmake.h"
#include "../cmDocumentation.h"

#include <signal.h>
#include <sys/ioctl.h>

#include "cmCursesMainForm.h"
#include "cmCursesStandardIncludes.h"
#include <cmsys/Encoding.hxx>

#include <form.h>

//----------------------------------------------------------------------------
static const char * cmDocumentationName[][2] =
{
  {0,
   "  ccmake - Curses Interface for CMake."},
  {0,0}
};

//----------------------------------------------------------------------------
static const char * cmDocumentationUsage[][2] =
{
  {0,
   "  ccmake <path-to-source>\n"
   "  ccmake <path-to-existing-build>"},
  {0,0}
};

//----------------------------------------------------------------------------
static const char * cmDocumentationOptions[][2] =
{
  CMAKE_STANDARD_OPTIONS_TABLE,
  {0,0}
};

cmCursesForm* cmCursesForm::CurrentForm=0;

extern "C"
{

void onsig(int)
{
  if (cmCursesForm::CurrentForm)
    {
    endwin();
    initscr(); /* Initialization */
    noecho(); /* Echo off */
    cbreak(); /* nl- or cr not needed */
    keypad(stdscr,TRUE); /* Use key symbols as
                            KEY_DOWN*/
    refresh();
    int x,y;
    getmaxyx(stdscr, y, x);
    cmCursesForm::CurrentForm->Render(1,1,x,y);
    cmCursesForm::CurrentForm->UpdateStatusBar();
    }
  signal(SIGWINCH, onsig);
}

}

void CMakeErrorHandler(const char* message, const char* title, bool&, void* clientData)
{
  cmCursesForm* self = static_cast<cmCursesForm*>( clientData );
  self->AddError(message, title);
}

int main(int argc, char const* const* argv)
{
  cmsys::Encoding::CommandLineArguments encoding_args =
    cmsys::Encoding::CommandLineArguments::Main(argc, argv);
  argc = encoding_args.argc();
  argv = encoding_args.argv();

  cmSystemTools::FindCMakeResources(argv[0]);
  cmDocumentation doc;
  doc.addCMakeStandardDocSections();
  if(doc.CheckOptions(argc, argv))
    {
    cmake hcm;
    hcm.AddCMakePaths();
    std::vector<cmDocumentationEntry> generators;
    hcm.GetGeneratorDocumentation(generators);
    doc.SetName("ccmake");
    doc.SetSection("Name",cmDocumentationName);
    doc.SetSection("Usage",cmDocumentationUsage);
    doc.SetSection("Generators",generators);
    doc.PrependSection("Options",cmDocumentationOptions);
    return doc.PrintRequestedDocumentation(std::cout)? 0:1;
    }

  bool debug = false;
  unsigned int i;
  int j;
  std::vector<std::string> args;
  for(j =0; j < argc; ++j)
    {
    if(strcmp(argv[j], "-debug") == 0)
      {
      debug = true;
      }
    else
      {
      args.push_back(argv[j]);
      }
    }

  std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
  for(i=1; i < args.size(); ++i)
    {
    std::string arg = args[i];
    if(arg.find("-B",0) == 0)
      {
      cacheDir = arg.substr(2);
      }
    }

  cmSystemTools::DisableRunCommandOutput();

  if (debug)
    {
    cmCursesForm::DebugStart();
    }

  initscr(); /* Initialization */
  noecho(); /* Echo off */
  cbreak(); /* nl- or cr not needed */
  keypad(stdscr,TRUE); /* Use key symbols as
                          KEY_DOWN*/

  signal(SIGWINCH, onsig);

  int x,y;
  getmaxyx(stdscr, y, x);
  if ( x < cmCursesMainForm::MIN_WIDTH  ||
       y < cmCursesMainForm::MIN_HEIGHT )
    {
    endwin();
    std::cerr << "Window is too small. A size of at least "
              << cmCursesMainForm::MIN_WIDTH << " x "
              <<  cmCursesMainForm::MIN_HEIGHT
              << " is required to run ccmake." <<  std::endl;
    return 1;
    }


  cmCursesMainForm* myform;

  myform = new cmCursesMainForm(args, x);
  if(myform->LoadCache(cacheDir.c_str()))
    {
    curses_clear();
    touchwin(stdscr);
    endwin();
    delete myform;
    std::cerr << "Error running cmake::LoadCache().  Aborting.\n";
    return 1;
    }

  cmSystemTools::SetErrorCallback(CMakeErrorHandler, myform);

  cmCursesForm::CurrentForm = myform;

  myform->InitializeUI();
  if ( myform->Configure(1) == 0 )
    {
    myform->Render(1, 1, x, y);
    myform->HandleInput();
    }

  // Need to clean-up better
  curses_clear();
  touchwin(stdscr);
  endwin();
  delete cmCursesForm::CurrentForm;
  cmCursesForm::CurrentForm = 0;

  std::cout << std::endl << std::endl;

  return 0;

}
