/*
   spacemaze - Fly a space ship through a maze and collect all the items.
   Copyright (C) 2000, 2001, 2002 John Ericson 

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

   2000-03-25 High / John Ericson john.ericson@home.se
*/

#include "campaign.h"

void CampaignStartDocument(campaign_s *campaign);
void CampaignEndDocument(campaign_s *campaign);
void CampaignCharacters(campaign_s *campaign, const xmlChar *ch, int len);
void CampaignStartElement(campaign_s *campaign, const xmlChar *name, const xmlChar **attrs);
void CampaignEndElement(campaign_s *campaign, const xmlChar *name);
void CampaignWarning(campaign_s *campaign, const char *msg, ...);
void CampaignError(campaign_s *campaign, const char *msg, ...);
void CampaignFatalError(campaign_s *campaign, const char *msg, ...);

static xmlSAXHandler CampaignSAXParser = {
   0, /* internalSubset */
   0, /* isStandalone */
   0, /* hasInternalSubset */
   0, /* hasExternalSubset */
   0, /* resolveEntity */
   0, /* getEntity */
   0, /* entityDecl */
   0, /* notationDecl */
   0, /* attributeDecl */
   0, /* elementDecl */
   0, /* unparsedEntityDecl */
   0, /* setDocumentLocator */
   (startDocumentSAXFunc) CampaignStartDocument, /* startDocument */
   (endDocumentSAXFunc) CampaignEndDocument, /* endDocument */
   (startElementSAXFunc) CampaignStartElement, /* startElement */
   (endElementSAXFunc) CampaignEndElement, /* endElement */
   0, /* reference */
   (charactersSAXFunc) CampaignCharacters, /* characters */
   0, /* ignorableWhitespace */
   0, /* processingInstruction */
   0, /* comment */
   (warningSAXFunc) CampaignWarning, /* warning */
   (errorSAXFunc) CampaignError, /* error */
   (fatalErrorSAXFunc) CampaignFatalError, /* fatalError */
};

static campaign_state_s state;

/* Used to buffer input from the characters callback */
static char ch_buffer[1024];
static int  ch_buffer_len;

int LoadCampaign(campaign_s *campaign, const char *filename) {
   int ret = 0;
   xmlParserCtxtPtr ctxt;

   ctxt = xmlCreateFileParserCtxt(filename);
   if (ctxt == NULL) return -1;
   ctxt->sax = &CampaignSAXParser;
   ctxt->userData = campaign;

   xmlParseDocument(ctxt);

   if (ctxt->wellFormed)
      ret = 0;
   else
      ret = -1;
   if (&CampaignSAXParser != NULL)
      ctxt->sax = NULL;
   xmlFreeParserCtxt(ctxt);

   return ret;
}

void CampaignStartDocument(campaign_s *campaign) {
   int i;

   /* Clean out the variable */
   strcpy(campaign->name, "(Noname)");
   strcpy(campaign->version, "(Noversion)");
   campaign->maxplayers = 1;
   campaign->numlevels = 0;

   /* Clean out the levels array */
   for (i = 0; i < MAXLEVELSINCAMPAIGN; i++) {
      strcpy(campaign->levels[i].filename, "");
   }

   state = CAMPAIGN_START;
}

void CampaignEndDocument(campaign_s *campaign) {
   /*
   Since we increase the element everytime we leave them (CampaignEndElement), 
   we have to decrease all one step at the end of the document parsing to get
   the right size.
   */

   /* Mark the end of the levels array with an empty string */
   strcpy(campaign->levels[campaign->numlevels+1].filename, "");

   campaign->numlevels--;
}

void CampaignCharacters(campaign_s *campaign, const xmlChar *ch, int len) {
   /*
   An XML parser isn't guaranteed to return the entire contents of a tag in a
   characters callback therefor we use a buffer to bundle it all togehter and
   process the string in the call to end_element.
   */

   char output[40];
    int i;

   /* Copy ch to output */
   for (i = 0; (i < len) && (i < 30);i++)
      output[i] = ch[i];

   /* Put an NULL at the end */
   output[i] = 0;

   strcat(ch_buffer, output);
   ch_buffer_len += len;
}

