// ---------------------------------------------------------------------------
// - XhtmlTelem.cpp                                                          -
// - afnix:wax module - xhtml table element node 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 "QuarkZone.hpp"
#include "Exception.hpp"
#include "XhtmlTelem.hpp"

namespace afnix {

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

  // the class attribute
  static const String XML_CLS_NAME = "class";
  /// the td align attribute
  static const String XML_ALG_ATTR = "align";
  /// the left align attribute
  static const String XML_LFT_ATTR = "left";
  /// the right align attribute
  static const String XML_RGT_ATTR = "right";

  // -------------------------------------------------------------------------
  // - class section                                                         -
  // -------------------------------------------------------------------------

  // create a table element node

  XhtmlTelem::XhtmlTelem (const String& tag) : XmlTag (tag) {
    d_trc = "";
    d_txc = "";
  }

  // create a table element node with a class

  XhtmlTelem::XhtmlTelem (const String& tag, 
			  const String& cls) : XmlTag (tag) {
    d_trc = "";
    d_txc = "";
    setattr (XML_CLS_NAME, cls);
  }

  // create a table element node with a class with a default tr class

  XhtmlTelem::XhtmlTelem (const String& tag, const String& cls, 
			  const String& trc) : XmlTag (tag) {
    d_trc = trc;
    d_txc = "";
    setattr (XML_CLS_NAME, cls);
  }

  // create a table element node with a class with a default tr and tx class

  XhtmlTelem::XhtmlTelem (const String& tag, const String& cls, 
			  const String& trc, 
			  const String& txc) : XmlTag (tag) {
    d_trc = trc;
    d_txc = txc;
    setattr (XML_CLS_NAME, cls);
  }

  // return the class name

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

  // set the default tr class

  void XhtmlTelem::settrc (const String& trc) {
    wrlock ();
    d_trc = trc;
    unlock ();
  }

  // set the default tx class

  void XhtmlTelem::settxc (const String& txc) {
    wrlock ();
    d_txc = txc;
    unlock ();
  }

  // get a new table row

  XhtmlTr* XhtmlTelem::newtr (void) {
    wrlock ();
    XhtmlTr* tr = d_trc.isnil () ? new XhtmlTr : new XhtmlTr (d_trc);
    if (d_txc.isnil () == false) tr->settxc (d_txc);
    try {
      addchild (tr);
      unlock ();
      return tr;
    } catch (...) {
      delete tr;
      unlock ();
      throw;
    }
  }

  // get a new table row by class

  XhtmlTr* XhtmlTelem::newtr (const String& cls) {
    wrlock ();
    XhtmlTr* tr  = new XhtmlTr (cls);
    if (d_txc.isnil () == false) tr->settxc (d_txc);
    try {
      addchild (tr);
      unlock ();
      return tr;
    } catch (...) {
      delete tr;
      unlock ();
      throw;
    }
  }

  // add a print table to this table

  void XhtmlTelem::addtbl (const PrintTable& tbl) {
    // get the number of rows and columns
    long rows = tbl.getrows ();
    long cols = tbl.getcols ();
    if ((rows == 0) || (cols == 0)) return;
    wrlock ();
    try {
      for (long i = 0; i < rows; i++) {
        XhtmlTr* tr = newtr ();
        for (long j = 0; j < cols; j++) {
          // get a new table data
          XhtmlTd* td = tr->newtd ();
	  // get the string data and parse it
          String data = tbl.get (i, j);
	  td->parse (data);
          // eventually get the direction
	  if (tbl.getcdir (j) == true) {
	    td->setattr (XML_ALG_ATTR, XML_RGT_ATTR);
	  } else {
	    td->setattr (XML_ALG_ATTR, XML_LFT_ATTR);
	  }
	}
      }
    } catch (...) {
      unlock ();
      throw;
    }
    unlock ();
  }


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

  // the quark zone
  static const long QUARK_ZONE_LENGTH = 4;
  static QuarkZone  zone (QUARK_ZONE_LENGTH);

  // the object supported quarks
  static const long QUARK_NEWTR  = zone.intern ("new-row");
  static const long QUARK_ADDTBL = zone.intern ("add-table");
  static const long QUARK_SETTRC = zone.intern ("set-xrow-class");
  static const long QUARK_SETTXC = zone.intern ("set-xdef-class");

  // return true if the given quark is defined

  bool XhtmlTelem::isquark (const long quark, const bool hflg) const {
    rdlock ();
    if (zone.exists (quark) == true) {
      unlock ();
      return true;
    }
    bool result = hflg ? XmlTag::isquark (quark, hflg) : false;
    unlock ();
    return result;
  }

  // apply this object with a set of arguments and a quark

  Object* XhtmlTelem::apply (Runnable* robj, Nameset* nset, const long quark,
			    Vector* argv) {
    // get the number of arguments
    long argc = (argv == nilp) ? 0 : argv->length ();
    
    // dispatch 0 argument
    if (argc == 0) {
      if (quark == QUARK_NEWTR) return newtr ();
    }
    // dispatch 1 argument
    if (argc == 1) {
      if (quark == QUARK_SETTRC) {
	String trc = argv->getstring (0);	
	settrc (trc);
	return nilp;
      }
      if (quark == QUARK_SETTXC) {
	String txc = argv->getstring (0);	
	settxc (txc);
	return nilp;
      }
      if (quark == QUARK_NEWTR) {
	String cls = argv->getstring (0);	
	return newtr (cls);
      }
      if (quark == QUARK_ADDTBL) {
        PrintTable* tbl = dynamic_cast <PrintTable*> (argv->get (0));
        if (tbl == nilp) {
          throw Exception ("type-error", 
			   "print table expected with add-table");
	}
        addtbl (*tbl);
        return nilp;
      }
    }
    // call the xml tag method
    return XmlTag::apply (robj, nset, quark, argv);
  }
}
