// Copyright 1997-2002 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.

#import "OWCSSSelector.h"

#import "OWSGMLTag.h"

#import <Foundation/Foundation.h>
#import <OmniBase/OmniBase.h>

RCS_ID("$Header: /Network/Source/CVS/OmniGroup/Frameworks/OWF/CSS.subproj/OWCSSSelector.m,v 1.16 2002/03/09 01:53:48 kc Exp $")

@implementation OWCSSSelector

-init;
{
    if (! [super init])
        return nil;    
    tagName = nil;
    className = nil;;
    idName = nil;
    pseudoClassName = nil;
    score = 0;
    return self;
}

- (void)dealloc;
{
    [tagName release];
    [className release];
    [idName release];
    [pseudoClassName release];
    [super dealloc];
}

- (void)setTagName:(NSString *)newName;
{
    OBASSERT(tagName == nil);
    tagName = [newName copy];
}

- (void)setClassName:(NSString *)newName;
{
    OBASSERT(className == nil);
    className = [newName copy];
}

- (void)setIDName:(NSString *)newName;
{
    OBASSERT(idName == nil);
    idName = [newName copy];
}

#warning WJS: We need to think of how to redo pseudoclasses, since in CSS2 you can have MULTIPLE pseudoclasses per selector.  I think we really just need a "flags" structure, like
/*
    struct {
        // Pseudo-class
        unsigned int first-child;
        // Link pseudo-classes
        unsigned int link:1, visited:1;
        // Language pseudo-class:
        unsigned int lang:1; // requires extra parameter, the language in question!
        // Active pseudo-classes
        unsigned int hover:1, active:1, focus:1;
        // Pseudo-elements
        unsigned int firstLine:1, firstLetter:1, before:1, after:1;
    } psuedoFlags;
*/
- (void)setPseudoClassName:(NSString *)newName;
{
//    OBASSERT(pseudoClassName == nil);
// WJS: 2/14/2001: Boy is this ever wrong, right now we can't have multiple pseudo-classes, yikes!
    [pseudoClassName release];
    pseudoClassName = [newName copy];
}

- (NSString *)tagName;
{
    return tagName;
}

- (NSString *)className;
{
    return className;
}

- (NSString *)idName;
{
    return idName;
}

- (NSString *)pseudoClassName;
{
    return pseudoClassName;
}

- (BOOL)isEqual:(OWCSSSelector *)selector;
{
    if ((selector->tagName != tagName) && (selector->tagName && ![selector->tagName isEqualToString:tagName]))
        return NO;
    if ((selector->className != className) && (selector->className && ![selector->className isEqualToString:className]))
        return NO;
    if ((selector->idName != idName) && (selector->idName && ![selector->idName isEqualToString:idName]))
        return NO;
    if ((selector->pseudoClassName != pseudoClassName) && (selector->pseudoClassName && ![selector->pseudoClassName isEqualToString:pseudoClassName]))
        return NO;
    return YES;
}

- (BOOL)matchesTag:(OWSGMLTag *)tag;
{
    if (tagName != nil && ![tagName isEqualToString:[tag name]])
        return NO;
    if (className != nil && ![className isEqualToString:[tag valueForAttribute:@"class"]])
        return NO;
    if (idName != nil && ![idName isEqualToString:[tag valueForAttribute:@"id"]])
        return NO;
    // We only support pseudo-classes on anchor tags, so if this selector has a pseudo-class and it's not an anchor tag, we die. If we do have a pseudo-class AND it is an anchor, then the only way we are in here is if it's one of the pseudoclasses we support.
    if (pseudoClassName != nil && ![[tag name] isEqualToString:@"a"])
        return NO;

    return YES;
}

// From http://www.w3.org/TR/REC-CSS1#cascading-order - not quite correct, but close.
- (unsigned int)score;
{
    if (score == 0) {
        if (tagName)
            score += 1;
        if (className)
            score += 10;
        if (pseudoClassName)
            score += 10;
        if (idName)
            score += 100;
    }
    
    return score;
}

- (NSString *)descriptionWithLocale:(NSDictionary *)locale indent:(unsigned)level;
{
    return [NSString stringWithFormat:@"{tagName = '%@', className = '%@', idName = '%@', pseudoClassName = '%@'}", tagName, className, idName, pseudoClassName];
}

@end
