//
// writes xml tree format from internal objects
//


#include "plugin.h"

char *str_append_token(char *str1, const char *str2)
{
  char *str;
  if(str1 != NULL)
  {
    str = new char[strlen(str1)+strlen(str2)+2];
    sprintf(str, "%s %s", str1, str2);
    delete [] str1;
  }
  else
  {
    str = new char[strlen(str2)+1];
    strcpy(str, str2);
  }
  return str;
}

void str_from_float(char *buf, float f)
{
  if(f == (int)f) sprintf(buf, "%i", (int)f);
  else  sprintf(buf, "%f", f);
}

void Patch_XMLWrite(patchMesh_t *pPatch, xmlNodePtr surface)
{
  char buf[16];
  char *str;
  int i, j;
  xmlNodePtr node;

  // write shader
  node = xmlNewChild(surface, NULL, (xmlChar *)"shader", (xmlChar *)pPatch->pShader->getName());

  // write matrix
  str = NULL;
  for(i=0; i<pPatch->width; i++)
  {
    for(j=0; j<pPatch->height; j++)
    {
      str_from_float(buf, pPatch->ctrl[i][j].xyz[0]);
      str = str_append_token(str, buf);
      str_from_float(buf, pPatch->ctrl[i][j].xyz[1]);
      str = str_append_token(str, buf);
      str_from_float(buf, pPatch->ctrl[i][j].xyz[2]);
      str = str_append_token(str, buf);
      str_from_float(buf, pPatch->ctrl[i][j].st[0]);
      str = str_append_token(str, buf);
      str_from_float(buf, pPatch->ctrl[i][j].st[1]);
      str = str_append_token(str, buf);
    }
  }

  node = xmlNewChild(surface, NULL, (xmlChar *)"matrix", (xmlChar *)str);
  delete [] str;
  sprintf(buf, "%i", pPatch->width);
  xmlSetProp(node, (xmlChar *)"width", (xmlChar *)buf);
  sprintf(buf, "%i", pPatch->height);
  xmlSetProp(node, (xmlChar *)"height", (xmlChar *)buf);
}

void Face_XMLWrite (face_t *face, xmlNodePtr surface, bool bAlternateTexdef = false)
{
  char buf[16];
  xmlNodePtr node;
  int i, j;
  char *str;
 
  // write shader
  node = xmlNewChild(surface, NULL, (xmlChar *)"shader", (xmlChar *)face->texdef.GetName());

  // write planepts
  str = NULL;
  for (i=0 ; i<3 ; i++)
	{
		for (j=0 ; j<3 ; j++)
		{
      str_from_float(buf, face->planepts[i][j]);
      str = str_append_token(str, buf);
		}
  }

  node = xmlNewChild(surface, NULL, (xmlChar *)"planepts", (xmlChar *)str);
  delete [] str;

  if(!bAlternateTexdef)
  {
    // write texdef
    sprintf(buf, "%i", (int)face->texdef.shift[0]);
    str = str_append_token(NULL, buf);
    sprintf(buf, "%i", (int)face->texdef.shift[1]);
    str = str_append_token(str, buf);
    sprintf(buf, "%i", (int)face->texdef.rotate);
    str = str_append_token(str, buf);
    sprintf(buf, "%f", face->texdef.scale[0]);
    str = str_append_token(str, buf);
    sprintf(buf, "%f", face->texdef.scale[1]);
    str = str_append_token(str, buf);

    node = xmlNewChild(surface, NULL, (xmlChar *)"texdef", (xmlChar *)str);
    delete [] str;
  }
  else
  {
    // write matrix texdef
    str = NULL;
    for (i=0 ; i<2 ; i++)
	  {
		  for (j=0 ; j<3 ; j++)
		  {
        str_from_float(buf, face->brushprimit_texdef.coords[i][j]);
        str = str_append_token(str, buf);
		  }
    }
    node = xmlNewChild(surface, NULL, (xmlChar *)"bpmatrix", (xmlChar *)str);
    delete [] str;
  }

  // write flags
  sprintf(buf, "%i", face->texdef.contents);
  str = str_append_token(NULL, buf);
  sprintf(buf, "%i", face->texdef.flags);
  str = str_append_token(str, buf);
  sprintf(buf, "%i", face->texdef.value);
  str = str_append_token(str, buf);

  node = xmlNewChild(surface, NULL, (xmlChar *)"flags", (xmlChar *)str);
  delete [] str;
}

void Brush_XMLWrite (brush_t *brush, xmlNodePtr primitive)
{
  xmlNodePtr node;

  for(face_t *face = brush->brush_faces; face != NULL; face = face->next)
  {
    node = xmlNewChild(primitive, NULL, (xmlChar *)"plane", NULL);
    Face_XMLWrite (face, node, brush->bBrushDef);
  }
}

void Epair_XMLWrite(epair_t *pEpair, xmlNodePtr epair)
{
  xmlSetProp(epair, (xmlChar *)"key", (xmlChar *)pEpair->key);
  xmlSetProp(epair, (xmlChar *)"value", (xmlChar *)pEpair->value);
}

void Entity_XMLWrite(entity_t *pEntity, xmlNodePtr entity)
{
  brush_t *pBrush;
  epair_t *pEpair;
  xmlNodePtr node;

  CPtrArray *brushes = (CPtrArray*)pEntity->pData;
 
  for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next)
  {
    node = xmlNewChild(entity, NULL, (xmlChar *)"epair", NULL);
    Epair_XMLWrite(pEpair, node);
  }

  for(int i=0; i<brushes->GetSize(); i++)
  {
    pBrush = (brush_t*)brushes->GetAt(i);

    if(pBrush->patchBrush)
    {
      node = xmlNewChild(entity, NULL, (xmlChar *)"patch", NULL);
      Patch_XMLWrite(pBrush->pPatch, node);
    }
    else
    {
      node = xmlNewChild(entity, NULL, (xmlChar *)"brush", NULL);
      Brush_XMLWrite(pBrush, node);
    }
  }
}

void Map_XMLWrite (CPtrArray *map, xmlNodePtr map_node)
{
  entity_t *pEntity;
  xmlNodePtr node;

  for(int i=0; i<map->GetSize(); i++)
  {
    pEntity = (entity_t*)map->GetAt(i);

    node = xmlNewChild(map_node, NULL, (xmlChar *)"entity", NULL);
    Entity_XMLWrite(pEntity, node);
  }
}

void Map_Write (CPtrArray *map, IDataStream *out)
{
  xmlChar* buf;
  int len;
  
  xmlDocPtr doc = xmlNewDoc((xmlChar *)"1.0");
  xmlCreateIntSubset(doc, (xmlChar *)"mapq3", NULL, (xmlChar *)"mapq3.dtd");
  doc->children->next = xmlNewDocNode(doc, NULL, (xmlChar *)"mapq3", NULL);

  Map_XMLWrite(map, doc->children->next);

  // xmlDocDumpMemory(doc, &buf, &len);
  xmlDocDumpFormatMemory(doc, &buf, &len, 1);
  xmlFreeDoc(doc);

  out->Write(buf, len);

  xmlFree(buf);
}
