
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2020 Matthias Koefferlein

  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/


#include "dbOASIS.h"
#include "dbOASISReader.h"
#include "dbOASISWriter.h"
#include "dbStream.h"

#include "tlClassRegistry.h"

namespace db
{

// ---------------------------------------------------------------
//  OASISDiagnostics implementation

OASISDiagnostics::~OASISDiagnostics ()
{
  //  .. nothing yet ..
}

// ---------------------------------------------------------------
//  RepetitionBase and RepetitionIteratorBase specializations


//  Regular repetitions

RegularRepetitionIterator::RegularRepetitionIterator (const RegularRepetition *rep, size_t i, size_t j)
  : mp_rep (rep), m_i (i), m_j (j)
{
  // .. nothing yet ..
}

RepetitionIteratorBase *
RegularRepetitionIterator::clone () const
{
  return new RegularRepetitionIterator (mp_rep, m_i, m_j);
}

void 
RegularRepetitionIterator::inc ()
{
  ++m_i;
  if (m_i == mp_rep->m_n) {
    m_i = 0;
    ++m_j;
  }
}

db::Vector
RegularRepetitionIterator::get () const
{
  return db::Vector (mp_rep->m_a.x () * db::Coord (m_i) + mp_rep->m_b.x () * db::Coord (m_j),
                    mp_rep->m_a.y () * db::Coord (m_i) + mp_rep->m_b.y () * db::Coord (m_j));
}

unsigned int 
RegularRepetitionIterator::type () const
{
  return 0;
}

bool 
RegularRepetitionIterator::equals (const RepetitionIteratorBase *b) const
{
  const RegularRepetitionIterator *r = dynamic_cast <const RegularRepetitionIterator *> (b);
  return r && mp_rep == r->mp_rep && m_i == r->m_i && m_j == r->m_j;
}

bool 
RegularRepetitionIterator::at_end () const
{
  return m_j == mp_rep->m_m;
}


RegularRepetition::RegularRepetition (const db::Vector &a, const db::Vector &b, size_t n, size_t m)
  : m_a (a), m_b (b), m_n (n), m_m (m)
{
  // .. nothing yet ..
}

RepetitionBase *
RegularRepetition::clone () const
{
  return new RegularRepetition (m_a, m_b, m_n, m_m);
}

RepetitionIteratorBase *
RegularRepetition::begin () const
{
  return new RegularRepetitionIterator (this, 0, 0);
}

unsigned int 
RegularRepetition::type () const
{
  return 0;
}

bool 
RegularRepetition::equals (const RepetitionBase *b) const
{
  const RegularRepetition *r = dynamic_cast <const RegularRepetition *> (b);
  tl_assert (r != 0);
  return m_a == r->m_a && m_b == r->m_b && m_n == r->m_n && m_m == r->m_m;
}

bool 
RegularRepetition::less (const RepetitionBase *b) const
{
  const RegularRepetition *r = dynamic_cast <const RegularRepetition *> (b);
  tl_assert (r != 0);
  if (m_a != r->m_a) {
    return m_a < r->m_a;
  }
  if (m_b != r->m_b) {
    return m_b < r->m_b;
  }
  if (m_n != r->m_n) {
    return m_n < r->m_n;
  }
  return m_m < r->m_m;
}

bool 
RegularRepetition::is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const
{
  a = m_a;
  b = m_b;
  n = m_n;
  m = m_m;
  return true;
}

const std::vector<db::Vector> *
RegularRepetition::is_iterated () const
{
  return 0;
}

//  Irregular repetitions

IrregularRepetitionIterator::IrregularRepetitionIterator (const IrregularRepetition *rep, size_t i)
  : mp_rep (rep), m_i (i)
{
  // .. nothing yet ..
}

RepetitionIteratorBase *
IrregularRepetitionIterator::clone () const
{
  return new IrregularRepetitionIterator (mp_rep, m_i);
}

void 
IrregularRepetitionIterator::inc ()
{
  ++m_i;
}

db::Vector
IrregularRepetitionIterator::get () const
{
  if (m_i == 0) {
    return db::Vector (0, 0);
  } else {
    return mp_rep->m_points [m_i - 1];
  }
}

unsigned int 
IrregularRepetitionIterator::type () const
{
  return 1;
}

bool 
IrregularRepetitionIterator::equals (const RepetitionIteratorBase *b) const
{
  const IrregularRepetitionIterator *r = dynamic_cast <const IrregularRepetitionIterator *> (b);
  return r && mp_rep == r->mp_rep && m_i == r->m_i;
}

bool 
IrregularRepetitionIterator::at_end () const
{
  return m_i == mp_rep->m_points.size () + 1;
}


IrregularRepetition::IrregularRepetition ()
  : m_points ()
{
  // .. nothing yet ..
}

RepetitionBase *
IrregularRepetition::clone () const
{
  IrregularRepetition *r =  new IrregularRepetition ();
  r->m_points = m_points;
  return r;
}

RepetitionIteratorBase *
IrregularRepetition::begin () const
{
  return new IrregularRepetitionIterator (this, 0);
}

unsigned int 
IrregularRepetition::type () const
{
  return 1;
}

bool 
IrregularRepetition::equals (const RepetitionBase *b) const
{
  const IrregularRepetition *r = dynamic_cast <const IrregularRepetition *> (b);
  tl_assert (r != 0);
  return m_points == r->m_points;
}

bool 
IrregularRepetition::less (const RepetitionBase *b) const
{
  const IrregularRepetition *r = dynamic_cast <const IrregularRepetition *> (b);
  tl_assert (r != 0);
  return m_points < r->m_points;
}

bool 
IrregularRepetition::is_regular (db::Vector & /*a*/, db::Vector & /*b*/, size_t & /*n*/, size_t & /*m*/) const
{
  return false;
}

const std::vector<db::Vector> *
IrregularRepetition::is_iterated () const
{
  return &m_points;
}


//  Repetition iterator

RepetitionIterator::RepetitionIterator (RepetitionIteratorBase *base)
  : mp_base (base)
{
  //  .. nothing yet ..
}

RepetitionIterator::~RepetitionIterator ()
{
  delete mp_base;
  mp_base = 0;
}

RepetitionIterator::RepetitionIterator (const RepetitionIterator &d)
{
  mp_base = d.mp_base->clone ();
}

RepetitionIterator &
RepetitionIterator::operator= (const RepetitionIterator &d)
{
  if (this != &d) {
    delete mp_base;
    mp_base = d.mp_base->clone ();
  }
  return *this;
}

bool 
RepetitionIterator::operator== (const RepetitionIterator &d) const
{
  if (mp_base->type () != d.mp_base->type ()) {
    return false;
  }
  return mp_base->equals (d.mp_base);
}

bool 
RepetitionIterator::at_end () const
{
  return mp_base->at_end ();
}

RepetitionIterator &
RepetitionIterator::operator++ ()
{
  mp_base->inc ();
  return *this;
}

db::Vector
RepetitionIterator::operator* () const
{
  return mp_base->get ();
}


//  Repetition 

Repetition::Repetition (RepetitionBase *base)
  : mp_base (base)
{
  // .. nothing yet ..
}

Repetition::~Repetition ()
{
  set_base (0);
}

Repetition::Repetition (const Repetition &d)
{
  if (d.mp_base) {
    mp_base = d.mp_base->clone ();
  } else {
    mp_base = 0;
  }
}

Repetition &
Repetition::operator= (const Repetition &d)
{
  if (this != &d) {
    set_base (d.mp_base ? d.mp_base->clone () : 0);
  }
  return *this;
}

Repetition &
Repetition::operator= (RepetitionBase *base)
{
  set_base (base);
  return *this;
}

bool 
Repetition::operator== (const Repetition &d) const
{
  if (mp_base == 0 && d.mp_base == 0) { 
    return true;
  }
  if (! (mp_base != 0 && d.mp_base != 0)) {
    return false;
  }
  if (mp_base->type () != d.mp_base->type ()) {
    return false;
  }
  return mp_base->equals (d.mp_base);
}

bool 
Repetition::operator< (const Repetition &d) const
{
  if (mp_base == 0 || d.mp_base == 0) { 
    return (mp_base == 0) < (d.mp_base == 0);
  }
  if (mp_base->type () != d.mp_base->type ()) {
    return mp_base->type () < d.mp_base->type ();
  }
  return mp_base->less (d.mp_base);
}

void
Repetition::set_base (RepetitionBase *base)
{
  if (mp_base) {
    delete mp_base;
  }
  mp_base = base;
}

size_t
Repetition::size () const
{
  return mp_base ? mp_base->size () : 1;
}

bool 
Repetition::is_regular (db::Vector &a, db::Vector &b, size_t &n, size_t &m) const
{
  return mp_base && mp_base->is_regular (a, b, n, m);
}

const std::vector<db::Vector> *
Repetition::is_iterated () const
{
  return mp_base != 0 ? mp_base->is_iterated () : 0;
}

RepetitionIterator 
Repetition::begin () const
{
  tl_assert (mp_base != 0);
  return RepetitionIterator (mp_base->begin ());
}

// ---------------------------------------------------------------
//  OASIS format declaration

class OASISFormatDeclaration
  : public db::StreamFormatDeclaration
{
public:
  OASISFormatDeclaration ()
  {
    //  .. nothing yet ..
  }

  virtual std::string format_name () const { return "OASIS"; }
  virtual std::string format_desc () const { return "OASIS"; }
  virtual std::string format_title () const { return "OASIS"; }
  virtual std::string file_format () const { return "OASIS files (*.OAS *.oas *.oas.gz *.OAS.gz)"; }

  virtual bool detect (tl::InputStream &stream) const 
  {
    const char *hdr = stream.get (4);
    return (hdr && hdr[0] == 0x25 && hdr[1] == 0x53 && hdr[2] == 0x45 && hdr[3] == 0x4d);
  }

  virtual ReaderBase *create_reader (tl::InputStream &s) const 
  {
    return new db::OASISReader (s);
  }

  virtual WriterBase *create_writer () const
  {
    return new db::OASISWriter ();
  }

  virtual bool can_read () const
  {
    return true;
  }

  virtual bool can_write () const
  {
    return true;
  }

  virtual tl::XMLElementBase *xml_writer_options_element () const
  {
    return new db::WriterOptionsXMLElement<db::OASISWriterOptions> ("oasis",
      tl::make_member (&db::OASISWriterOptions::compression_level, "compression-level") +
      tl::make_member (&db::OASISWriterOptions::write_cblocks, "write-cblocks") +
      tl::make_member (&db::OASISWriterOptions::strict_mode, "strict-mode") +
      tl::make_member (&db::OASISWriterOptions::write_std_properties, "write-std-properties") +
      tl::make_member (&db::OASISWriterOptions::subst_char, "subst-char") +
      tl::make_member (&db::OASISWriterOptions::permissive, "permissive")
    );
  }
};

static tl::RegisteredClass<db::StreamFormatDeclaration> reader_decl (new OASISFormatDeclaration (), 10, "OASIS");

//  provide a symbol to force linking against
int force_link_OASIS = 0;

}


