//========================================================================
//
// StructTreeRoot.cc
//
// This file is licensed under the GPLv2 or later
//
// Copyright 2013, 2014 Igalia S.L.
// Copyright 2014 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright 2017 Jan-Erik S <janerik234678@gmail.com>
// Copyright 2017, 2018 Albert Astals Cid <aacid@kde.org>
// Copyright 2017, 2018 Adrian Johnson <ajohnson@redneon.com>
// Copyright 2018, Adam Reichold <adam.reichold@t-online.de>
//
//========================================================================

#include "goo/GooString.h"
#include "StructTreeRoot.h"
#include "StructElement.h"
#include "PDFDoc.h"
#include "Object.h"
#include "Dict.h"
#include <set>
#include <assert.h>


StructTreeRoot::StructTreeRoot(PDFDoc *docA, Dict *structTreeRootDict):
  doc(docA)
{
  assert(doc);
  assert(structTreeRootDict);
  parse(structTreeRootDict);
}

StructTreeRoot::~StructTreeRoot()
{
  for (ElemPtrArray::iterator i = elements.begin(); i != elements.end(); ++i)
    delete *i;
}

void StructTreeRoot::parse(Dict *root)
{
  // The RoleMap/ClassMap dictionaries are needed by all the parsing
  // functions, which will resolve the custom names to canonical
  // standard names.
  roleMap = root->lookup("RoleMap");
  classMap = root->lookup("ClassMap");

  // ParentTree (optional). If present, it must be a number tree,
  // otherwise it is not possible to map stream objects to their
  // corresponding structure element. Here only the references are
  // loaded into the array, the pointers to the StructElements will
  // be filled-in later when parsing them.
  const Object parentTreeObj = root->lookup("ParentTree");
  if (parentTreeObj.isDict()) {
    parseNumberTreeNode(parentTreeObj.getDict());
  }

  std::set<int> seenElements;

  // Parse the children StructElements
  const bool marked = doc->getCatalog()->getMarkInfo() & Catalog::markInfoMarked;
  Object kids = root->lookup("K");
  if (kids.isArray()) {
    if (marked && kids.arrayGetLength() > 1) {
      error(errSyntaxWarning, -1, "K in StructTreeRoot has more than one children in a tagged PDF");
    }
    for (int i = 0; i < kids.arrayGetLength(); i++) {
      Object ref = kids.arrayGetNF(i);
      if (ref.isRef()) {
        seenElements.insert(ref.getRefNum());
      }
      Object obj = kids.arrayGet(i);
      if (obj.isDict()) {
        StructElement *child = new StructElement(obj.getDict(), this, nullptr, seenElements);
        if (child->isOk()) {
          if (marked && !(child->getType() == StructElement::Document ||
                          child->getType() == StructElement::Part ||
                          child->getType() == StructElement::Art ||
                          child->getType() == StructElement::Div)) {
            error(errSyntaxWarning, -1, "StructTreeRoot element of tagged PDF is wrong type ({0:s})", child->getTypeName());
          }
          appendChild(child);
          if (ref.isRef()) {
            parentTreeAdd(ref.getRef(), child);
          }
        } else {
          error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
          delete child;
        }
      } else {
        error(errSyntaxWarning, -1, "K has a child of wrong type ({0:s})", obj.getTypeName());
      }
    }
  } else if (kids.isDict()) {
    StructElement *child = new StructElement(kids.getDict(), this, nullptr, seenElements);
    if (child->isOk()) {
      appendChild(child);
      Object ref = root->lookupNF("K");
      if (ref.isRef())
        parentTreeAdd(ref.getRef(), child);
    } else {
      error(errSyntaxWarning, -1, "StructTreeRoot element could not be parsed");
      delete child;
    }
  } else if (!kids.isNull()) {
    error(errSyntaxWarning, -1, "K in StructTreeRoot is wrong type ({0:s})", kids.getTypeName());
  }

  // refToParentMap is only used during parsing. Ensure all memory used by it is freed.
  std::multimap<Ref, Parent*>().swap(refToParentMap);
}

void StructTreeRoot::parseNumberTreeNode(Dict *node)
{
  Object kids = node->lookup("Kids");
  if (kids.isArray()) {
    for (int i = 0; i < kids.arrayGetLength(); i++) {
      Object obj = kids.arrayGet(i);
      if (obj.isDict()) {
	parseNumberTreeNode(obj.getDict());
      } else {
	error(errSyntaxError, -1, "Kids item at position {0:d} is wrong type ({1:s})", i, obj.getTypeName());
      }
    }
    return;
  } else if (!kids.isNull()) {
    error(errSyntaxError, -1, "Kids object is wrong type ({0:s})", kids.getTypeName());
  }

  Object nums = node->lookup("Nums");
  if (nums.isArray()) {
    if (nums.arrayGetLength() % 2 == 0) {
      // keys in even positions, references in odd ones
      for (int i = 0; i < nums.arrayGetLength(); i += 2) {
	Object key = nums.arrayGet(i);

	if (!key.isInt()) {
	  error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i, key.getTypeName());
	  continue;
	}
	int keyVal = key.getInt();
	std::vector<Parent>& vec = parentTree[keyVal];

	Object value = nums.arrayGet(i + 1);
	if (value.isArray()) {
	  vec.resize(value.arrayGetLength());
	  for (int j = 0; j < value.arrayGetLength(); j++) {
	    Object itemvalue = value.arrayGetNF(j);
	    if (itemvalue.isRef()) {
	      Ref ref = itemvalue.getRef();
	      vec[j].ref = ref;
	      refToParentMap.insert(std::pair<Ref, Parent*>(ref, &vec[j]));
	    } else if (!itemvalue.isNull()) {
	      error(errSyntaxError, -1, "Nums array item at position {0:d}/{1:d} is invalid type ({2:s})", i, j, itemvalue.getTypeName());
	    }
	  }
	} else {
	  value = nums.arrayGetNF(i + 1);
	  if (value.isRef()) {
	    Ref ref = value.getRef();
	    vec.resize(1);
	    vec[0].ref = ref;
	    refToParentMap.insert(std::pair<Ref, Parent*>(ref, &vec[0]));
	  } else {
	    error(errSyntaxError, -1, "Nums item at position {0:d} is wrong type ({1:s})", i + 1, value.getTypeName());
	  }
	}
      }
    } else {
      error(errSyntaxError, -1, "Nums array length is not a even ({0:d})", nums.arrayGetLength());
    }
  } else {
    error(errSyntaxError, -1, "Nums object is wrong type ({0:s})", nums.getTypeName());
  }
}


void StructTreeRoot::parentTreeAdd(const Ref objectRef, StructElement *element)
{
  auto range = refToParentMap.equal_range(objectRef);
  for (auto it = range.first; it !=range.second; ++it)
    it->second->element = element;
}
