/*
 * Copyright 2006 Sony Computer Entertainment Inc.
 *
 * Licensed under the MIT Open Source License, for details please see license.txt or the website
 * http://www.opensource.org/licenses/mit-license.php
 *
 */

#include <sstream>
#include <dae.h>
#include <dom.h>
#include <dae/daeDatabase.h>
#include <dae/daeIOPluginCommon.h>
#include <dae/daeMetaElement.h>
#include <dae/daeErrorHandler.h>
#include <dae/daeMetaElementAttribute.h>
#ifndef NO_ZAE
#include <dae/daeZAEUncompressHandler.h>
#endif

using namespace std;

daeIOPluginCommon::daeIOPluginCommon()
    : database(NULL),
    topMeta(NULL)
{
}

daeIOPluginCommon::~daeIOPluginCommon()
{
}

daeInt daeIOPluginCommon::setMeta(daeMetaElement *_topMeta)
{
    topMeta = _topMeta;
    return DAE_OK;
}

void daeIOPluginCommon::setDatabase(daeDatabase* _database)
{
    database = _database;
}

// This function needs to be re-entrant, it can be called recursively from inside of resolveAll
// to load files that the first file depends on.
daeInt daeIOPluginCommon::read(const daeURI& uri, daeString docBuffer)
{
    // Make sure topMeta has been set before proceeding
    if (topMeta == NULL)
    {
        return DAE_ERR_BACKEND_IO;
    }

    // Generate a version of the URI with the fragment removed
    daeURI fileURI(*uri.getDAE(), uri.str(), true);

    //check if document already exists
    if ( database->isDocumentLoaded( fileURI.getURI() ) )
    {
        return DAE_ERR_COLLECTION_ALREADY_EXISTS;
    }

    daeElementRef domObject = docBuffer ?
                              readFromMemory(docBuffer, fileURI) :
                              readFromFile(fileURI); // Load from URI

#ifdef NO_ZAE

    if (!domObject) {
        string msg = docBuffer ?
                     "Failed to load XML document from memory\n" :
                     string("Failed to load ") + fileURI.str() + "\n";
        daeErrorHandler::get()->handleError(msg.c_str());
        return DAE_ERR_BACKEND_IO;
    }

    // Insert the document into the database, the Database will keep a ref on the main dom, so it won't get deleted
    // until we clear the database

    daeDocument *document = NULL;

    int res = database->insertDocument(fileURI.getURI(),domObject,&document);
    if (res!= DAE_OK)
        return res;

#else

    bool zaeRoot = false;
    string extractedURI = "";
    if (!domObject) {
        daeZAEUncompressHandler zaeHandler(fileURI);
        if (zaeHandler.isZipFile())
        {
            string rootFilePath = zaeHandler.obtainRootFilePath();
            daeURI rootFileURI(*fileURI.getDAE(), cdom::nativePathToUri(rootFilePath));
            domObject = readFromFile(rootFileURI);
            if (!domObject)
            {
                string msg = string("Failed to load ") + fileURI.str() + "\n";
                daeErrorHandler::get()->handleError(msg.c_str());
                return DAE_ERR_BACKEND_IO;
            }
            zaeRoot = true;
            extractedURI = rootFileURI.str();
        }
        else
        {
            string msg = docBuffer ?
                         "Failed to load XML document from memory\n" :
                         string("Failed to load ") + fileURI.str() + "\n";
            daeErrorHandler::get()->handleError(msg.c_str());
            return DAE_ERR_BACKEND_IO;
        }
    }

    // Insert the document into the database, the Database will keep a ref on the main dom, so it won't get deleted
    // until we clear the database

    daeDocument *document = NULL;

    int res = database->insertDocument(fileURI.getURI(),domObject,&document, zaeRoot, extractedURI);
    if (res!= DAE_OK)
        return res;

#endif

    return DAE_OK;
}










daeElementRef daeIOPluginCommon::beginReadElement(daeElement* parentElement,
                                                  daeString elementName,
                                                  const vector<attrPair>& attributes,
                                                  daeInt lineNumber) {
    daeMetaElement* parentMeta = parentElement ? parentElement->getMeta() : topMeta;
    daeElementRef element = parentMeta->create(elementName);

    if(!element)
    {
        ostringstream msg;
        msg << "The DOM was unable to create an element named " << elementName << " at line "
            << lineNumber << ". Probably a schema violation.\n";
        daeErrorHandler::get()->handleWarning( msg.str().c_str() );
        return NULL;
    }

    // Process the attributes
    for (size_t i = 0; i < attributes.size(); i++) {
        daeString name  = attributes[i].first,
                  value = attributes[i].second;
        if (!element->setAttribute(name, value)) {
            ostringstream msg;
            msg << "The DOM was unable to create an attribute " << name << " = " << value
                << " at line " << lineNumber << ".\nProbably a schema violation.\n";
            daeErrorHandler::get()->handleWarning(msg.str().c_str());
        }
    }

    if (parentElement == NULL) {
        // This is the root element. Check the COLLADA version.
        daeURI *xmlns = (daeURI*)(element->getMeta()->getMetaAttribute( "xmlns" )->getWritableMemory( element ));
        if ( strcmp( xmlns->getURI(), element->getDAE()->getColladaNamespace() ) != 0 ) {
            // Invalid COLLADA version
            daeErrorHandler::get()->handleError("Trying to load an invalid COLLADA version for this DOM build!");
            return NULL;
        }
    }

    return element;
}

bool daeIOPluginCommon::readElementText(daeElement* element, daeString text, daeInt elementLineNumber) {
    if (element->setCharData(text))
        return true;

    ostringstream msg;
    msg << "The DOM was unable to set a value for element of type " << element->getTypeName()
        << " at line " << elementLineNumber << ".\nProbably a schema violation.\n";
    daeErrorHandler::get()->handleWarning(msg.str().c_str());
    return false;
}
