//========================================================================
//
// Linearization.cc
//
// This file is licensed under the GPLv2 or later
//
// Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
// Copyright 2015 Jason Crain <jason@aquaticape.us>
// Copyright 2017, 2019 Albert Astals Cid <aacid@kde.org>
// Copyright 2019 Adam Reichold <adam.reichold@t-online.de>
// Copyright 2019 Even Rouault <even.rouault@spatialys.com>
//
//========================================================================

#include "Linearization.h"
#include "Parser.h"
#include "Lexer.h"

//------------------------------------------------------------------------
// Linearization
//------------------------------------------------------------------------

Linearization::Linearization (BaseStream *str)
{
  Parser *parser;

  str->reset();
  parser = new Parser(nullptr,
      str->makeSubStream(str->getStart(), false, 0, Object(objNull)),
      false);
  Object obj1 = parser->getObj();
  Object obj2 = parser->getObj();
  Object obj3 = parser->getObj();
  linDict = parser->getObj();
  if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) {
    Object obj5 = linDict.dictLookup("Linearized");
    if (!(obj5.isNum() && obj5.getNum() > 0)) {
       linDict.setToNull();
    }
  } else {
    linDict.setToNull();
  }
  delete parser;
}

Linearization:: ~Linearization()
{
}

unsigned int Linearization::getLength() const
{
  if (!linDict.isDict()) return 0;

  int length;
  if (linDict.getDict()->lookupInt("L", nullptr, &length) &&
      length > 0) {
    return length;
  } else {
    error(errSyntaxWarning, -1, "Length in linearization table is invalid");
    return 0;
  }
}

unsigned int Linearization::getHintsOffset() const
{
  int hintsOffset;

  Object obj1, obj2;
  if (linDict.isDict() &&
      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
      obj1.arrayGetLength()>=2 &&
      (obj2 = obj1.arrayGet(0), obj2.isInt()) &&
      obj2.getInt() > 0) {
    hintsOffset = obj2.getInt();
  } else {
    error(errSyntaxWarning, -1, "Hints table offset in linearization table is invalid");
    hintsOffset = 0;
  }

  return hintsOffset;
}

unsigned int Linearization::getHintsLength() const
{
  int hintsLength;

  Object obj1, obj2;
  if (linDict.isDict() &&
      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
      obj1.arrayGetLength()>=2 &&
      (obj2 = obj1.arrayGet(1), obj2.isInt()) &&
      obj2.getInt() > 0) {
    hintsLength = obj2.getInt();
  } else {
    error(errSyntaxWarning, -1, "Hints table length in linearization table is invalid");
    hintsLength = 0;
  }

  return hintsLength;
}

unsigned int Linearization::getHintsOffset2() const
{
  int hintsOffset2 = 0; // default to 0

  Object obj1;
  if (linDict.isDict() &&
      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
      obj1.arrayGetLength()>=4) {
    Object obj2 = obj1.arrayGet(2);
    if (obj2.isInt() && obj2.getInt() > 0) {
      hintsOffset2 = obj2.getInt();
    } else {
      error(errSyntaxWarning, -1, "Second hints table offset in linearization table is invalid");
      hintsOffset2 = 0;
    }
  }

  return hintsOffset2;
}

unsigned int Linearization::getHintsLength2() const
{
  int hintsLength2 = 0; // default to 0

  Object obj1;
  if (linDict.isDict() &&
      (obj1 = linDict.dictLookup("H"), obj1.isArray()) &&
      obj1.arrayGetLength()>=4) {
    Object obj2 = obj1.arrayGet(3);
    if (obj2.isInt() && obj2.getInt() > 0) {
      hintsLength2 = obj2.getInt();
    } else {
      error(errSyntaxWarning, -1, "Second hints table length in linearization table is invalid");
      hintsLength2 = 0;
    }
  }

  return hintsLength2;
}

int Linearization::getObjectNumberFirst() const
{
  int objectNumberFirst = 0;
  if (linDict.isDict() &&
      linDict.getDict()->lookupInt("O", nullptr, &objectNumberFirst) &&
      objectNumberFirst > 0) {
    return objectNumberFirst;
  } else {
    error(errSyntaxWarning, -1, "Object number of first page in linearization table is invalid");
    return 0;
  }
}

unsigned int Linearization::getEndFirst() const
{
  int pageEndFirst = 0;
  if (linDict.isDict() &&
      linDict.getDict()->lookupInt("E", nullptr, &pageEndFirst) &&
      pageEndFirst > 0) {
    return pageEndFirst;
  } else {
    error(errSyntaxWarning, -1, "First page end offset in linearization table is invalid");
    return 0;
  }
}

int Linearization::getNumPages() const
{
  int numPages = 0;
  if (linDict.isDict() &&
      linDict.getDict()->lookupInt("N", nullptr, &numPages) &&
      numPages > 0) {
    return numPages;
  } else {
    error(errSyntaxWarning, -1, "Page count in linearization table is invalid");
    return 0;
  }
}

unsigned int Linearization::getMainXRefEntriesOffset() const
{
  int mainXRefEntriesOffset = 0;
  if (linDict.isDict() &&
      linDict.getDict()->lookupInt("T", nullptr, &mainXRefEntriesOffset) &&
      mainXRefEntriesOffset > 0) {
    return mainXRefEntriesOffset;
  } else {
    error(errSyntaxWarning, -1, "Main Xref offset in linearization table is invalid");
    return 0;
  }
}

int Linearization::getPageFirst() const
{
  int pageFirst = 0; // Optional, defaults to 0.

  if (linDict.isDict()) {
    linDict.getDict()->lookupInt("P", nullptr, &pageFirst);
  }

  if ((pageFirst < 0) || (pageFirst >= getNumPages())) {
    error(errSyntaxWarning, -1, "First page in linearization table is invalid");
    return 0;
  }

  return pageFirst;
}


