/*
 * Copyright © 2022  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Garret Rieger
 */

#ifndef GRAPH_SERIALIZE_HH
#define GRAPH_SERIALIZE_HH

namespace graph {

struct overflow_record_t
{
  unsigned parent;
  unsigned child;

  bool operator != (const overflow_record_t o) const
  { return !(*this == o); }

  inline bool operator == (const overflow_record_t& o) const
  {
    return parent == o.parent &&
        child == o.child;
  }

  inline uint32_t hash () const
  {
    uint32_t current = 0;
    current = current * 31 + hb_hash (parent);
    current = current * 31 + hb_hash (child);
    return current;
  }
};

inline
int64_t compute_offset (
    const graph_t& graph,
    unsigned parent_idx,
    const hb_serialize_context_t::object_t::link_t& link)
{
  const auto& parent = graph.vertices_[parent_idx];
  const auto& child = graph.vertices_[link.objidx];
  int64_t offset = 0;
  switch ((hb_serialize_context_t::whence_t) link.whence) {
    case hb_serialize_context_t::whence_t::Head:
      offset = child.start - parent.start; break;
    case hb_serialize_context_t::whence_t::Tail:
      offset = child.start - parent.end; break;
    case hb_serialize_context_t::whence_t::Absolute:
      offset = child.start; break;
  }

  assert (offset >= link.bias);
  offset -= link.bias;
  return offset;
}

inline
bool is_valid_offset (int64_t offset,
                      const hb_serialize_context_t::object_t::link_t& link)
{
  if (unlikely (!link.width))
    // Virtual links can't overflow.
    return link.is_signed || offset >= 0;

  if (link.is_signed)
  {
    if (link.width == 4)
      return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
    else
      return offset >= -(1 << 15) && offset < (1 << 15);
  }
  else
  {
    if (link.width == 4)
      return offset >= 0 && offset < ((int64_t) 1 << 32);
    else if (link.width == 3)
      return offset >= 0 && offset < ((int32_t) 1 << 24);
    else
      return offset >= 0 && offset < (1 << 16);
  }
}

/*
 * Will any offsets overflow on graph when it's serialized?
 */
inline bool
will_overflow (graph_t& graph,
               hb_vector_t<overflow_record_t>* overflows = nullptr)
{
  if (overflows) overflows->resize (0);
  graph.update_positions ();

  hb_hashmap_t<overflow_record_t*, bool> record_set;
  const auto& vertices = graph.vertices_;
  for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
  {
    // Don't need to check virtual links for overflow
    for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
    {
      int64_t offset = compute_offset (graph, parent_idx, link);
      if (likely (is_valid_offset (offset, link)))
        continue;

      if (!overflows) return true;

      overflow_record_t r;
      r.parent = parent_idx;
      r.child = link.objidx;
      if (record_set.has(&r)) continue; // don't keep duplicate overflows.

      overflows->push (r);
      record_set.set(&r, true);
    }
  }

  if (!overflows) return false;
  return overflows->length;
}

inline
void print_overflows (graph_t& graph,
                      const hb_vector_t<overflow_record_t>& overflows)
{
  if (!DEBUG_ENABLED(SUBSET_REPACK)) return;

  graph.update_parents ();
  int limit = 10;
  for (const auto& o : overflows)
  {
    if (!limit--) break;
    const auto& parent = graph.vertices_[o.parent];
    const auto& child = graph.vertices_[o.child];
    DEBUG_MSG (SUBSET_REPACK, nullptr,
               "  overflow from "
               "%4u (%4u in, %4u out, space %2u) => "
               "%4u (%4u in, %4u out, space %2u)",
               o.parent,
               parent.incoming_edges (),
               parent.obj.real_links.length + parent.obj.virtual_links.length,
               graph.space_for (o.parent),
               o.child,
               child.incoming_edges (),
               child.obj.real_links.length + child.obj.virtual_links.length,
               graph.space_for (o.child));
  }
  if (overflows.length > 10) {
    DEBUG_MSG (SUBSET_REPACK, nullptr, "  ... plus %u more overflows.", overflows.length - 10);
  }
}

template <typename O> inline void
serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
                        char* head,
                        hb_serialize_context_t* c)
{
  OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
  *offset = 0;
  c->add_link (*offset,
               // serializer has an extra nil object at the start of the
               // object array. So all id's are +1 of what our id's are.
               link.objidx + 1,
               (hb_serialize_context_t::whence_t) link.whence,
               link.bias);
}

inline
void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
                     char* head,
                     hb_serialize_context_t* c)
{
  switch (link.width)
  {
    case 0:
      // Virtual links aren't serialized.
      return;
    case 4:
      if (link.is_signed)
      {
        serialize_link_of_type<OT::HBINT32> (link, head, c);
      } else {
        serialize_link_of_type<OT::HBUINT32> (link, head, c);
      }
      return;
    case 2:
      if (link.is_signed)
      {
        serialize_link_of_type<OT::HBINT16> (link, head, c);
      } else {
        serialize_link_of_type<OT::HBUINT16> (link, head, c);
      }
      return;
    case 3:
      serialize_link_of_type<OT::HBUINT24> (link, head, c);
      return;
    default:
      // Unexpected link width.
      assert (0);
  }
}

/*
 * serialize graph into the provided serialization buffer.
 */
inline hb_blob_t* serialize (const graph_t& graph)
{
  hb_vector_t<char> buffer;
  size_t size = graph.total_size_in_bytes ();

  if (!size) return hb_blob_get_empty ();

  if (!buffer.alloc (size)) {
    DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
    return nullptr;
  }
  hb_serialize_context_t c((void *) buffer, size);

  c.start_serialize<void> ();
  const auto& vertices = graph.vertices_;
  for (unsigned i = 0; i < vertices.length; i++) {
    c.push ();

    size_t size = vertices[i].obj.tail - vertices[i].obj.head;
    char* start = c.allocate_size <char> (size);
    if (!start) {
      DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
      return nullptr;
    }

    hb_memcpy (start, vertices[i].obj.head, size);

    // Only real links needs to be serialized.
    for (const auto& link : vertices[i].obj.real_links)
      serialize_link (link, start, &c);

    // All duplications are already encoded in the graph, so don't
    // enable sharing during packing.
    c.pop_pack (false);
  }
  c.end_serialize ();

  if (c.in_error ()) {
    DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d",
               c.errors);
    return nullptr;
  }

  return c.copy_blob ();
}

} // namespace graph

#endif // GRAPH_SERIALIZE_HH
