//
//  PSArmorSet.m
//  ArmorP3V1
//

#import "PSArmorSet.h"
#import "PSItemType.h"
#import "MatrixBuilder.h"
#import "PSItem.h"
#import "PSWrap.h"
#import "DecorationMatcher.h"
#import "PSMutex.h"

@implementation PSArmorSet

@synthesize totalSlotCount = _totalSlotCount;

@synthesize shellFire = _shellFire;
@synthesize shellWater = _shellWater;
@synthesize shellIce = _shellIce;
@synthesize shellThunder = _shellThunder;
@synthesize shellDragon = _shellDragon;

@synthesize bodyCopieCount = _bodyCopieCount;
@synthesize listArmor = _listArmor;
@synthesize setSkills = _setSkills;

@synthesize defMax = _defMax;
@synthesize defInitial = _defInitial;

@synthesize hunterRank = _hunterRank;
@synthesize townRank = _townRank;
@synthesize genderType = _genderType;
@synthesize hunterType = _hunterType;
@synthesize weaponSlotCount = _weaponSlotCount;

@synthesize mysetNumber = _mysetNumber;
@synthesize mysetName = _mysetName;
@synthesize mysetPicturePath = _mysetPicturePath;
@synthesize targetSkills = _targetSkills;

//@synthesize session = _session;

+(int)compareArmorSet:(id)a to:(id)b {
    if (a == b) {
        return 0;
    }
    if (a == nil) {
        return -1;
    }
    if (b == nil) {
        return 1;
    }
    PSArmorSet* that = a;
    PSArmorSet* target = b;
    
    int x = that.listArmor.count - target.listArmor.count;
    if (x != 0) {
        return x;
    }
    
    for (int i = 0; i < that.listArmor.count; ++ i) {
        PSWrap* wrap1 = [that.listArmor objectAtIndex:i];
        PSWrap* wrap2 = [target.listArmor objectAtIndex:i];
        x = [PSWrap comparePSWrap:wrap1 to: wrap2];
        if (x != 0) {
            return x;
        }
    }
    
    return 0;
}

-(NSUInteger)hash {
    int hash = 0;
    for (int i = 0; i < self.listArmor.count; ++ i) {
        PSWrap* deco = [self.listArmor objectAtIndex:i];
        hash += deco.item.name.hash;
    }
    return hash;
}

-(BOOL)isEqual:(id)object {
    if ([PSArmorSet compareArmorSet:self to:object] == 0) {
        return TRUE;
    }
    return FALSE;
}


-(id)init
{
    self = [super init];
    if (self) {
        _listArmor = [[NSMutableArray alloc]init];
    }else {
        [[PSMutex mainMutex] raiseMemoryError];
    }
    [[PSMutex mainMutex] showMemoryAlertIfError];
    return self;
}

-(void)dealloc
{
    [_listArmor release];
    [_targetSkills release];
    [_setSkills release];
    [_mysetName release];
    [_mysetPicturePath release];
    [super dealloc];
}

-(PSArmorSet *)createCopy
{
    PSArmorSet* obj = [[PSArmorSet alloc]init];
    [obj.listArmor addObjectsFromArray: self.listArmor];
    obj.weaponSlotCount = self.weaponSlotCount;
    obj.mysetNumber = self.mysetNumber;
    obj.mysetName = self.mysetName;
    obj.targetSkills = self.targetSkills;
    obj.hunterRank = self.hunterRank;
    obj.townRank = self.townRank;
    obj.genderType = self.genderType;
    obj.hunterType = self.hunterType;
    
    return obj;
}

