package org.jboss.resteasy.util;

import org.jboss.resteasy.spi.LoggableFailure;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
public class MediaTypeHelper
{
   public static MediaType getConsumes(Class declaring, AccessibleObject method)
   {
      Consumes consume = method.getAnnotation(Consumes.class);
      if (consume == null)
      {
         consume = (Consumes) declaring.getAnnotation(Consumes.class);
         if (consume == null) return null;
      }
      return MediaType.valueOf(consume.value()[0]);
   }

   public static MediaType getProduces(Class declaring, Method method)
   {
      Produces consume = method.getAnnotation(Produces.class);
      if (consume == null)
      {
         consume = (Produces) declaring.getAnnotation(Produces.class);
      }
      if (consume == null) return null;
      return MediaType.valueOf(consume.value()[0]);
   }

   public static float getQ(MediaType type)
   {
      float rtn = getQWithParamInfo(type);
      if (rtn == 2.0F) return 1.0F;
      return rtn;
   }

   public static float getQWithParamInfo(MediaType type)
   {
      if (type.getParameters() != null)
      {
         String val = type.getParameters().get("q");
         try
         {
            if (val != null)
            {
               float rtn = Float.valueOf(val);
               if (rtn > 1.0F)
                  throw new LoggableFailure("MediaType q value cannot be greater than 1.0: " + type.toString(), HttpResponseCodes.SC_BAD_REQUEST);
               return rtn;
            }
         }
         catch (NumberFormatException e)
         {
            throw new RuntimeException("MediaType q parameter must be a float: " + type, e);
         }
      }
      return 2.0f;
   }

   /**
    * subtypes like application/*+xml
    *
    * @param subtype
    * @return
    */
   public static boolean isCompositeWildcardSubtype(String subtype)
   {
      return subtype.startsWith("*+");
   }

   /**
    * subtypes like application/*+xml
    *
    * @param subtype
    * @return
    */
   public static boolean isWildcardCompositeSubtype(String subtype)
   {
      return subtype.endsWith("+*");
   }

   public static boolean isComposite(String subtype)
   {
      return (isCompositeWildcardSubtype(subtype) || isWildcardCompositeSubtype(subtype));
   }

   private static class MediaTypeComparator implements Comparator<MediaType>, Serializable
   {

      private static final long serialVersionUID = -5828700121582498092L;

      public int compare(MediaType mediaType2, MediaType mediaType)
      {
         float q = getQWithParamInfo(mediaType);
         boolean wasQ = q != 2.0f;
         if (q == 2.0f) q = 1.0f;

         float q2 = getQWithParamInfo(mediaType2);
         boolean wasQ2 = q2 != 2.0f;
         if (q2 == 2.0f) q2 = 1.0f;


         if (q < q2) return -1;
         if (q > q2) return 1;

         if (mediaType.isWildcardType() && !mediaType2.isWildcardType()) return -1;
         if (!mediaType.isWildcardType() && mediaType2.isWildcardType()) return 1;
         if (mediaType.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) return -1;
         if (!mediaType.isWildcardSubtype() && mediaType2.isWildcardSubtype()) return 1;
         if (isComposite(mediaType.getSubtype()) && !isComposite(mediaType2.getSubtype()))
            return -1;
         if (!isComposite(mediaType.getSubtype()) && isComposite(mediaType2.getSubtype()))
            return 1;
         if (isCompositeWildcardSubtype(mediaType.getSubtype()) && !isCompositeWildcardSubtype(mediaType2.getSubtype()))
            return -1;
         if (!isCompositeWildcardSubtype(mediaType.getSubtype()) && isCompositeWildcardSubtype(mediaType2.getSubtype()))
            return 1;
         if (isWildcardCompositeSubtype(mediaType.getSubtype()) && !isWildcardCompositeSubtype(mediaType2.getSubtype()))
            return -1;
         if (!isWildcardCompositeSubtype(mediaType.getSubtype()) && isWildcardCompositeSubtype(mediaType2.getSubtype()))
            return 1;

         int numNonQ = 0;
         if (mediaType.getParameters() != null)
         {
            numNonQ = mediaType.getParameters().size();
            if (wasQ) numNonQ--;
         }

         int numNonQ2 = 0;
         if (mediaType2.getParameters() != null)
         {
            numNonQ2 = mediaType2.getParameters().size();
            if (wasQ2) numNonQ2--;
         }

         if (numNonQ < numNonQ2) return -1;
         if (numNonQ > numNonQ2) return 1;


         return 0;
      }
   }

   public static int compareWeight(MediaType one, MediaType two)
   {
      return new MediaTypeComparator().compare(one, two);
   }

   public static boolean sameWeight(MediaType one, MediaType two)
   {
      return new MediaTypeComparator().compare(one, two) == 0;
   }

   public static void sortByWeight(List<MediaType> types)
   {
      if (types == null || types.size() <= 1) return;
      Collections.sort(types, new MediaTypeComparator());
   }

   public static MediaType getBestMatch(List<MediaType> desired, List<MediaType> provided)
   {
      sortByWeight(desired);
      sortByWeight(provided);
      boolean emptyDesired = desired == null || desired.size() == 0;
      boolean emptyProvided = provided == null || provided.size() == 0;
      
      if (emptyDesired && emptyProvided) return null;
      if (emptyDesired && !emptyProvided) return provided.get(0);
      if (emptyProvided && !emptyDesired) return desired.get(0);

      for (MediaType desire : desired)
      {
         for (MediaType provide : provided)
         {
            if (provide.isCompatible(desire)) return provide;
         }
      }
      return null;
   }

   public static List<MediaType> parseHeader(String header)
   {
      ArrayList<MediaType> types = new ArrayList<MediaType>();
      String[] medias = header.split(",");
      for (int i = 0; i < medias.length; i++)
      {
         types.add(MediaType.valueOf(medias[i].trim()));
      }
      return types;
   }

   public static boolean equivalent(MediaType m1, MediaType m2)
   {
      if (m1 == m2) return true;

      if (!m1.getType().equals(m2.getType())) return false;
      if (!m1.getSubtype().equals(m2.getSubtype())) return false;

      return equivalentParams(m1, m2);
   }

   public static boolean equivalentParams(MediaType m1, MediaType m2)
   {
      Map<String, String> params1 = m1.getParameters();
      Map<String, String> params2 = m2.getParameters();

      if (params1 == params2) return true;
      if (params1 == null || params2 == null) return false;
      if (params1.size() == 0 && params2.size() == 0) return true;
      int numParams1 = params1.size();
      if (params1.containsKey("q")) numParams1--;
      int numParams2 = params2.size();
      if (params2.containsKey("q")) numParams2--;

      if (numParams1 != numParams2) return false;
      if (numParams1 == 0) return true;

      for (Map.Entry<String, String> entry : params1.entrySet())
      {
         String key = entry.getKey();
         if (key.equals("q")) continue;
         String value = entry.getValue();
         String value2 = params2.get(key);
         if (value == value2) continue; // both null
         if (value == null || value2 == null) return false;
         if (value.equals(value2) == false) return false;
      }
      return true;
   }
}
