+/* }}} */
+/* Section Class {{{ */
+@interface Section : NSObject {
+ _transient Database *database_;
+
+ _H<NSString> name_; // Themes (SpringBoard)
+ _H<NSString> simplified_; // SpringBoard
+ _H<NSString> localized_; // TrampolĂn (via Google Translate ;P)
+ _H<NSString> base_; // Themes
+
+ NSUInteger count_;
+ BOOL visible_;
+
+ _transient Section *parent_; // Themes
+ _H<NSMutableArray> subsections_;
+}
+
+@property (nonatomic, readonly) NSString *name;
+@property (nonatomic, readonly) NSString *simplified;
+@property (nonatomic, readonly) NSString *localized;
+@property (nonatomic, readonly) NSString *base;
+
+@property (nonatomic, assign) BOOL visible;
+
+@property (nonatomic, assign) NSUInteger count;
+- (void) addToCount;
+
+@property (nonatomic, assign) Section *parent;
+@property (nonatomic, retain) NSArray *subsections;
+- (void) addSubsection:(Section *)subsection;
+
+@end
+
+@implementation Section
+@synthesize count=count_, visible=visible_;
+
+- (NSString *) name {
+ return name_;
+}
+
+- (NSString *) simplified {
+ return simplified_;
+}
+
+- (NSString *) localized {
+ return localized_;
+}
+
+- (NSString *) base {
+ return base_;
+}
+
+- (Section *) parent {
+ return parent_;
+}
+
+- (void) setParent:(Section *)parent {
+ parent_ = parent;
+}
+
+- (NSArray *) subsections {
+ return subsections_;
+}
+
+- (void) setSubsections:(NSArray *)subsections {
+ subsections_ = [[subsections mutableCopy] autorelease];
+}
+
+- (void) addSubsection:(Section *)subsection {
+ [subsections_ addObject:subsection];
+}
+
++ (NSString *) simplifyName:(NSString *)title {
+ const char *data = [title UTF8String];
+ size_t size = [title length];
+
+ static Pcre square_r("^\\[(.*)\\]$");
+ if (square_r(data, size))
+ return [self simplifyName:square_r[1]];
+
+ static Pcre paren_r("^\\((.*)\\)$");
+ if (paren_r(data, size))
+ return [self simplifyName:paren_r[1]];
+
+ return title;
+}
+
++ (NSString *) localizeName:(NSString *)section {
+ return [[NSBundle mainBundle] localizedStringForKey:section value:nil table:@"Sections"];
+}
+
+- (NSComparisonResult) compareByLocalized:(Section *)section {
+ NSString *lhs(localized_);
+ NSString *rhs([section localized]);
+
+ /*if ([lhs length] != 0 && [rhs length] != 0) {
+ unichar lhc = [lhs characterAtIndex:0];
+ unichar rhc = [rhs characterAtIndex:0];
+
+ if (isalpha(lhc) && !isalpha(rhc))
+ return NSOrderedAscending;
+ else if (!isalpha(lhc) && isalpha(rhc))
+ return NSOrderedDescending;
+ }*/
+
+ return [lhs compare:rhs options:LaxCompareOptions_];
+}
+
+- (id) initWithName:(NSString *)name database:(Database *)database {
+ if ((self = [super init])) {
+ database_ = database;
+
+ subsections_ = [NSMutableArray array];
+
+ if (name != nil) {
+ name_ = name;
+
+ static Pcre name_r("^(.*?) \\((.*)\\)$");
+ if (name_r([name UTF8String], [name length])) {
+ base_ = name_r[1];
+ name = name_r[2];
+ }
+
+ simplified_ = [[self class] simplifyName:name];
+ localized_ = [[self class] localizeName:simplified_];
+
+ NSDictionary *metadata([Sections_ objectForKey:(name ?: @"")]);
+ NSNumber *hidden(metadata == nil ? nil : [metadata objectForKey:@"Hidden"]);
+ visible_ = hidden == nil || ![hidden boolValue];
+ } else {
+ name_ = simplified_ = @"No Section";
+ localized_ = UCLocalize("NO_SECTION");
+ visible_ = YES;
+ }
+ } return self;
+}
+
+// The skipRelated parameter is to protect against cycles when performing
+// subsection and parent related changes.
+- (void) setVisible:(BOOL)visible skipRelated:(Section *)related {
+ visible_ = visible;
+
+ NSMutableDictionary *metadata([Sections_ objectForKey:name_]);
+ if (metadata == nil) {
+ metadata = [NSMutableDictionary dictionaryWithCapacity:2];
+ [Sections_ setObject:metadata forKey:name_];
+ }
+
+ [metadata setObject:[NSNumber numberWithBool:(visible_ == NO)] forKey:@"Hidden"];
+ Changed_ = true;
+
+ if (parent_ == nil) {
+ // If you turn off a top-level section, do the same to all its subsections.
+ if (!visible_) {
+ for (Section *section in (id) subsections_) {
+ if (section != related)
+ [section setVisible:visible_ skipRelated:self];
+ }
+ }
+ } else {
+ // If you turn on a subsection, make sure its top-level section is on.
+ if (visible_) {
+ if (parent_ != related)
+ [parent_ setVisible:visible_ skipRelated:self];
+ }
+ }
+}
+
+- (void) setVisible:(BOOL)visible {
+ [self setVisible:visible skipRelated:nil];
+}
+
+- (void) addToCount {
+ count_ += 1;
+}
+
+@end
+