-(void)calculateUseList:(SkillSet*)mask
{
    SkillSet* skills = nil;
    
    _bodyCopieCount = 0;
    _defMax = 0;
    _defInitial = 0;
    _totalSlotCount = 0;
    _shellFire = 0; //火耐性
    _shellWater = 0; //水耐性
    _shellIce = 0; //氷耐性
    _shellThunder = 0; //雷耐性
    _shellDragon = 0; //龍耐
    
    for (int i = 0; i < _listArmor.count; ++i) {
        PSWrap* wrap = [_listArmor objectAtIndex:i];
        
        if (mask.listKind != wrap.maskedSkills.listKind) {
            [wrap.maskedSkills cleanup];
            wrap.maskedSkills = [[SkillSet alloc]initWithColumn:mask];
            [wrap.maskedSkills set_only:wrap.item.skills];
            [wrap.maskedSkills release];
        }
    }

    PSWrap* body = [_listArmor objectAtIndex:ITEM_TYPE_BODY];

    if (body.item.isVirtual && body.sameArmors != nil) {
        PSWrap* seek = nil;
        for (int x = 0; x < body.sameArmors.count; ++ x) {
            PSWrap* internal = [body.sameArmors objectAtIndex:x];
            if (seek == nil || internal.item.defMax > seek.item.defMax) {
                seek = internal;
            }
        }
        if (seek != nil) {
            body = seek;
            
            if (mask.listKind != body.maskedSkills.listKind) {
                [body.maskedSkills cleanup];
                body.maskedSkills = [[SkillSet alloc]initWithColumn:mask];
                [body.maskedSkills set_only:body.item.skills];
            }
        }
    }
    
    for (int i = 0; i < _listArmor.count; ++i) {
        PSWrap* wrap = [_listArmor objectAtIndex: i];
        BOOL isFromNull = FALSE;
        if (wrap.item.isVirtual && wrap.sameArmors != nil) {
            PSWrap* seek = nil;
            for (int x = 0; x < wrap.sameArmors.count; ++ x) {
                PSWrap* internal = [wrap.sameArmors objectAtIndex:x];
                if (seek == nil || internal.item.defMax > seek.item.defMax) {
                    seek = internal;
                }
            }
            if (seek != nil) {
                wrap = seek;
                isFromNull = TRUE;
            }
        }
        PSItem* item = wrap.item;
        
        _defMax += item.defMax;
        _defInitial += item.defInitial;
        _shellFire += item.shellFire; //火耐性
        _shellWater += item.shellWater; //水耐性
        _shellIce += item.shellIce; //氷耐性
        _shellThunder += item.shellThunder; //雷耐性
        _shellDragon += item.shellDragon; //龍耐
        _totalSlotCount += item.slotCount;
        
        if (item.isCopieSkill) {
            wrap = body;
            item = wrap.item;
            _bodyCopieCount++;
            isFromNull = FALSE;
        }
        
        if (skills == nil) {
            skills = [[SkillSet alloc]initWithColumn:mask];
        }
        if (mask != nil && wrap != nil) {
            if (isFromNull) {
            }else {
                [skills sum_fixed: wrap.maskedSkills];
            }
        } else {
            if (isFromNull) {
            }else {
                [skills sum_all: wrap.item.skills];
            }
        }
    }
    if (_setSkills != nil) {
        [_setSkills release];
    }
    _setSkills = skills;
    [_setSkills retain];
    [skills release];
}

-(int)createChildSet:(NSMutableArray*)result checker:(NSMutableSet*) already
{
    int count = 0;
    for(int i = 0; i < _listArmor.count; ++ i) {
        NSMutableArray* newSet = [[NSMutableArray alloc]init];
        [newSet addObjectsFromArray: _listArmor];
        
        PSWrap* armor = [_listArmor objectAtIndex:i];
        NSMutableArray* childList = armor.childArmors;
        
        for(int n = 0; n < childList.count; ++ n) {
            PSItem *e = [childList objectAtIndex: n];
            [newSet replaceObjectAtIndex:i withObject: e];
            
            PSArmorSet* newSetObj = [self createCopy];
            [newSetObj.listArmor removeAllObjects];
            [newSetObj.listArmor addObjectsFromArray: newSet];
            
            if (already != nil) {
                if (![already containsObject: newSetObj]) {
                    [result addObject: newSetObj];
                    count ++;
                }
            }
            [newSetObj release];
        }
        [newSet release];
    }
    return count;
}

-(void)drawArmorSetSub:(NSMutableArray *)column:(PSWrap *)item:(SkillSet*)targetSkills:(BOOL)useExtract {
    NSArray* ar1 = item.sameArmors;
    BOOL did = FALSE;
    if (item.item.isVirtual && !useExtract) {
    }else if (useExtract) {
        for (int i = 0; i < ar1.count; ++ i) {
            PSWrap* wrap = [ar1 objectAtIndex: i];
            if (targetSkills != nil) {
                if ([PSSession isExistForSkill:targetSkills :wrap.item] == FALSE) {
                    continue;
                }
            }
            [self drawArmorSetSub:column : wrap: targetSkills: useExtract ];
            did = TRUE;
        }
        if (item.item.isVirtual == FALSE){ 
            did = FALSE;
        }
    }
    if (did == FALSE) {
        [column addObject: item];
    }
}

