/***************************************************************************
                          qtag.cpp  -  description
                             -------------------
    begin                : Thu Aug 15 2002
    copyright            : (C) 2002 by Andras Mantia <amantia@kde.org>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; version 2 of the License.               *
 *                                                                         *
 ***************************************************************************/

#include "qtag.h"
#include "node.h"
#include "tag.h"
#include <kdebug.h>

TQTag::TQTag()
{
 attrs.setAutoDelete(true);
 single = false;
 optional = false;
 type = "xmltag";
 parentDTD = 0L;
}

TQTag::TQTag( TQTag &t)
{
  tagName = t.tagName;
  single = t.single;
  optional = t.optional;
  m_fileName = t.m_fileName;
  parentDTD = t.parentDTD;
  type = t.type;
  returnType = t.returnType;
  comment = t.comment;
  commonGroups = t.commonGroups;
  stoppingTags = t.stoppingTags;
  childTags = t.childTags;
  className = t.className;

  for (int i=0; i < t.attributeCount(); i++)
  {
    addAttribute(t.attributeAt(i));
  }
}

TQTag::~TQTag()
{
}

/** Add an attribute to the tag. */
void TQTag::addAttribute(Attribute* attr)
{
 if (attr)
 {
  Attribute* a = attribute(attr->name);
  bool createNew = !a;
  if (createNew)
    a = new Attribute;
  a->name = attr->name;
  a->type = attr->type;
  TQStringList::ConstIterator end = attr->values.constEnd();
  for ( TQStringList::ConstIterator it = attr->values.constBegin(); it != end; ++it )
  {
     a->values.append(*it);
  }
  a->defaultValue = attr->defaultValue;
  a->status = attr->status;
  a->source = attr->source;
  a->method = attr->method;
  a->interface = attr->interface;
  a->arguments = attr->arguments;
  if (createNew)
    attrs.append(a);
 }
}
/** Returns the number of attributes for the tag. */
int TQTag::attributeCount()
{
  return attrs.count();
}
/** Returns the attribute at index. */
Attribute* TQTag::attributeAt(int index)
{
  return attrs.at(index);
}

/** Returns true if the attribute exists */
bool TQTag::isAttribute(const TQString &attrName)
{
  Attribute *a;
  int i;
  AttributeList *groupAttrs;

  //Check in the TQTag specific attributes
  for(a = attrs.first(); a; a = attrs.next())
  {
    if(a->name == attrName)
      return true;
  }
  //Check in the common attributes
  for(i = 0; i < (signed)commonGroups.count(); i++)
  {
    groupAttrs = parentDTD->commonAttrs->find(commonGroups[i]);
    if(groupAttrs)
    {
      for(a = groupAttrs->first(); a; a = groupAttrs->next())
      {
        if(a->name == attrName)
         return true;
      }
    }
  }
  return false;
}

/** No descriptions */
void TQTag::setSingle(bool isSingle)
{
 single = isSingle;
}
/** No descriptions */
void TQTag::setOptional(bool isOptional)
{
 optional = isOptional;
}
/** No descriptions */
void TQTag::setName(const TQString& theName)
{
  tagName = theName;
}
/** No descriptions */
TQString TQTag::name(bool doNotConvert)
{
  if (doNotConvert || !parentDTD || parentDTD->caseSensitive)
      return tagName;
  else
      return tagName.upper();
}
/** No descriptions */
bool TQTag::isSingle()
{
  return single;
}
/** No descriptions */
bool TQTag::isOptional()
{
  return optional;
}
/** No descriptions */
void TQTag::setFileName(const TQString& fileName)
{
  m_fileName = fileName;
}

/** No descriptions */
TQString TQTag::fileName()
{
 return m_fileName;
}

TQTag TQTag::operator = (TQTag &t)
{
  tagName = t.tagName;
  single = t.single;
  optional = t.optional;
  m_fileName = t.m_fileName;
  parentDTD = t.parentDTD;
  type = t.type;
  returnType = t.returnType;
  comment = t.comment;
  commonGroups = t.commonGroups;
  stoppingTags = t.stoppingTags;
  className = t.className;

  for (int i=0; i < t.attributeCount(); i++)
  {
    addAttribute(t.attributeAt(i));
  }

  return *this;
}

/** Returns the attribute with name, or 0 if the tag does not have any attribute with name. */
Attribute* TQTag::attribute(const TQString& name)
{
 Attribute *attr = 0L;
 for (uint i = 0; i < attrs.count(); i++)
 {
   if (attrs.at(i)->name == name)
   {
     attr = attrs.at(i);
     break;
   }
 }

 return attr;
}

bool TQTag::isChild(const TQString& tag, bool trueIfNoChildsDefined)
{
 TQString tagName = tag;
  tagName = parentDTD->caseSensitive ? tagName : tagName.upper();
  if(trueIfNoChildsDefined)
    return (childTags.isEmpty() || childTags.contains(tagName));
  else
    return (!childTags.isEmpty() && childTags.contains(tagName));
}

bool TQTag::isChild(Node *node, bool trueIfNoChildsDefined, bool treatEmptyNodesAsText)
{
  TQString nodeName;

  if(!node)
    return false;
  else if(node->tag->type == Tag::Text)
  {
    if(trueIfNoChildsDefined)
      return(childTags.isEmpty() || childTags.contains("#text") || childTags.contains("#TEXT"));
    else
      return(!childTags.isEmpty() && (childTags.contains("#text") || childTags.contains("#TEXT")));
  }
  else if(node->tag->type == Tag::Empty && !treatEmptyNodesAsText)
      return true;
  else if(node->tag->type == Tag::Empty && treatEmptyNodesAsText)
  {
      if(trueIfNoChildsDefined)
          return(childTags.isEmpty() || childTags.contains("#text") || childTags.contains("#TEXT"));
      else
          return(!childTags.isEmpty() && (childTags.contains("#text") || childTags.contains("#TEXT")));      
  }
  else if(node->tag->type == Tag::XmlTagEnd)
  {
    nodeName = node->tag->name;
    if(nodeName.left(1) == "/")
      nodeName = nodeName.mid(1);
    return isChild(nodeName, trueIfNoChildsDefined);
  }
  else if(node->tag->type == Tag::ScriptTag)
    //FIXME: It might depend of scripts...
    return true;
  else
    return isChild(node->tag->name, trueIfNoChildsDefined);
}

TQPtrList<TQTag> TQTag::parents()
{
  TQPtrList<TQTag> qTagList;
  TQDictIterator<TQTag> it((*parentDTD->tagsList));
  for(; it.current(); ++it)
  {
    if(it.current()->isChild(name()))
      qTagList.append(it.current());
  }
  return qTagList;
}
