//
// CSSCombinatorSelector.m
// HTMLKit
//
// Created by Iska on 12/10/15.
// Copyright © 2015 BrainCookie. All rights reserved.
//
#import "CSSCombinatorSelector.h"
#import "HTMLElement.h"
#import "HTMLNode+Private.h"
#pragma mark - Declarations
@interface CSSChildOfElementCombinatorSelector : CSSCombinatorSelector
@end
@interface CSSDecendantOfElementCombinatorSelector : CSSCombinatorSelector
@end
@interface CSSAdjacentSiblingCombinatorSelector : CSSCombinatorSelector
@end
@interface CSSGeneralSiblingCombinatorSelector : CSSCombinatorSelector
@end
#pragma mark - Base Combinator
@interface CSSCombinatorSelector ()
{
CSSSelector *_selector;
}
@property (nonatomic, strong, readonly) CSSSelector *selector;
@end
@implementation CSSCombinatorSelector
@synthesize selector = _selector;
+ (instancetype)childOfElementCombinator:(CSSSelector *)selector
{
return [[CSSChildOfElementCombinatorSelector alloc] initWithSelector:selector];
}
+ (instancetype)descendantOfElementCombinator:(CSSSelector *)selector
{
return [[CSSDecendantOfElementCombinatorSelector alloc] initWithSelector:selector];
}
+ (instancetype)adjacentSiblingCombinator:(CSSSelector *)selector
{
return [[CSSAdjacentSiblingCombinatorSelector alloc] initWithSelector:selector];
}
+ (instancetype)generalSiblingCombinator:(CSSSelector *)selector
{
return [[CSSGeneralSiblingCombinatorSelector alloc] initWithSelector:selector];
}
- (instancetype)initWithSelector:(CSSSelector *)selector
{
self = [super init];
if (self) {
_selector = selector;
}
return self;
}
@end
#pragma mark - Child OfElement Combinator
@implementation CSSChildOfElementCombinatorSelector
- (BOOL)acceptElement:(HTMLElement *)element
{
HTMLElement *parent = element.parentElement;
return parent != nil && [self.selector acceptElement:parent];
}
- (NSString *)debugDescription
{
return [NSString stringWithFormat:@"%@ > ", self.selector.debugDescription];
}
@end
#pragma mark - Decendant Of Element Combinator
@implementation CSSDecendantOfElementCombinatorSelector
- (BOOL)acceptElement:(HTMLElement *)element
{
HTMLElement *parent = element.parentElement;
while (parent != nil) {
if ([self.selector acceptElement:parent]) {
return YES;
}
parent = parent.parentElement;
}
return NO;
}
- (NSString *)debugDescription
{
return [NSString stringWithFormat:@"%@ ", self.selector.debugDescription];
}
@end
#pragma mark - Adjacent Sibling Combinator
@implementation CSSAdjacentSiblingCombinatorSelector
- (BOOL)acceptElement:(HTMLElement *)element
{
HTMLNode *previous = element.previousSiblingElement;
if (previous == nil || previous.nodeType != HTMLNodeElement) {
return NO;
}
return [self.selector acceptElement:previous.asElement];
}
- (NSString *)debugDescription
{
return [NSString stringWithFormat:@"%@ + ", self.selector.debugDescription];
}
@end
#pragma mark - General Sibling Combinator
@implementation CSSGeneralSiblingCombinatorSelector
- (BOOL)acceptElement:(HTMLElement *)element
{
HTMLNode *previous = element.previousSiblingElement;
while (previous != nil && previous.nodeType == HTMLNodeElement) {
if ([self.selector acceptElement:previous.asElement]) {
return YES;
}
previous = previous.previousSiblingElement;
}
return NO;
}
- (NSString *)debugDescription
{
return [NSString stringWithFormat:@"%@ ~ ", self.selector.debugDescription];
}
@end