-(void)drawArmorSets: (NSMutableArray*)result :(BOOL)useExtract:(SkillSet*)targetSkill:(id<IProgress>)progress:(int)searchMaxCount {
    MatrixBuilder* matrix = [[MatrixBuilder alloc]init];

    for(int i = 0; i < _listArmor.count; ++ i) {
        PSWrap*item = [_listArmor objectAtIndex: i];
        NSMutableArray *column = [[NSMutableArray alloc]init];
        if (useExtract) {
            [self drawArmorSetSub:column :item: targetSkill: useExtract];
        }else if (item.item.isVirtual) {
            [self drawArmorSetSub:column :item: targetSkill: useExtract];
            /*
            PSWrap* next = nil;
            PSItem* nest = item.item;
            switch (item.item.slotCount) {
                case 0:
                    next = [PSWrap getVirtualWrap:nest.itemType :1];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    next = [PSWrap getVirtualWrap:nest.itemType :2];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    next = [PSWrap getVirtualWrap:nest.itemType :3];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    next = [PSWrap getVirtualWrap:nest.itemType :VIRTUAL_COPIE];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    break;
                case 1:
                    next = [PSWrap getVirtualWrap:nest.itemType :2];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    next = [PSWrap getVirtualWrap:nest.itemType :3];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    break;
                case 2:
                    next = [PSWrap getVirtualWrap:nest.itemType :3];
                    [self drawArmorSetSub:column :next: targetSkill: useExtract];
                    break;
                case 3:
                    break;
                default:
                    NSLog(@"expand %d", item.item.slotCount);
                    break;
            }*/
        }else {
            [column addObject:item];
        }
        [matrix addColumn: column];
        [column release];
    }
    
    [matrix start];
    NSMutableArray *fetch = [[NSMutableArray alloc]init];
    
    while([matrix hasNext]) {
        if (result.count >= searchMaxCount) {
            break;
        }
        if (progress.cancelFlag) {
            break;
        }
        [fetch removeAllObjects];
        [matrix fetchNext: fetch];
        
        PSArmorSet* set = [self createCopy];
        [set.listArmor removeAllObjects];
        for(int i = 0; i < fetch.count; ++ i) {
            PSWrap* item = [fetch objectAtIndex: i];
            [set.listArmor addObject: item];
        }
        [set calculateUseList: FALSE];
        [result addObject: set];
        [set release];
    }
    [matrix release];
    [fetch release];
}

-(void)compactDecorationSlotList:(NSMutableArray *)array {
    /*public void compactDecorationSlotList(PSArmorSet set, List<DecorationSlot> list) {
        Comparator<DecorationSlot> c = new Comparator<DecorationSlot>() {
            
            public int compare(DecorationSlot t, DecorationSlot t1) {
                int x = t.mapDecoration.compareTo(t1.mapDecoration);
                if (x == 0) {
                    x = t.mapBodyDecoration.compareTo(t1.mapBodyDecoration);
                }
                return x;
            }
        };
        TreeSet<DecorationSlot> tree = new TreeSet<DecorationSlot>(c);
        tree.addAll(list);
        if (tree.size() != list.size()) {
            list.clear();
            list.addAll(tree);
        }
    }*/    
}

-(void)getShellValueAsText:(NSMutableString*)str {
    int shellTotal = _shellFire + _shellWater + _shellIce + _shellThunder + _shellDragon;
    [str appendFormat: @"火[%d]水[%d]氷[%d]雷[%d]龍[%d]計[%d]", _shellFire, _shellWater, _shellIce, _shellThunder, _shellDragon, shellTotal];
}

