//
//  SkillKindRepository.m
//  MHP3SkillSim
//

#import "SkillDB.h"
#import "Repository.h"
#import "PSMutex.h"

@implementation SkillDB

@synthesize listCategory = _listCategory;
@synthesize listCategoryKindOrder = _listCategoryKindOrder;
@synthesize listKindMaster = _listKindMaster;
@synthesize noCategory = _noCategory;

-(id) init
{
    self = [ super init ];
    if (self) {
        _listCategory = [[NSMutableArray alloc]init];
        _listCategoryKindOrder = [[NSMutableArray alloc]init];
        _listKindMaster = [[NSMutableArray alloc]init];
        _noCategory = [[SkillCategory alloc]init];
        _noCategory.name = @"カテゴリ無し";
        [_listCategory addObject:_noCategory];
        
        if (_listCategory == nil || _listCategoryKindOrder == nil || _listKindMaster == nil) {
            [[PSMutex mainMutex] raiseMemoryError];
            self = nil;
            [super dealloc];
        }
    }else {
        [[PSMutex mainMutex] raiseMemoryError];
    }
    return self;
}

-(void)dealloc {
    [_noCategory release];
    [_listCategory release];
    [_listCategoryKindOrder release];
    [_listKindMaster release];
    [super dealloc];
}

-(int)countOfCategory {
    return _listCategory.count;
}

-(int)indexOfCategory: (NSString*)categoryName {
    for (int i = 0; i < _listCategory.count; i ++) {
        SkillCategory* cate = [_listCategory objectAtIndex:i];
        if ([cate.name isEqual:categoryName]) {
            return i;
        }
    }
    return -1;
}

-(id)categoryOfIndex: (int)index {
    return [_listCategory objectAtIndex:index];
}

-(int)countOfKind {
    return _listKindMaster.count;
}

-(int)indexOfKind: (NSString*)kindName {
    for (int i = 0; i < _listKindMaster.count; i ++) {
        SkillKind* kind = [_listKindMaster objectAtIndex:i];
        if ([kind.name isEqual:kindName]) {
            return i;
        }
    }
    return -1;
}

-(id)kindOfIndex: (int)index {
    return [_listKindMaster objectAtIndex:index];
}

-(SkillKind*) findSkillKindByName:(NSString *)name
{
    for (int i = 0; i < _listKindMaster.count; ++ i) {
        SkillKind* kind = [_listKindMaster objectAtIndex: i];
        if (kind.name.length == name.length) {
            if (kind.name.hash == name.hash) {
                if ([kind.name isEqual: name]) {
                    return kind;
                }
            }
        }
    }
    return nil;
}

-(void)addSkillName:(NSString*) skillName : (NSString*) kindName : (int) point : (BOOL) positive
{
    SkillPoint* sp = [[SkillPoint alloc]init];
    sp.pointName = skillName;
    sp.skillPoint = point;
    sp.positiveRange = positive;

    SkillKind* kind = [self findSkillKindByName: kindName];
    if (kind == nil) {
        kind = [[SkillKind alloc] init];
        kind.name = kindName;
        [_listKindMaster addObject: kind];
        [kind release];
    }
    sp.skillKind = kind;
    [_noCategory.listPoint addObject:sp];
    [sp release];
    
    if (point < 0 && positive == NO) {
        NSString* str = [[NSString alloc]initWithFormat: @"%@を除外", skillName];
        sp = [[SkillPoint alloc]init];
        sp.pointName = str;
        sp.skillKind = kind;
        sp.skillPoint = point + 1;
        sp.positiveRange = YES;
        [_noCategory.listPoint addObject:sp];
        [sp release];
        [str release];
    }
}

