// -------------------------------------------------------------------------
//  Includes
// -------------------------------------------------------------------------
#include <util/PlatformUtils.hpp>
#include <util/XMLString.hpp>
#include <util/XMLUniDefs.hpp>
#include <util/TranscodingException.hpp>

#include <dom/DOM_DOMException.hpp>

#include <parsers/DOMParser.hpp>
#include <dom/DOM.hpp>
#include <string.h>
#include <stdlib.h>
#include <fstream.h>



//******************************************************
// Error Handler Code, taken almost intact from DOMCount
//********************************************************
#include <sax/ErrorHandler.hpp>
#include <sax/SAXParseException.hpp>

class SAXParseException;

// ---------------------------------------------------------------------------
//  Simple error handler deriviative to install on parser
// ---------------------------------------------------------------------------
class DOMCommonErrorHandler : public ErrorHandler
{
public:
    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    DOMCommonErrorHandler();
    ~DOMCommonErrorHandler();


    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    bool getSawErrors() const;


    // -----------------------------------------------------------------------
    //  Implementation of the SAX ErrorHandler interface
    // -----------------------------------------------------------------------
    void warning(const SAXParseException& e);
    void error(const SAXParseException& e);
    void fatalError(const SAXParseException& e);
    void resetErrors();


private :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    DOMCommonErrorHandler(const DOMCommonErrorHandler&);
    void operator=(const DOMCommonErrorHandler&);


    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fSawErrors
    //      This is set if we get any errors, and is queryable via a getter
    //      method. Its used by the main code to suppress output if there are
    //      errors.
    // -----------------------------------------------------------------------
    bool    fSawErrors;
};


// ---------------------------------------------------------------------------
//  This is a simple class that lets us do easy (though not terribly efficient)
//  trancoding of XMLCh data to local code page for display.
// ---------------------------------------------------------------------------
class StrX
{
public :
    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    StrX(const XMLCh* const toTranscode)
    {
        // Call the private transcoding method
        fLocalForm = XMLString::transcode(toTranscode);
    }

    ~StrX()
    {
        delete [] fLocalForm;
    }


    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    const char* localForm() const
    {
        return fLocalForm;
    }

private :
    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fLocalForm
    //      This is the local code page form of the string.
    // -----------------------------------------------------------------------
    char*   fLocalForm;
};

inline ostream& operator<<(ostream& target, const StrX& toDump)
{
    target << toDump.localForm();
    return target;
}

inline bool DOMCommonErrorHandler::getSawErrors() const
{
    return fSawErrors;
}



DOMCommonErrorHandler::DOMCommonErrorHandler() :

    fSawErrors(false)
{
}

DOMCommonErrorHandler::~DOMCommonErrorHandler()
{
}


// ---------------------------------------------------------------------------
//  DOMCountHandlers: Overrides of the SAX ErrorHandler interface
// ---------------------------------------------------------------------------
void DOMCommonErrorHandler::error(const SAXParseException& e)
{
    fSawErrors = true;
    cerr << "\nError at file " << StrX(e.getSystemId())
         << ", line " << e.getLineNumber()
         << ", char " << e.getColumnNumber()
         << "\n  Message: " << StrX(e.getMessage()) << endl;
}

void DOMCommonErrorHandler::fatalError(const SAXParseException& e)
{
    fSawErrors = true;
    cerr << "\nFatal Error at file " << StrX(e.getSystemId())
         << ", line " << e.getLineNumber()
         << ", char " << e.getColumnNumber()
         << "\n  Message: " << StrX(e.getMessage()) << endl;
}

void DOMCommonErrorHandler::warning(const SAXParseException& e)
{
    cerr << "\nWarning at file " << StrX(e.getSystemId())
         << ", line " << e.getLineNumber()
         << ", char " << e.getColumnNumber()
         << "\n  Message: " << StrX(e.getMessage()) << endl;
}

void DOMCommonErrorHandler::resetErrors()
{
    fSawErrors = false;
}





// -----------------------------------------------------------------------
//  Global Variables
// -----------------------------------------------------------------------
static char*                    gXmlFile               = 0;
static char*                    gXmlSkeleton           = 0;
static char*                    gXmlMap                = 0;
static bool                     gDoNamespaces          = false;
static bool                     gDoSchema              = false;
static bool                     gSchemaFullChecking    = false;
static bool                     gDoCreate              = false;
static DOMParser::ValSchemes    gValScheme             = DOMParser::Val_Auto;

// Return code
int retval = 0;

// Error check variable
bool errorsOccured = false;


// ---------------------------------------------------------------------------
//  Function declaration
// ---------------------------------------------------------------------------
void     usage(char*);
DOM_Document cargaDocXML (char* archivo);