-(void)printArmorSetDetail: (NSMutableString*) strArmor: (NSMutableString*)strCharm: (NSMutableString*)strMaterials: (BOOL)skillseek {
    DecorationMatcher* matcher = nil;
    NSMutableArray* listSlot = [[NSMutableArray alloc]init];
    BOOL retireSearch = FALSE;
    PSArmorSet* set = self;
    [set calculateUseList: FALSE];
    
    PSSession* sess = [[PSSession alloc]init];
    sess.searchGenderType = _genderType;
    sess.searchHunterRank = _hunterRank;
    sess.searchHunterType = _hunterType;
    sess.searchTownRank = _townRank;
    sess.searchSkills = _targetSkills;
    
    matcher = [[DecorationMatcher alloc]initWithData:sess];
    [sess release];
    //    matcher = new DecorationMatcher(set.session, set.targetSkills, set.session == this.session ? items : null);
    [matcher canHaveEnoughDecoration:self :TRUE :listSlot];

    if (skillseek) {
        if (self.weaponSlotCount < 0) {
            PSArmorSet* tmp = [self createCopy];
            tmp.weaponSlotCount = 0;
            set = tmp;
        }
        /*
        PlusOneFinder finder = new PlusOneFinder(set.session, set.targetSkills, set.session == this.session ? items : null);
        finder.useNestedFind = true;
        ArrayList<DecorationSlot> prevResult = new ArrayList<DecorationSlot>(listSlot);
        finder.findAnyPlusOne(set, 10000, prevResult, null);
        
        List<PSArmorSet> tryList = new ArrayList<PSArmorSet>();
        tryList.add(set);
        finder.tryFixMinus(tryList, listSlot);
        finder.getResultMap(tryList);
        retireSearch = finder.wasTimeout;
        [tmp release];
         */
    }

    //[set compactDecorationSlotList:listSlot];
    
    NSString* gender = @"-";
    if (set.genderType == 1) {
        gender = @"男";
    }else if (self.genderType == 2) {
        gender = @"女";
    }else if (set.genderType == 0) {
        gender = @"男女兼用";
    }
    NSString* hunter = @"-";
    if (set.hunterType == 1) {
        hunter = @"剣士";
    }else if (set.hunterType == 2) {
        hunter = @"ガンナー";
    }else if (set.hunterType == 0) {
        hunter = @"剣士ガンナー兼用";
    }
    NSString* hr = [[NSString alloc]initWithFormat:@"HR%d", set.hunterRank];
    NSString* tr = [[NSString alloc]initWithFormat:@"村%d", set.townRank];
    int defInitial = set.defInitial;
    int defMax = set.defMax;
    int totalSlot = set.totalSlotCount;
    int weaponSlot = set.weaponSlotCount;
    
    [strArmor appendFormat: @"□%@／%@□%@／%@\n", gender, hunter, hr, tr];
    [hr release];
    [tr release];
    
    [strArmor appendString:@"+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n"];
    [strArmor appendFormat: @"防御力 [%d→%d]／スロ数[%d]／武器スロ[%d]\n", defInitial, defMax,totalSlot,weaponSlot];

    for (int i = 0; i < set.listArmor.count; ++i) {
        NSString* armorTitle = nil;
        PSWrap* item = [set.listArmor objectAtIndex:i];
        /*if (item.item.isVirtualNone) {
            continue;
        }*/

        switch(i) {
            case 0:
                armorTitle = @"頭装備";
                break;
            case 1:
                armorTitle = @"胴装備";
                break;
            case 2:
                armorTitle = @"腕装備";
                break;
            case 3:
                armorTitle = @"腰装備";
                break;
            case 4:
                armorTitle = @"足装備";
                break;
            case 5:
                armorTitle = @"お守り";
                break;
        }
        
        [strArmor appendString: armorTitle];
        [strArmor appendString: @":"];
        [item.item getArmorNameAndSlot:strArmor];
        [strArmor appendString: @"\n"];
    }
    [strArmor appendString:@"耐性値:"];
    [set getShellValueAsText:strArmor];
    [strArmor appendString:@"\n"];

    [strArmor appendString:@"ポイント:"];
    [set calculateUseList: FALSE];
    [set.setSkills sortByPower];
    [set.setSkills skillToString:strArmor :nil :FALSE];
    [strArmor appendString:@"\n"];
    
    NSMutableDictionary* printMap = [[NSMutableDictionary alloc]init];
    NSEnumerator* listSlotEN = [listSlot objectEnumerator];
    
    for (int i = 0; i < 10000; ++ i) {
        DecorationSlot* deco = [listSlotEN nextObject];
        if (deco == nil) {
            break;
        }
        
        SkillSet* skill = [[SkillSet alloc]init];
        [deco getFullDecorationsSkills:skill];
        [skill sum_all:set.setSkills];
        [deco updateAnotherSkill: set];
        
        NSMutableDictionary* e = [printMap objectForKey:skill];

        if (e == nil) {
            e = [[NSMutableDictionary alloc]init];
            [printMap setObject:e forKey:skill];
        }
        [e setObject:deco forKey: skill];

        //[canonicalSkill release];
        [skill release];
    }

    NSEnumerator* en = [printMap keyEnumerator];
    int counter = 1;
    while (TRUE) {
        id obj = [en nextObject];
        if (obj == nil) {
            break;
        }
        SkillSet* key = obj;
        NSMutableDictionary* elist0 = [printMap objectForKey:key];
        NSEnumerator* elist = [elist0 keyEnumerator];
        
        while (TRUE) {
            id obj2 = [elist nextObject];
            if (obj2 == nil) {
                break;
            }

            SkillSet *key2 = obj2;
            
            if (key2.count == 0) {
                continue;
            }
            DecorationSlot* deco = [elist0 objectForKey: key2];
            SkillSet* skills = [[SkillSet alloc]init];
            [deco getFullDecorationsSkills:skills];
            [skills sum_all: set.setSkills];
            [skills sortByPower];

            [strCharm appendString:@"+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n"];
            [strCharm appendFormat:@"装飾品%d:", counter];
            counter ++;
            
            [deco toDecorationString:strCharm];
            [strCharm appendString:@"\n"];
            [strCharm appendString:@"ポイント:"];
            [skills skillToString:strCharm :nil :FALSE];
            [strCharm appendString:@"\n"];
        }
        //[strCharm appendString:@"+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n"];
        [strCharm appendString:@"スキル:"];
        [strCharm appendString:@"\n"];
        NSMutableArray * nameList = [key getNamedSkillNameForDisplay];
        for (int i = 0; i < nameList.count; ++ i) {
            [strCharm appendFormat: @" %@\n", [nameList objectAtIndex:i]]; 
        }
    }
    
    if (retireSearch) {
        [strArmor appendString: @"---------これ以上表示できません------- (10秒ルール)\n"];
    }
    
    //[strArmor appendString:@"\n"];
    
    /*
    for (int i = 0; i < set.listArmor.count; ++ i) {
        PSWrap* item = [set.listArmor objectAtIndex:i];
        if (item.item.isVirtualNone) {
            continue;
        }
        if (item.item.isVirtual && item.item.skills.count == 0 && item.item.slotCount == 0) {
            continue;
        }
        [strMaterials appendString:@"+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n"];
        [item.item printContents:strMaterials];
    }*/
    
    NSMutableDictionary* decoSet = [[NSMutableDictionary alloc]init];
    en = [listSlot objectEnumerator];
    while (true) {
        DecorationSlot* slot = [en nextObject];
        if (slot == nil) {
            break;
        }
        DecorationCount* mapDecoration = slot.mapDecoration;
        DecorationCount* mapBodyDecoration = slot.mapBodyDecoration;
        
        for (int k = 0; k < mapDecoration.count; ++k) {
            PSWrap* deco = [mapDecoration decoAt:k];
            if (deco != 0) {
                [decoSet setObject:deco forKey:deco];
            }
        }
        for (int k = 0; k < mapBodyDecoration.count; ++k) {
            PSWrap* deco = [mapBodyDecoration decoAt:k];
            if (deco != 0) {
                [decoSet setObject:deco forKey:deco];
            }
        }
    }
    NSEnumerator *e = [decoSet keyEnumerator];
    if (set.weaponSlotCount < 0) {
        //nothing
    }else {
        while(TRUE) {
            PSWrap* item = [e nextObject];
            if (item == nil) {
                break;
            }
            [strMaterials appendString:@"+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\n"];
            [item.item printContents:strMaterials];
        }
    }
    
    if (self != set) {
        [set release];
    }
}

-(NSString *)description {
    NSMutableString* str = [[NSMutableString alloc]init];
    
    for (int i = 0; i < _listArmor.count; ++ i) {
        PSWrap* wrap = [_listArmor objectAtIndex:i];
        [str appendFormat:@"%@[%d]", wrap.item.name, wrap.item.slotCount];
        if (wrap.item.itemType == ITEM_TYPE_CHARM) {
            [str appendFormat:@"%@", wrap.item.skills];
        }else {
            [str appendString:@","];
        }
    }
    
    NSString* ret = [NSString stringWithString:str];
    [str release];
    return ret;
}

@end
