/*
 * This file is part of Lorenz, licensed under the MIT License (MIT).
 *
 * Copyright (c) Jamie Mansfield <https://www.jamierocks.uk/>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package me.jamiemansfield.lorenz.impl.model;

import me.jamiemansfield.bombe.type.signature.MethodSignature;
import me.jamiemansfield.lorenz.model.ClassMapping;
import me.jamiemansfield.lorenz.model.MethodMapping;
import me.jamiemansfield.lorenz.model.MethodParameterMapping;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;

/**
 * A basic implementation of {@link MethodMapping}.
 *
 * @author Jamie Mansfield
 * @since 0.2.0
 */
public class MethodMappingImpl
        extends AbstractMemberMappingImpl<MethodMapping, ClassMapping>
        implements MethodMapping {

    private final MethodSignature signature;
    private final Map<Integer, MethodParameterMapping> parameters = new HashMap<>();

    /**
     * Creates a new method mapping, from the given parameters.
     *
     * @param parentClass The class mapping, this mapping belongs to
     * @param signature The signature
     * @param deobfuscatedName The de-obfuscated name
     */
    public MethodMappingImpl(final ClassMapping parentClass, final MethodSignature signature,
            final String deobfuscatedName) {
        super(parentClass, signature.getName(), deobfuscatedName);
        this.signature = signature;
    }

    @Override
    public MethodSignature getSignature() {
        return this.signature;
    }

    @Override
    public Collection<MethodParameterMapping> getParameterMappings() {
        return Collections.unmodifiableCollection(this.parameters.values());
    }

    @Override
    public MethodParameterMapping createParameterMapping(final int index, final String deobfuscatedName) {
        return this.parameters.compute(index, (i, existingMapping) -> {
            if (existingMapping != null) return existingMapping.setDeobfuscatedName(deobfuscatedName);
            return this.getMappings().getModelFactory().createMethodParameterMapping(this, index, deobfuscatedName);
        });
    }

    @Override
    public Optional<MethodParameterMapping> getParameterMapping(final int index) {
        return Optional.ofNullable(this.parameters.get(index));
    }

    @Override
    public boolean hasParameterMapping(final int index) {
        return this.parameters.containsKey(index);
    }

    @Override
    protected StringJoiner buildToString() {
        return super.buildToString()
                .add("obfuscatedSignature=" + this.getObfuscatedDescriptor())
                .add("deobfuscatedSignature=" + this.getDeobfuscatedDescriptor());
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) return true;
        if (!super.equals(obj) || !(obj instanceof MethodMapping)) return false;
        final MethodMapping that = (MethodMapping) obj;
        return Objects.equals(this.signature, that.getSignature());
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), this.signature);
    }

}

@@ -1518,16 +1518,41 @@
 pping;%0A%0A
+import java.util.Arrays;%0A
 import j
@@ -1606,56 +1606,8 @@
 ns;%0A
-import java.util.HashMap;%0Aimport java.util.Map;%0A
 impo
@@ -1685,16 +1685,52 @@
 gJoiner;
+%0Aimport java.util.stream.Collectors;
 %0A%0A/**%0A *
@@ -2033,21 +2033,8 @@
 inal
- Map%3CInteger,
  Met
@@ -2052,17 +2052,18 @@
 rMapping
-%3E
+%5B%5D
  paramet
@@ -2069,26 +2069,8 @@
 ters
- = new HashMap%3C%3E()
 ;%0A%0A 
@@ -2550,32 +2550,136 @@
 re = signature;%0A
+        this.parameters = new MethodParameterMapping%5Bsignature.getDescriptor().getParamTypes().size()%5D;%0A
     %7D%0A%0A    @Over
@@ -2893,45 +2893,312 @@
 able
-Collection(this.parameters.values());
+List(Arrays.stream(this.parameters)%0A                .filter(Objects::nonNull).collect(Collectors.toList()));%0A    %7D%0A%0A    private void checkIndex(final int index) %7B%0A        if (index %3C 0 %7C%7C index %3E= this.parameters.length) %7B%0A            throw new IndexOutOfBoundsException(String.valueOf(index));%0A        %7D
 %0A   
@@ -3334,76 +3334,103 @@
     
-return this.parameters.compute(index, (i, existingM
+this.checkIndex(index);%0A        final MethodParameterMapping m
 apping
-) -%3E %7B%0A    
+ = this.parameters%5Bindex%5D;%0A
     
@@ -3437,25 +3437,17 @@
     if (
-existingM
+m
 apping !
@@ -3458,24 +3458,30 @@
 ll) 
-return existingM
+%7B%0A            return m
 appi
@@ -3519,24 +3519,48 @@
 atedName);%0A 
+       %7D%0A        else %7B%0A
            r
@@ -3554,30 +3554,56 @@
 %0A           
+ 
 return
+ this.parameters%5Bindex%5D =
  this.getMap
@@ -3698,18 +3698,16 @@
        %7D
-);
 %0A    %7D%0A%0A
@@ -3795,32 +3795,64 @@
 al int index) %7B%0A
+        this.checkIndex(index);%0A
         return O
@@ -3889,19 +3889,15 @@
 ters
-.get(
+%5B
 index
-)
+%5D
 );%0A 
@@ -3966,32 +3966,64 @@
 al int index) %7B%0A
+        this.checkIndex(index);%0A
         return t
@@ -4040,27 +4040,23 @@
 ters
-.containsKey(index)
+%5Bindex%5D != null
 ;%0A  

Store MethodParameterMappings as array instead of HashMap