/*
* 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(), 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(), COLLADA_NAMESPACE ) != 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;
}