void CampaignStartElement(campaign_s *campaign, const xmlChar *name, const xmlChar **attrs) {

   if (strcmp(name, "Campaign") == 0) {
      state += CAMPAIGN_CAMPAIGN;

      /* Start parsing attrib line if there is any attribs */
      /* This code could be generalized since its useful on several places */
      if (attrs != NULL)
         if (strcmp(attrs[0], "version") == 0)
            strcpy(campaign->version, attrs[1]);
         else
            printf("Unknown attribut %s in %s found. Ignoring.\n", attrs[1], name);
   }
   else if (strcmp(name, "Info") == 0) state += CAMPAIGN_INFO;
   else if (strcmp(name, "Name") == 0) state += CAMPAIGN_NAME;
   else if (strcmp(name, "Author") == 0) state += CAMPAIGN_AUTHOR;
   else if (strcmp(name, "Description") == 0) state += CAMPAIGN_DESCRIPTION;
   else if (strcmp(name, "Gametype") == 0) state += CAMPAIGN_GAMETYPE;
   else if (strcmp(name, "Levels") == 0) state += CAMPAIGN_LEVELS;
   else if (strcmp(name, "LevelFile") == 0) {
      state += CAMPAIGN_LEVELFILE;

      if (attrs != NULL)
         if (strcmp(attrs[0], "file") == 0)
            strcpy(campaign->levels[campaign->numlevels++].filename, attrs[1]);
         else
            printf("Unknown attribut %s in %s found. Ignoring.\n", attrs[1], name);
   }
   else
      printf("Unknown Element <%s> found. Ignoring.\n", name);
}

void CampaignEndElement(campaign_s *campaign, const xmlChar *name) {

   char *output;

   ch_buffer[ch_buffer_len] = 0;

   output = trim(ch_buffer);
   strcpy(ch_buffer, output);


   switch (state) {
   case (CAMPAIGN_CAMPAIGN + CAMPAIGN_INFO + CAMPAIGN_NAME):
      strcpy(campaign->name, ch_buffer);
      break;
   case (CAMPAIGN_CAMPAIGN + CAMPAIGN_INFO + CAMPAIGN_AUTHOR):
   case (CAMPAIGN_CAMPAIGN + CAMPAIGN_INFO + CAMPAIGN_DESCRIPTION):
   case (CAMPAIGN_CAMPAIGN + CAMPAIGN_INFO + CAMPAIGN_GAMETYPE):
      /* Info we dont use at the moment */
      break;
   /*
   case (CAMPAIGN_CAMPAIGN + CAMPAIGN_LEVELS + CAMPAIGN_LEVELFILE):
      /* Why cant I use strtof? */
   /* strcpy(campaign->levels[campaign->numlevels].filename, ch_buffer);
      break;
   */
   }

   /* Reset characters buffer */
   ch_buffer[0] = 0;
   ch_buffer_len = 0;


   if (strcmp(name, "Campaign") == 0) state -= CAMPAIGN_CAMPAIGN;
   else if (strcmp(name, "Info") == 0) state -= CAMPAIGN_INFO;
   else if (strcmp(name, "Name") == 0) state -= CAMPAIGN_NAME;
   else if (strcmp(name, "Author") == 0) state -= CAMPAIGN_AUTHOR;
   else if (strcmp(name, "Description") == 0) state -= CAMPAIGN_DESCRIPTION;
   else if (strcmp(name, "Gametype") == 0) state -= CAMPAIGN_GAMETYPE;
   else if (strcmp(name, "Levels") == 0) state -= CAMPAIGN_LEVELS;
   else if (strcmp(name, "LevelFile") == 0) state -= CAMPAIGN_LEVELFILE;

}

void CampaignWarning(campaign_s *campaign, const char *msg, ...) {
   va_list args;
   char buffer[255];

   strcpy(buffer, "Loading campaign warning: ");

   va_start(args, msg);
   vsprintf(&buffer[strlen(buffer)], msg, args);

   printf("%s", buffer);
   va_end(args);
}

void CampaignError(campaign_s *campaign, const char *msg, ...) {
   va_list args;
   char buffer[255];

   strcpy(buffer, "Loading campaign error: ");

   va_start(args, msg);
   vsprintf(&buffer[strlen(buffer)], msg, args);

   printf("%s", buffer);
   va_end(args);
}

void CampaignFatalError(campaign_s *campaign, const char *msg, ...) {
   va_list args;
   char buffer[255];

   strcpy(buffer, "Loading campaign fatal error: ");

   va_start(args, msg);
   vsprintf(&buffer[strlen(buffer)], msg, args);

   printf("%s", buffer);
   va_end(args);
}