nsIAtom*
nsAttrValue::AtomAt(PRInt32 aIndex) const
{
  NS_PRECONDITION(aIndex >= 0, "Index must not be negative");
  NS_PRECONDITION(GetAtomCount() > PRUint32(aIndex), "aIndex out of range");
  
  if (BaseType() == eAtomBase) {
    return GetAtomValue();
  }

  NS_ASSERTION(Type() == eAtomArray, "GetAtomCount must be confused");
  
  return GetAtomArrayValue()->ElementAt(aIndex);
}
PRUint32
nsAttrValue::GetAtomCount() const
{
  ValueType type = Type();

  if (type == eAtom) {
    return 1;
  }

  if (type == eAtomArray) {
    return GetAtomArrayValue()->Length();
  }

  return 0;
}
PRBool
nsAttrValue::Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
{
  switch (BaseType()) {
    case eAtomBase:
    {
      nsIAtom* atom = GetAtomValue();

      if (aCaseSensitive == eCaseMatters) {
        return aValue == atom;
      }

      // For performance reasons, don't do a full on unicode case insensitive
      // string comparison. This is only used for quirks mode anyway.
      return
        nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(aValue),
                                              nsDependentAtomString(atom));
    }
    default:
    {
      if (Type() == eAtomArray) {
        AtomArray* array = GetAtomArrayValue();
        if (aCaseSensitive == eCaseMatters) {
          return array->IndexOf(aValue) != AtomArray::NoIndex;
        }

        nsDependentAtomString val1(aValue);

        for (nsCOMPtr<nsIAtom> *cur = array->Elements(),
                               *end = cur + array->Length();
             cur != end; ++cur) {
          // For performance reasons, don't do a full on unicode case
          // insensitive string comparison. This is only used for quirks mode
          // anyway.
          if (nsContentUtils::EqualsIgnoreASCIICase(val1,
                nsDependentAtomString(*cur))) {
            return PR_TRUE;
          }
        }
      }
    }
  }

  return PR_FALSE;
}
PRBool
nsAttrValue::Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
{
  switch (BaseType()) {
    case eAtomBase:
    {
      nsIAtom* atom = GetAtomValue();

      if (aCaseSensitive == eCaseMatters) {
        return aValue == atom;
      }

      const char *val1, *val2;
      aValue->GetUTF8String(&val1);
      atom->GetUTF8String(&val2);

      return nsCRT::strcasecmp(val1, val2) == 0;
    }
    default:
    {
      if (Type() == eAtomArray) {
        nsCOMArray<nsIAtom>* array = GetAtomArrayValue();
        if (aCaseSensitive == eCaseMatters) {
          return array->IndexOf(aValue) >= 0;
        }

        const char *val1, *val2;
        aValue->GetUTF8String(&val1);

        for (PRInt32 i = 0, count = array->Count(); i < count; ++i) {
          array->ObjectAt(i)->GetUTF8String(&val2);
          if (nsCRT::strcasecmp(val1, val2) == 0) {
            return PR_TRUE;
          }
        }
      }
    }
  }

  return PR_FALSE;
}
void
nsAttrValue::ParseAtomArray(const nsAString& aValue)
{
  nsAString::const_iterator iter, end;
  aValue.BeginReading(iter);
  aValue.EndReading(end);
  PRBool hasSpace = PR_FALSE;
  
  // skip initial whitespace
  while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
    hasSpace = PR_TRUE;
    ++iter;
  }

  if (iter == end) {
    SetTo(aValue);
    return;
  }

  nsAString::const_iterator start(iter);

  // get first - and often only - atom
  do {
    ++iter;
  } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));

  nsCOMPtr<nsIAtom> classAtom = do_GetAtom(Substring(start, iter));
  if (!classAtom) {
    Reset();
    return;
  }

  // skip whitespace
  while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
    hasSpace = PR_TRUE;
    ++iter;
  }

  if (iter == end && !hasSpace) {
    // we only found one classname and there was no whitespace so
    // don't bother storing a list
    ResetIfSet();
    nsIAtom* atom = nsnull;
    classAtom.swap(atom);
    SetPtrValueAndType(atom, eAtomBase);
    return;
  }

  if (!EnsureEmptyAtomArray()) {
    return;
  }

  AtomArray* array = GetAtomArrayValue();
  
  if (!array->AppendElement(classAtom)) {
    Reset();
    return;
  }

  // parse the rest of the classnames
  while (iter != end) {
    start = iter;

    do {
      ++iter;
    } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));

    classAtom = do_GetAtom(Substring(start, iter));

    if (!array->AppendElement(classAtom)) {
      Reset();
      return;
    }

    // skip whitespace
    while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
      ++iter;
    }
  }

  SetMiscAtomOrString(&aValue);
  return;
}
void
nsAttrValue::SetTo(const nsAttrValue& aOther)
{
  switch (aOther.BaseType()) {
    case eStringBase:
    {
      ResetIfSet();
      nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr());
      if (str) {
        str->AddRef();
        SetPtrValueAndType(str, eStringBase);
      }
      #ifdef TAINTED
      if(aOther.isTainted()==1){

       mTainted=1;
       mJSStr=aOther.mJSStr;
      }
      #endif
      return;
    }
    case eOtherBase:
    {
      break;
    }
    case eAtomBase:
    {
      ResetIfSet();
      nsIAtom* atom = aOther.GetAtomValue();
      NS_ADDREF(atom);
      SetPtrValueAndType(atom, eAtomBase);
      return;
    }
    case eIntegerBase:
    {
      ResetIfSet();
      mBits = aOther.mBits;
      return;      
    }
  }

  MiscContainer* otherCont = aOther.GetMiscContainer();
  if (!EnsureEmptyMiscContainer()) {
    return;
  }

  MiscContainer* cont = GetMiscContainer();
  switch (otherCont->mType) {
    case eInteger:
    {
      cont->mInteger = otherCont->mInteger;
      break;
    }
    case eEnum:
    {
      cont->mEnumValue = otherCont->mEnumValue;
      break;
    }
    case ePercent:
    {
      cont->mPercent = otherCont->mPercent;
      break;
    }
    case eColor:
    {
      cont->mColor = otherCont->mColor;
      break;
    }
    case eCSSStyleRule:
    {
      NS_ADDREF(cont->mCSSStyleRule = otherCont->mCSSStyleRule);
      break;
    }
    case eAtomArray:
    {
      if (!EnsureEmptyAtomArray() ||
          !GetAtomArrayValue()->AppendElements(*otherCont->mAtomArray)) {
        Reset();
        return;
      }
      break;
    }
    case eSVGValue:
    {
      NS_ADDREF(cont->mSVGValue = otherCont->mSVGValue);
      break;
    }
    case eDoubleValue:
    {
      cont->mDoubleValue = otherCont->mDoubleValue;
      break;
    }
    case eIntMarginValue:
    {
      if (otherCont->mIntMargin)
        cont->mIntMargin = new nsIntMargin(*otherCont->mIntMargin);
      break;
    }
    default:
    {
      NS_NOTREACHED("unknown type stored in MiscContainer");
      break;
    }
  }

  void* otherPtr = MISC_STR_PTR(otherCont);
  if (otherPtr) {
    if (static_cast<ValueBaseType>(otherCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
        eStringBase) {
      static_cast<nsStringBuffer*>(otherPtr)->AddRef();
    } else {
      static_cast<nsIAtom*>(otherPtr)->AddRef();
    }
    cont->mStringBits = otherCont->mStringBits;
  }
  // Note, set mType after switch-case, otherwise EnsureEmptyAtomArray doesn't
  // work correctly.
  cont->mType = otherCont->mType;
}
void
nsAttrValue::ParseAtomArray(const nsAString& aValue)
{
  nsAString::const_iterator iter, end;
  aValue.BeginReading(iter);
  aValue.EndReading(end);

  // skip initial whitespace
  while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
    ++iter;
  }

  if (iter == end) {
    ResetIfSet();
    return;
  }

  nsAString::const_iterator start(iter);

  // get first - and often only - atom
  do {
    ++iter;
  } while (iter != end && !nsCRT::IsAsciiSpace(*iter));

  nsCOMPtr<nsIAtom> classAtom = do_GetAtom(Substring(start, iter));
  if (!classAtom) {
    Reset();
    return;
  }

  // skip whitespace
  while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
    ++iter;
  }

  if (iter == end) {
    // we only found one classname so don't bother storing a list
    ResetIfSet();
    nsIAtom* atom = nsnull;
    classAtom.swap(atom);
    SetPtrValueAndType(atom, eAtomBase);
    return;
  }

  if (!EnsureEmptyAtomArray()) {
    return;
  }

  nsCOMArray<nsIAtom>* array = GetAtomArrayValue();
  
  if (!array->AppendObject(classAtom)) {
    Reset();
    return;
  }

  // parse the rest of the classnames
  do {
    start = iter;

    do {
      ++iter;
    } while (iter != end && !nsCRT::IsAsciiSpace(*iter));

    classAtom = do_GetAtom(Substring(start, iter));

    if (!array->AppendObject(classAtom)) {
      Reset();
      return;
    }

    // skip whitespace
    while (iter != end && nsCRT::IsAsciiSpace(*iter)) {
      ++iter;
    }
  } while (iter != end);

  return;
}
void
nsAttrValue::SetTo(const nsAttrValue& aOther)
{
  switch (aOther.BaseType()) {
    case eStringBase:
    {
      ResetIfSet();
      nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr());
      if (str) {
        str->AddRef();
        SetPtrValueAndType(str, eStringBase);
      }
      return;
    }
    case eOtherBase:
    {
      break;
    }
    case eAtomBase:
    {
      ResetIfSet();
      nsIAtom* atom = aOther.GetAtomValue();
      NS_ADDREF(atom);
      SetPtrValueAndType(atom, eAtomBase);
      return;
    }
    case eIntegerBase:
    {
      ResetIfSet();
      mBits = aOther.mBits;
      return;      
    }
  }

  MiscContainer* otherCont = aOther.GetMiscContainer();
  switch (otherCont->mType) {
    case eColor:
    {
      if (EnsureEmptyMiscContainer()) {
        MiscContainer* cont = GetMiscContainer();
        cont->mColor = otherCont->mColor;
        cont->mType = eColor;
      }
      break;
    }
    case eCSSStyleRule:
    {
      SetTo(otherCont->mCSSStyleRule);
      break;
    }
    case eAtomArray:
    {
      if (!EnsureEmptyAtomArray() ||
          !GetAtomArrayValue()->AppendObjects(*otherCont->mAtomArray)) {
        Reset();
      }
      break;
    }
#ifdef MOZ_SVG
    case eSVGValue:
    {
      SetTo(otherCont->mSVGValue);
    }
#endif
    default:
    {
      NS_NOTREACHED("unknown type stored in MiscContainer");
      break;
    }
  }
}