var TNBase = new Object();

TNBase.TNGui = function() {};
TNBase.TNGui.prototype =
{
  activate: function(name, parentElement, hide)
  {
    return this.showByClassName(hide ? false : true, 'tnActivate_'+name, parentElement);
  },
  deactivate: function(name, parentElement, show)
  {
    return this.showByClassName(show || false, 'tnDeactivate_'+name, parentElement);
  },
  showByClassName: function(display, name, parentElement)
  {
      var a = $A(this.getElementsByClassName(name, parentElement));

    a.each(function(child) {
      child.style.display = display ? '' : 'none';      
    });
      return a.length;
  },
  showHide: function(element, hide)
  {
    var o = $(element);
    if(o)
    {
      if(!hide)
        Element.show(o);
      else
        Element.hide(o);
    }
  },
  addRemoveClassName: function(element, className, remove)
  {
    var o = $(element);
    if(o)
    {
      if(remove)
        Element.removeClassName(element, className);
      else
        Element.addClassName(element, className);
    }
  },
  setElementContentByCache: function(cacheIds, id, content, attribute, newId)
  {
    var o = cacheIds && cacheIds.get ? cacheIds.get(id) : null;
    return this._setElementContent(o, content, attribute, newId);
  },
  setElementContent: function(element, content, attribute, newId)
  {
    return this._setElementContent($(element), content, attribute, newId);
  },
  setElementContentHash: function(elementHash, prefix, attribute)
  {
    var objects = {};

    for(var id in elementHash)
    {
      var o = TNGui.setElementContent(prefix+id, elementHash[id]);
      if(o)
        objects[id] = o;
    }
    return objects;
  },
  _setElementContent: function(element, content, attribute, newId)
  {
    if(element != null)
    {       
      // Find what attribute to set
      var setAttribute = 'innerHTML';
      if(attribute && element[attribute])
        setAttribute = attribute;
      else if(element.tagName == 'IMG')
        setAttribute = 'src';
      else if(element.tagName == 'INPUT')
        setAttribute = 'value';
			
      element.id            = newId || '';
      element[setAttribute] = content;
      return element;
    }

    return;
  },
  getElementsByClassName: function(className, parentElement) 
  {
    var children = ($(parentElement) || document.body).getElementsByTagName('*');
    var re = new RegExp("(^|\\s)" + className + "(\\s|$)");
    return $A(children).inject([], function(elements, child) {
      if (child.className.match(re))
        elements.push(Element.extend(child));
      return elements;
    });
    //return parentElement.getElementsByClassName(className);
  },
  limitElementSize: function(element, minWidth, maxWidth, minHeight, maxHeight)
  {
    return;
  }
};

var TNGui = new TNBase.TNGui();