// ------------------------------------------------------------------------
//  About...
//  Simply do $>executable_name xmlfile1 xmlfile2 xmlfile3
// ------------------------------------------------------------------------
void usage(char* exec)
{
    cout << "   *************************************************** \n";
    cout << "   **  Libra/Minerva XML Almacenator,               **\n";
    cout << "   *************************************************** \n";
    cout << " Este programa almacena en BBDD los ficheros de datos en XML generados\n";
    cout << "por una Itineracion Telematica.\n\n";
    cout << " Uso:  " << exec;
    cout << " [opciones] <Archivo XML> <Esqueleto XML> <Mapeo XML>\n";
    cout << " Opciones: (* marca opcion por defecto)\n"
		 << "    -?         Esta ayuda.\n\n"
         << " Además de UTF-8, el parser soporta los siguientes tipos de codificacion:\n"
         << "  USASCII, ISO8859-1(*), UTF-16[BL]E, UCS-4[BL]E, WINDOWS-1252, IBM1140, IBM037\n";
}



// ---------------------------------------------------------------------------
// main
// ---------------------------------------------------------------------------
int main(int argC, char* argV[])
{

    // Xerces Init
    try
    {
        XMLPlatformUtils::Initialize();
    }

    catch(const XMLException& toCatch)
    {
        cerr << "Error durante la inicialización de Xerces-C.\n"
             << "  Mensaje de error:"
             << toCatch.getMessage() << endl;
        return 1;
    }
	{

		if (argC < 2)
		{
			usage(argV[0]);
			XMLPlatformUtils::Terminate();
			return 2;
		}

		int parmInd;
		for (parmInd = 1; parmInd < argC; parmInd++)
		{
			if (argV[parmInd][0] != '-')
				break;
			if (!strcmp(argV[parmInd], "-?"))
			{
				usage(argV[0]);
				XMLPlatformUtils::Terminate();
				return 2;
			}
			 else if (!strcmp(argV[parmInd], "-n")
				  ||  !strcmp(argV[parmInd], "-N"))
			{
				gDoNamespaces = true;
			}
			 else if (!strcmp(argV[parmInd], "-s")
				  ||  !strcmp(argV[parmInd], "-S"))
			{
				gDoSchema = true;
			}
			 else if (!strcmp(argV[parmInd], "-f")
				  ||  !strcmp(argV[parmInd], "-F"))
			{
				gSchemaFullChecking = true;
			}
			 else if (!strcmp(argV[parmInd], "-e")
				  ||  !strcmp(argV[parmInd], "-E"))
			{
				gDoCreate = true;
			}
			 else
			{
				cerr << "Opcion no reconocida '" << argV[parmInd]
					 << "'. Opcion ignorada.\n" << endl;
			}
		}

		// file reading
		if (parmInd + 3 != argC)
		{
			usage(argV[0]);
			XMLPlatformUtils::Terminate();
			return 2;
		}
		gXmlFile = argV[parmInd];
		gXmlSkeleton = argV[parmInd+1];
		gXmlMap = argV[parmInd+2];

		errorsOccured = false;

		// First doc parsing
		DOM_Document doc;
		doc = cargaDocXML (gXmlFile);
		
		// second
		DOM_Document docSkel;
		docSkel = cargaDocXML (gXmlSkeleton);

		// and last
		DOM_Document docMap;
		docMap = cargaDocXML (gXmlMap);

		// only for checking
		cout << " Parse Completed...\n";
	
	}
    // Xerces closing
    XMLPlatformUtils::Terminate();

	cout << " All Good!!  Retval=" << retval<< "\n";
	return retval;
}


DOM_Document cargaDocXML (char* archivo){

	// set up the parser
    DOMParser *parser = new DOMParser;
    parser->setValidationScheme(gValScheme);
    parser->setDoNamespaces(gDoNamespaces);
    parser->setDoSchema(gDoSchema);
    parser->setValidationSchemaFullChecking(gSchemaFullChecking);
    DOMCommonErrorHandler *errReporter = new DOMCommonErrorHandler();
    parser->setErrorHandler(errReporter);
    parser->setCreateEntityReferenceNodes(gDoCreate);
    parser->setToCreateXMLDeclTypeNode(true);

    try
    {
		// parsing
        parser->parse(archivo);
        int errorCount = parser->getErrorCount();
        if (errorCount > 0)
            errorsOccured = true;
    }
    // error code
	catch (const XMLException& e)
    {
        cerr << "Error XML durante la lectura del fichero.\n   Mensaje: "
             << e.getMessage() << endl;
        errorsOccured = true;
    }
    catch (const DOM_DOMException& e)
    {
       cerr << "Error DOM durante la lectura del fichero\n   Codigo de DOMException: "
             << e.code << endl;
        errorsOccured = true;
    }
    catch (...)
    {
        cerr << "Error desconocido durante la lectura del fichero\n " << endl;
        errorsOccured = true;
    }

    // returning and deleting data
	DOM_Document tmp = parser->getDocument();

    delete errReporter;
	delete parser;

	return tmp;
}