-(void)setCategory : (NSString*)categoryName : (NSString*)skillName
{
    SkillPoint* point = nil;
    SkillCategory* skillCategory = nil;
    BOOL error = FALSE;
    
    for (int i = 0; i < _noCategory.count; ++ i) {
        SkillPoint* p = [_noCategory pointAtIndex:i];
        if ([p.pointName isEqual: skillName]) {
            point = p;
            break;
        }
    }
    
    if (point == nil) {
        error = TRUE;
    }
    
    for (int i = 0; i < _listCategory.count; ++ i) {
        SkillCategory* c = [_listCategory objectAtIndex: i];
        if ([c.name isEqual:categoryName]) {
            skillCategory = c;
            break;
        }
        
        if (error && point != nil) {
            for (int j = 0; j < c.listPoint.count; ++ j) {
                SkillPoint *p = [c.listPoint objectAtIndex:j];
                if ([p.pointName isEqual: skillName]) {
                    error = FALSE;
                    break;
                }
            }
        }
    }

    if (!point) {
        //NSLog(@"already done -%@-%@-", categoryName, skillName);
        return;
    }
    if (error) {
        NSLog(@"err whene create skill object -%@-%@-", categoryName, skillName);
        return;
    }
    
    if (skillCategory == nil) {
        skillCategory = [[SkillCategory alloc]init];
        skillCategory.name = categoryName;
        [_listCategory addObject: skillCategory];
        [skillCategory release];
    }

    [skillCategory.listPoint addObject:point];
    point.category = skillCategory;
    [_noCategory.listPoint removeObject:point];

    for (int i = 0; i < _noCategory.count; ++ i) {
        SkillPoint* p = [_noCategory pointAtIndex:i];
        if (p.skillKind == point.skillKind) {
            [skillCategory.listPoint addObject:p];
            [_noCategory.listPoint removeObject:p];
            i --;
        }
    }
}

-(void)sort
{
    for (int i = 0; i < _listCategory.count; ++ i) {
        SkillCategory* cate = [_listCategory objectAtIndex:i];
        NSMutableArray* listPoint = cate.listPoint;
        [listPoint sortUsingFunction:sortByCategory context:self];
    }
    [_listCategory removeObject: _noCategory];
    [_listCategory addObject: _noCategory];
}

int sortByCategory(id a, id b, void* context)
{
    SkillPoint *p1 = (SkillPoint*)a;
    SkillPoint *p2 = (SkillPoint*)b;
    SkillDB* skillDB = (SkillDB*)context;
    int x = 0;
    
    if (x == 0) {
        if (p1.skillPoint < 0 && p2.skillPoint >= 0) {
            x = 1;
        }
        if (p2.skillPoint < 0 && p1.skillPoint >= 0) {
            x = -1;
        }
    }

    if (x == 0) {
        SkillKind* k1 = p1.skillKind;
        SkillKind* k2 = p2.skillKind;
        if (k1 != k2) {
            int f1 = [skillDB indexOfKind:k1.name];
            int f2 = [skillDB indexOfKind:k2.name];
            x = f1 - f2;
        }
    }    

    if (x == 0) {
        x = p2.skillPoint - p1.skillPoint;
    }


    if (x < 0) return NSOrderedAscending;
    if (x > 0) return NSOrderedDescending;
    return NSOrderedSame;
}

-(SkillPoint*) getNearSkillPoint: (SkillPoint*) point {
    SkillPoint* found = nil;

    
    for (int i = 0; i < [self countOfCategory]; ++ i) {
        SkillCategory* cate = [self categoryOfIndex: i];
        
        for(int j = 0; j < cate.count; ++ j) {
            SkillPoint* seek = [cate pointAtIndex: j];
            
            if (seek.skillPoint % 5 != 0) {
                continue;
            }
            if (seek.skillKind == point.skillKind) {
                if (point.skillPoint >= 0) {
                    if (point.skillPoint >= seek.skillPoint && seek.skillPoint >= 0) {
                        if (found == nil || found.skillPoint < seek.skillPoint) {
                            found = seek;
                        }
                    }
                } else {
                    if (point.skillPoint <= seek.skillPoint && seek.skillPoint <= 0) {
                        if (found == nil || found.skillPoint > seek.skillPoint) {
                            found = seek;
                        }
                    }
                }
            }
        }
    }
    return found;
}

-(SkillPoint*) getMatchSkillPoint: (SkillPoint*) point {
    for (int i = 0; i < [self countOfCategory]; ++ i) {
        SkillCategory* cate = [self categoryOfIndex: i];
        
        for(int j = 0; j < cate.count; ++ j) {
            SkillPoint* seek = [cate pointAtIndex :j];
            if (seek.skillKind == point.skillKind && seek.skillPoint == point.skillPoint) {
                return seek;
            }
        }
    }
    return nil;
}

-(SkillPoint*)pointNameToPoint:(NSString*)pointName {
    for (int i = 0; i < self.countOfCategory; ++ i) {
        SkillCategory* cate = [self categoryOfIndex: i];
        
        for(int j = 0; j < cate.count; ++ j) {
            SkillPoint* seek = [cate pointAtIndex: j];
            if ([seek.pointName isEqual:pointName]) {
                return seek;
            }
            
        }
    }
    return nil;
}

@end