TNBase.TNText = function() {};
TNBase.TNText.prototype =
{
  initialize: function()
  {
	
  },
  replaceHash: function(text, hash)
  {
    if(text && text != '')
    {
      return text.replace(/\[\#\#[^\]]+\#\#\]/g, function (val)
      {
        var a = val.substr(3, val.length - 6).toLowerCase();
        return hash[a] || '';
      });
    }
    return ''; 
  }
}

TNText = new TNBase.TNText();

TNIdCache = Class.create();
	
TNIdCache.prototype =
{
  initialize: function(current_element)
  {
    this.cache = new Object();
    this.add(current_element);
  },
  set: function(id, new_id)
  {
    this.cache[new_id] = this.cache[id];
    delete this.cache[id];
  },
  get: function(id)
  {
    return this.cache[id];
  },
  add: function(current_element)
  {
    if(!current_element || !current_element.getElementsByTagName)
      return;

    var all = current_element.getElementsByTagName("*");

    for (var g=0; g<all.length; g++)
    {
      if (all[g].getAttribute && all[g].getAttribute("id"))
      {			 
        this.cache[all[g].getAttribute("id")] = all[g];
      }
    }

    if(current_element.getAttribute && current_element.getAttribute("id"))
      this.cache[current_element.getAttribute("id")] = current_element;
  },
  getDataStructure: function()
  {
    return $H(this.cache).inspect();
  }
};

TNTemplate = Class.create();

TNTemplate.prototype =
{
  initialize: function(parents, mode)
  {
    var tmpParents = parents && parents.length ? parents : new Array(parents || document);
    this.idCache   = new TNIdCache();

    this.objectParents = $A(tmpParents).collect(function(obj)
    {        
      if(mode && mode.getIds)
        this.idCache.add(obj); 

      return obj;
    }.bind(this));  

    this.name = '';
    if(mode && mode.name)
    {
      this.name = mode.name;
    }

    this.loops   = {};
  },
  hideAllActivates: function()
  {
    if(this.objectParents.length == 1 && this.objectParents[0] == document)
    {
      TNGui.showByClassName(false, 'tnActivate_.*', document);
    }
  },
  getObjects: function()
  {
    var a = $A(this.objectParents).collect(function(obj)
    {
        return obj;
    });

    return a;
  },
  getParents: function()
  {
    return this.objectParents;
  },
  _loopClone: function(loopData)
  {
    var clones = $A(loopData.objects).collect(function(object)
    {
      var clone = object.cloneNode(true);
      return clone;
    });

    return new TNTemplate(clones, { name: loopData.name, getIds: true });
  },
  getLoopsAdded: function(loopName)
  {
    var added = 0;
    if(this.loops[loopName])
      added = this.loops[loopName].loopsAdded;

    return added;
  },
  getLoop: function(loopName)
  {
    if(this.loops[loopName])
    {
      return this._loopClone(this.loops[loopName]);
    }

    var loopsFound = $A(this.objectParents).inject([], function(elements, object)
    {
      elements = TNGui.getElementsByClassName('tnLoop_'+loopName, object);    
      return elements;
    });

    var addAt;
    var parent;
    if(!loopsFound || loopsFound.length == 0)
      return undefined;

    var lastElement = loopsFound[loopsFound.length - 1];
    addAt  = lastElement.nextSibling;
    parent = lastElement.parentNode;

    $A(loopsFound).each(function(template)
    {
      parent.removeChild(template);
    }.bind(parent));

    var a =
    {
      name:             loopName,
      objects:          loopsFound,
      elementsRendered: [],
      renderArray:      [],
      loopsAdded:       0,
      addAt:            addAt,
      parent:           parent
    };

    this.loops[loopName] = a;
    
    return this._loopClone(a);
  },
  update: function(id, value, attribute)
  {
    return TNGui.setElementContentByCache(this.idCache, id, value, attribute);
  },
  updateHash: function(hash, prefix, attribute)
  {
    var objects = {};

    for(var id in hash)
    {
      var o = TNGui.setElementContentByCache(this.idCache, prefix+id, hash[id], attribute);
      if(o)
        objects[id] = o;;
    }
    return objects;
  },
  addLoop: function(loopTemplate)
  {
    if(!loopTemplate || !loopTemplate.name || loopTemplate.name == '' || !this.loops[loopTemplate.name] ||
       !this.loops[loopTemplate.name].objects)
      return 0;  

    var loopName      = loopTemplate.name;
        
    var theLoop       = this.loops[loopTemplate.name];
    var objectsToAdd  = loopTemplate.getObjects();

    loopTemplate.update('tnLoop_'+loopName+'_offset', theLoop.loopsAdded);
    loopTemplate.update('tnLoop_'+loopName+'_index', ++theLoop.loopsAdded);    

    loopTemplate.render();      

    for(var i = 0; i < objectsToAdd.length; i++)
    {
      TNGui.addRemoveClassName(objectsToAdd[i], loopName+'_index'+theLoop.loopsAdded);
      theLoop.renderArray.push(objectsToAdd[i]);
    }

    return theLoop.loopsAdded;
  },
  clearLoop: function(loopName)
  {
    if(this.loops[loopName])
    {
      var loop = this.loops[loopName];
      $A(loop.elementsRendered).each(function(template)
      {
        loop.parent.removeChild(template);
      }.bind(loop));

      loop.elementsRendered = new Array();
      loop.loopsAdded = 0;
    }
  },
  getRenderedLoopElements: function(loopName)
  {
    if(this.loops[loopName])
    {
      var loop = this.loops[loopName];
      return loop.elementsRendered;
    }

    return [];
  },
  render: function()
  {
    $H(this.loops).values().each(function(loop) 
    { 
      $A(loop.renderArray).each(function(block)
      {  
        loop.parent.insertBefore(block, loop.addAt);
      }.bind(loop));

      loop.elementsRendered = loop.elementsRendered.concat(loop.renderArray);
      loop.renderArray = new Array();
    }.bind(this));
  },
  inspect: function()
  {
      return $H(this.loops).values().collect(function(loop) 
      {
	return loop.parent.innerHTML;
      }).join("\n");
  }
};

var TNDocument = new TNTemplate();



