
// a hash that is used to globally identify generated boxes
var idMap = new Hash();

/**
 * This helper function returns the first element of the given parameter, if it has one.
 * If not, the parameter itself will be returned.
 *
 * @param object_or_array
 */
function pickFirst(object_or_array) {
  if (object_or_array[0])
    return object_or_array[0];

  return object_or_array;
}

/**
 * This helper function checks if an string is null or empty
 *
 * @param item
 */
function isBlank(text) {
  return !text || text.clean() == '';
}

/**
 * Parses the 'date' attribute of the given parameter and return a Date object.
 *
 * @param item Item with a date attribute
 */
function extractDate(item) {
  return item.date ? new Date(Date.parse(item.date)) : new Date(1900, 01, 01)
}


/**
 * This is the base class of all template items. The constructor uses the parents data
 * object (the first parameter) and the dataPath defined inside the template (the second
 * parameter) to select the base data object. The dataPath can be false (inherit data object
 * from parent) or a jsonPath string (to select sub-data from parent data object).
 * If an id is provided in the template, the item will be added to the global idMap (see above).
 */
var Base = new Class({

  data: null,

  initialize: function(data, template) {
    // if dataPath is set, evaluate it - if not inherit the data from parent
    this.data = (template.dataPath ? jsonPath(data[0], template.dataPath) : data);

    // if an id is set, the element will be stored in an global hash for later use
    if (template.id) idMap.set(template.id, this);
  }

});

/**
 * The Collection class simply generates a couple of member elements and passes them the parent.
 * It assume that the base data object is an array and that childTemplate is defined inside the
 * template. If an element of that array also provide a collection (detected by the toCollection
 * method), the two collections will be combined.
 */
var Collection = new Class({
  Extends: Base,

  elements: [ ],

  initialize: function(data, template) {
    this.parent(data, template);

    if (!this.data)               { return; } // couldn't create a collection without a dataPath to an array!
    if (!template.childTemplates) { alert('couldn\'t create a collection without a child template!'); return; }

    $each(this.data, function(data) {

      $each(template.childTemplates, function(childTemplate) {
        var object = eval('new ' + childTemplate['class'] + '([ data ], childTemplate)');

        // if the object provides a toCollection method, the two collections will be combined
        if (object.toCollection)
          this.elements.combine(object.toCollection());

        if (object.toElement)
          this.elements.push(object);

      }.bind(this));

    }.bind(this));
  },

  toCollection: function() {
    return this.elements;
  }

});

