package io.vertx.ext.web.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.TreeSet;

import io.vertx.codegen.annotations.Fluent;

public class ParsedMIME implements Comparable<ParsedMIME>{
  
  private String component;
  private String subComponent;
  
  private Map<String, String> parameter;

  private static final String STAR = "*";
  private static final String EMPTY = "";
  
  public ParsedMIME(String mimeComponent, String mimeSubComponent) {
    
    this.component = mimeComponent.equals(STAR) ? STAR : mimeComponent;
    this.subComponent = mimeSubComponent.equals(STAR) ? STAR : mimeSubComponent;
  }
  
  /**
   * Import a ParsedMIME
   */
  protected ParsedMIME(ParsedMIME mime) {
    this(mime.component, mime.subComponent);
    parameter = mime.parameter;
  }

  @Fluent
  public ParsedMIME addParameter(String key, String value) {
    ensureParameterExists();
    
    parameter.put(key, value);
    return this;
  }
  
  @Fluent
  public ParsedMIME addParameter(String key) {
    ensureParameterExists();
    
    parameter.put(key, EMPTY);
    return this;
  }
  
  private void ensureParameterExists() {
    if(parameter == null){
      parameter = new HashMap<>();
    }
  }

  private int compareParam1ToParam2(String param1, String param2){
    int param1IsStar = param1.equals("*") ? 0 : 1;
    int param2IsStar = param2.equals("*") ? 0 : 1;
    
    return param2IsStar - param1IsStar;
  }
  
  @Override
  public int compareTo(ParsedMIME other) {
    // The most specific is always the most relevant
    
    int componentComparison = compareParam1ToParam2(this.component, other.component);
    if(componentComparison != 0){
      return componentComparison;
    }
    
    int subComponentComparison = compareParam1ToParam2(this.subComponent, other.subComponent);
    if(subComponentComparison != 0){
      return subComponentComparison;
    }
    
    if(this.parameter == null && other.parameter == null){
      return 0;
    }
    
    return this.parameter == null ? 1 : -1;
  }
  
  @Override
  public int hashCode() {
    return Objects.hash(component, parameter, subComponent);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    ParsedMIME other = (ParsedMIME) obj;
    return  Objects.equals(this.component, other.component) &&
            Objects.equals(this.subComponent, other.subComponent) &&
            Objects.equals(this.parameter, other.parameter);
  }

  @Override
  public String toString() {
    return "ParsedMIME [component=" + component + ", subComponent=" + subComponent + ", parameter=" + parameter + "]";
  }
  
}

@@ -180,23 +180,103 @@
 va.util.
-Objects
+Map.Entry;%0D%0Aimport java.util.Objects;%0D%0Aimport java.util.Optional;%0D%0Aimport java.util.Set
 ;%0D%0Aimpor
@@ -1309,24 +1309,24 @@
 y, EMPTY);%0D%0A
-
     return t
@@ -1336,24 +1336,1220 @@
 ;%0D%0A  %7D%0D%0A  %0D%0A
+  /**%0D%0A   * Tests if this MIME complies with matchTry MIME%0D%0A   * @return%0D%0A   */%0D%0A  public boolean isMatchedBy(ParsedMIME matchTry) %7B%0D%0A%0D%0A    if (component != STAR && !component.equals(matchTry.component)) %7B%0D%0A      return false;%0D%0A    %7D%0D%0A    if (subComponent != STAR && !subComponent.equals(matchTry.subComponent)) %7B%0D%0A      return false;%0D%0A    %7D%0D%0A    %0D%0A    if (matchTry.parameter == null) %7B%0D%0A      return true;%0D%0A      %0D%0A    %7D%0D%0A    if (parameter == null) %7B%0D%0A      return false;%0D%0A    %7D%0D%0A      %0D%0A    for (Entry%3CString, String%3E requiredParameter : matchTry.parameter.entrySet()) %7B%0D%0A      String parameterValueToTest = parameter.get(requiredParameter.getKey());%0D%0A      String requiredParamVal = requiredParameter.getValue();%0D%0A      %0D%0A      if (parameterValueToTest == null %7C%7C (%0D%0A          requiredParamVal != null && !requiredParamVal.equals(parameterValueToTest))%0D%0A         )%7B%0D%0A        return false;%0D%0A      %7D%0D%0A    %7D%0D%0A    return true;%0D%0A  %7D%0D%0A  %0D%0A  public Optional%3CParsedMIME%3E findMatchedBy(Iterable%3CParsedMIME%3E matchTries) %7B%0D%0A    %0D%0A    for (ParsedMIME matchTry : matchTries) %7B%0D%0A      if(isMatchedBy(matchTry))%7B%0D%0A        return Optional.of(matchTry);%0D%0A      %7D%0D%0A    %7D%0D%0A    return Optional.empty();%0D%0A  %7D%0D%0A  %0D%0A
   private vo

isMatchedBy! Compares if this MIME complies with the given ParsedMIME(s)