// ---------------------------------------------------------------------------
// - Form.cpp                                                                -
// - afnix engine - form class implementation                                -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - 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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2008 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "Form.hpp"
#include "Engsid.hxx"
#include "Integer.hpp"
#include "Recycle.hpp"
#include "Exception.hpp"

namespace afnix {

  // -------------------------------------------------------------------------
  // - memory section                                                        -
  // -------------------------------------------------------------------------

  // the form recycler
  static Recycle recycler;

  // allocate a form
  void* Form::operator new (const t_size size) {
    return recycler.pop (size);
  }

  // delete a form
  void Form::operator delete (void* handle) {
    recycler.push (handle);
  }

  // -------------------------------------------------------------------------
  // - private section                                                       -
  // -------------------------------------------------------------------------

  // this procedure returns a new form object for deserialization
  static Serial* mksob (void) {
    return new Form;
  }

  // register this lexical serial id
  static const t_byte SERIAL_ID = Serial::setsid (SERIAL_FORM_ID, mksob);
  
  // -------------------------------------------------------------------------
  // - class section                                                         -
  // -------------------------------------------------------------------------

  Form::Form (void) {
    d_lnum = 0;
  }

  // create a new form with a type

  Form::Form (t_type type) : Cons (type) {
    d_lnum = 0;
  }

  // create a new form with a type and line number

  Form::Form (t_type type, const long lnum) : Cons (type) {
    d_lnum = lnum;
  }

  // create a form with a car
  
  Form::Form (Object* car) : Cons (car) {
    d_lnum = 0;
  }

  // create a form with a type and a car
  
  Form::Form (t_type type, Object* car) : Cons (type, car) {
    d_lnum = 0;
  }

  // copy constructor for this form

  Form::Form (const Form& that) : Cons (that) {
    that.rdlock ();
    d_name = that.d_name;
    d_lnum = that.d_lnum;
    that.unlock ();
  }
  
  // return the class name

  String Form::repr (void) const {
    return "Form";
  }

  // assign a form to another one

  Form& Form::operator = (const Form& that) {
    if (this == &that) return *this;
    wrlock ();
    that.rdlock ();
    Cons::operator = (that);
    d_name = that.d_name;
    d_lnum = that.d_lnum;
    that.unlock ();
    unlock ();
    return *this;
  }

  // return the form serial code

  t_byte Form::serialid (void) const {
    return SERIAL_FORM_ID;
  }

  // serialize this form

  void Form::wrstream (Output& os) const {
    rdlock ();
    Integer lnum (d_lnum);
    d_name.wrstream (os);
    lnum.wrstream   (os);
    Cons::wrstream  (os);
    unlock ();
  }

  // deserialize this form

  void Form::rdstream (Input& is) {
    wrlock ();
    String  sval;
    Integer ival;
    sval.rdstream  (is);
    ival.rdstream  (is);
    Cons::rdstream (is);
    d_name  = sval;
    d_lnum  = ival.tointeger ();    
    unlock ();
  }

  // set the form information
  
  void Form::setinfo (const String& name, const long lnum) {
    wrlock ();
    d_name = name;
    d_lnum = lnum;
    unlock ();
  }

  // set the form file name
  
  void Form::setname (const String& name) {
    wrlock ();
    d_name = name;
    unlock ();
  }

  // return the form file name

  String Form::getname (void) const {
    rdlock ();
    String result = d_name;
    unlock ();
    return result;
  }

  // set the form line number
  
  void Form::setlnum (const long lnum) {
    wrlock ();
    d_lnum = lnum;
    unlock ();
  }

  // return the form line number

  long Form::getlnum (void) const {
    rdlock ();
    long result = d_lnum;
    unlock ();
    return result;
  }

  // -------------------------------------------------------------------------
  // - object section                                                        -
  // -------------------------------------------------------------------------

  // evaluate this object in the current nameset

  Object* Form::eval (Runnable* robj, Nameset* nset) {
    try {
      return Cons::eval (robj, nset);
    } catch (Exception& e) {
      e.updname (getname ());
      e.updlnum (getlnum ());
      throw;
    }
  }
}
