/* Copyright (C) 2014 InfiniDB, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; version 2 of
   the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA. */

/*******************************************************************************
 * $Id: colxml.cpp 2237 2013-05-05 23:42:37Z dcathey $
 *
 ******************************************************************************/

#include <clocale>

#include <libxml/xmlwriter.h>

#include <boost/filesystem.hpp>

#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <vector>
#include "calpontsystemcatalog.h"
#include "inputmgr.h"
#include "we_xmlgenproc.h"
#include "we_config.h"
#include "dbrm.h"

using namespace std;
using namespace bulkloadxml;

int main(int argc, char** argv)
{
  const int DEBUG_LVL_TO_DUMP_SYSCAT_RPT = 4;
  // set effective ID to root
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");
  WriteEngine::Config::initConfigCache();  // load Columnstore.xml config settings

  // Bug 6137
  std::string aBulkRoot = WriteEngine::Config::getBulkRoot();

  if (!aBulkRoot.empty())
  {
    if (!boost::filesystem::exists(aBulkRoot.c_str()))
    {
      cout << "Creating directory : " << aBulkRoot << endl;
      boost::filesystem::create_directories(aBulkRoot.c_str());
    }

    if (boost::filesystem::exists(aBulkRoot.c_str()))
    {
      std::ostringstream aSS;
      aSS << aBulkRoot;
      aSS << "/job";
      std::string jobDir = aSS.str();

      if (!boost::filesystem::exists(jobDir.c_str()))
      {
        cout << "Creating directory : " << jobDir << endl;
        bool aSuccess = boost::filesystem::create_directories(jobDir.c_str());

        if (!aSuccess)
        {
          cout << "\nFailed to create job directory, please check permissions\n" << endl;
          return -1;
        }
      }
    }
    else
    {
      cout << "\nFailed to create bulk directory, check for permissions\n" << endl;
      return -1;
    }
  }
  else
  {
    cout << "\nBulkRoot is empty in config file. Failed to create job file.\n\n";
    return -1;
  }

  InputMgr mgr("299");  //@bug 391

  if (!mgr.input(argc, argv))
    return 1;

  int debugLevel = atoi(mgr.getParm(WriteEngine::XMLGenData::RPT_DEBUG).c_str());

  bool bUseLogFile = true;
  bool bSysCatRpt = false;

  if (debugLevel == DEBUG_LVL_TO_DUMP_SYSCAT_RPT)
  {
    cout << "\nRunning colxml to dump system catalog report:\n\n";
    bUseLogFile = false;
    bSysCatRpt = true;
  }
  else
  {
    cout << "\nRunning colxml with the following parameters:\n";
  }

  WriteEngine::XMLGenProc curJob(&mgr, bUseLogFile, bSysCatRpt);

  if (debugLevel > 0 && debugLevel <= 3)
  {
    curJob.setDebugLevel(debugLevel);
    cout << "\nDebug level is set to " << debugLevel << endl;
  }

  BRM::DBRM dbrm;

  if (dbrm.getSystemReady() < 1)
  {
    std::string errMsg(
        "System is not ready.  Verify that ColumnStore is up and ready "
        "before running colxml.");

    if (bUseLogFile)
      curJob.logErrorMessage(errMsg);
    else
      cout << errMsg << endl;

    return 1;
  }

  bool rc = false;

  const WriteEngine::XMLGenData::TableList& tables = mgr.getTables();

  try
  {
    if (tables.empty())
      mgr.loadCatalogTables();

    if (tables.empty())
    {
      string msg =
          "Either schema name is invalid or no table "
          "is in the schema.";
      curJob.logErrorMessage(msg);
    }
    else
    {
      curJob.startXMLFile();

      for (InputMgr::TableList::const_iterator tbl = tables.begin(); tbl != tables.end(); ++tbl)
      {
        curJob.makeTableData(*tbl);
        rc = curJob.makeColumnData(*tbl);

        if (!rc)
          cout << "No columns for " << tbl->table << endl;
      }
    }
  }
  catch (runtime_error& ex)
  {
    curJob.logErrorMessage(string("colxml runtime exception: ") + ex.what());
    cout << curJob.errorString() << endl;
    return 1;
  }
  catch (exception& ex)
  {
    curJob.logErrorMessage(string("colxml exception: ") + ex.what());
    cout << curJob.errorString() << endl;
    return 1;
  }
  catch (...)
  {
    curJob.logErrorMessage(string("colxml unknown exception "));
    cout << curJob.errorString() << endl;
    return 1;
  }

  if (rc)
  {
    if (debugLevel == DEBUG_LVL_TO_DUMP_SYSCAT_RPT)
    {
      std::string xmlFileName("-");
      curJob.writeXMLFile(xmlFileName);
      cout << "\nDump completed for tables:\n\t";
    }
    else
    {
      std::string xmlFileName = curJob.genJobXMLFileName();
      cout << "Creating job description file: " << xmlFileName << endl;
      curJob.writeXMLFile(xmlFileName);
      cout << "File completed for tables:\n\t";
    }

    copy(tables.begin(), tables.end(),
         ostream_iterator<execplan::CalpontSystemCatalog::TableName>(cout, "\n\t"));
    cout << "\nNormal exit.\n";
  }
  else
  {
    cout << "File not made.\n";
    cout << curJob.errorString();
    return 1;
  }

  return 0;
}
