/**
 * This is part of an XML patch library.
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * Contact: Jari Urpalainen <jari.urpalainen@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * @date Created: Tue May 24 13:28:44 EEST 2005
 */

#include "config.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <ctype.h>
#include <unistd.h>

#include <libxml/tree.h>

#include "xml_patch.h"

static void usage()
{
    fprintf (stdout, "xml_patch [-v] -f doc -p patch-doc [-o output-doc]\n"
		     "       v == verbose output\n"
		     "       o == dumb output to document\n"
		     "returns 0 if succeeds, -1 for an error\n"
		     "version: %s\n", PACKAGE_VERSION);
}

/** patching, don't care about request namespaces */
static int
patch (xmlDocPtr doc, xmlNodePtr node)
{
    int rc = 0;

    if (!strcmp ((char*)node->name, "add"))
	rc = xml_patch_add (doc, node);
    else if (!strcmp ((char*)node->name, "replace"))
	rc = xml_patch_replace (doc, node);
    else if (!strcmp ((char*)node->name, "remove"))
	rc = xml_patch_remove (doc, node);
    else
	rc = -1;
    return rc;
}

/** main for xml-patching */
int
main(int argc, char *argv[])
{
    int opt, rc = -1, fPrint = 0, i = 1;
    const char *pcszDoc = NULL, *pcszPatch = NULL, *pcszOutput = NULL;
    xmlDocPtr doc, docPatch;
    xmlNodePtr node;

    while((opt = getopt (argc, argv, "vf:p:o:")) != -1) {
	switch (opt) {
	case ':':
	case 'h':
	case '?':
	    usage ();
	    return -1;

	case 'v':
	    fPrint = 1;
	    break;

	case 'f':
	    pcszDoc = optarg;
	    break;

	case 'p':
	    pcszPatch = optarg;
	    break;

	case 'o':
	    pcszOutput = optarg;
	    break;
	}
    }
    if (!pcszDoc || !pcszPatch) {
	usage();
	return -1;
    }
    /* do not prevent the creation of cdata nodes */
    doc = xmlParseFile (pcszDoc);
    docPatch = xmlParseFile (pcszPatch);

    node = xmlDocGetRootElement (docPatch);

    for (node = node ? node->children : NULL;
	 node; node = node->next) {

	if (node->type == XML_ELEMENT_NODE) {
	    if (fPrint) {
		fprintf (stdout, "%d. Patching document:\n", i);

		xmlDocDump (stdout, doc);
		fprintf (stdout, "\n%d. patch:\n", i++);
		xmlElemDump (stdout, docPatch, node);
	    }
	    rc = patch (doc, node);

	    if (fPrint) {
		fprintf (stdout, "\n%s.\n", rc ? "failed" : "succeeded");
		if (rc)
		    break;

		fprintf (stdout, "\nUpdated document:\n");
		xmlDocDump (stdout, doc);
		fprintf (stdout, "\n");
	    }
	    if (rc)
		break;
	}
    }
    if (pcszOutput)
	xmlSaveFile (pcszOutput, doc);

    xmlFreeDoc (doc);
    xmlFreeDoc (docPatch);

    xmlCleanupParser();

    if (fPrint)
	fprintf (stdout, "Patching %s\n", !rc ? "successful" : "failed");
    else if (rc)
	fprintf (stderr, "Patching %s\n", !rc ? "successful" : "failed");
    return rc;
}

