// ---------------------------------------------------------------------------
// - 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-2011 amaury darsch                                   -
// ---------------------------------------------------------------------------

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

namespace afnix {

  // -------------------------------------------------------------------------
  // - 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) {
    that.rdlock ();
    try {
      // assign the base cons cell
      Cons::operator = (that);
      // copy locally
      d_name = that.d_name;
      d_lnum = that.d_lnum;
      that.unlock ();
    } catch (...) {
      that.unlock ();
      throw;
    }
  }
  
  // return the class name

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

  // return a clone of this object

  Object* Form::clone (void) const {
    return new Form (*this);
  }

  // assign a form to another one

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

  // return the form serial code

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

  // serialize this form

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

  // deserialize this form

  void Form::rdstream (InputStream& is) {
    wrlock ();
    try {
      String  sval;
      Integer ival;
      sval.rdstream  (is);
      ival.rdstream  (is);
      Cons::rdstream (is);
      d_name  = sval;
      d_lnum  = ival.tolong ();    
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

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

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

  // return the form file name

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

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

  // return the form line number

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

  // -------------------------------------------------------------------------
  // - 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;
    }
  }
}
