/*
 * Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.web.bindery.requestfactory.server;

import com.google.gwt.dev.asm.Type;
import com.google.web.bindery.autobean.vm.impl.TypeUtils;
import com.google.web.bindery.requestfactory.shared.BaseProxy;
import com.google.web.bindery.requestfactory.shared.ProxyFor;
import com.google.web.bindery.requestfactory.shared.ProxyForName;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.RequestFactory;
import com.google.web.bindery.requestfactory.shared.Service;
import com.google.web.bindery.requestfactory.shared.ServiceName;
import com.google.web.bindery.requestfactory.vm.impl.OperationKey;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

/**
 * Implements all of the resolution methods in ServiceLayer.
 */
final class ResolverServiceLayer extends ServiceLayerDecorator {

  private static Deobfuscator deobfuscator;
  private static final Logger log = Logger.getLogger(ServiceLayer.class.getName());

  private static synchronized boolean updateDeobfuscator(ClassLoader classLoader, String binaryName) {
    RequestFactoryInterfaceValidator validator =
        new RequestFactoryInterfaceValidator(log,
            new RequestFactoryInterfaceValidator.ClassLoaderLoader(classLoader));
    validator.antidote();
    validator.validateRequestFactory(binaryName);
    if (validator.isPoisoned()) {
      return false;
    }
    if (deobfuscator == null) {
      deobfuscator = validator.getDeobfuscator();
    } else {
      deobfuscator =
          new Deobfuscator.Builder().merge(deobfuscator).merge(validator.getDeobfuscator()).build();
    }
    return true;
  }

  @Override
  public ClassLoader getDomainClassLoader() {
    return Thread.currentThread().getContextClassLoader();
  }

  @Override
  public Class<? extends BaseProxy> resolveClass(String typeToken) {
    String deobfuscated = deobfuscator.getTypeFromToken(typeToken);
    if (deobfuscated == null) {
      die(null, "No type for token %s", typeToken);
    }

    return forName(deobfuscated).asSubclass(BaseProxy.class);
  }

  @Override
  public <T> Class<? extends T> resolveClientType(Class<?> domainClass, Class<T> clientClass,
      boolean required) {
    if (List.class.isAssignableFrom(domainClass)) {
      return List.class.asSubclass(clientClass);
    }
    if (Set.class.isAssignableFrom(domainClass)) {
      return Set.class.asSubclass(clientClass);
    }
    if (TypeUtils.isValueType(domainClass)) {
      return domainClass.asSubclass(clientClass);
    }
    Class<?> toSearch = domainClass;
    while (toSearch != null) {
      List<String> clientTypes = deobfuscator.getClientProxies(toSearch.getName());
      if (clientTypes != null) {
        for (String clientType : clientTypes) {
          Class<?> proxy = forName(clientType);
          if (clientClass.isAssignableFrom(proxy)) {
            return proxy.asSubclass(clientClass);
          }
        }
      }
      toSearch = toSearch.getSuperclass();
    }
    if (required) {
      die(null, "The domain type %s cannot be sent to the client", domainClass.getCanonicalName());
    }
    return null;
  }

  @Override
  public Class<?> resolveDomainClass(Class<?> clazz) {
    if (List.class.equals(clazz)) {
      return List.class;
    } else if (Set.class.equals(clazz)) {
      return Set.class;
    } else if (BaseProxy.class.isAssignableFrom(clazz)) {
      ProxyFor pf = clazz.getAnnotation(ProxyFor.class);
      if (pf != null) {
        return pf.value();
      }
      ProxyForName pfn = clazz.getAnnotation(ProxyForName.class);
      if (pfn != null) {
        Class<?> toReturn = forName(pfn.value());
        return toReturn;
      }
    }
    return die(null, "Could not resolve a domain type for client type %s", clazz.getCanonicalName());
  }

  @Override
  public Method resolveDomainMethod(String operation) {
    /*
     * The validator has already determined the mapping from the RequsetContext
     * method to a domain method signature. We'll reuse this calculation instead
     * of iterating over all methods.
     */
    String domainDescriptor = deobfuscator.getDomainMethodDescriptor(operation);

    if (domainDescriptor == null) {
      return die(null, "No domain method descriptor is mapped to operation %s", operation);
    }

    Class<?>[] domainArgs = getArgumentTypes(domainDescriptor);
    Class<? extends RequestContext> requestContext = getTop().resolveRequestContext(operation);
    Class<?> serviceImplementation = getTop().resolveServiceClass(requestContext);

    // Request<FooProxy> someMethod(int a, double b, FooProxy c);
    Method requestContextMethod = getTop().resolveRequestContextMethod(operation);

    Throwable ex;
    try {
      return serviceImplementation.getMethod(requestContextMethod.getName(), domainArgs);
    } catch (SecurityException e) {
      ex = e;
    } catch (NoSuchMethodException e) {
      ex = e;
    }

    return die(ex,
        "Could not find method in implementation %s matching descriptor %s for operation %s",
        serviceImplementation.getCanonicalName(), domainDescriptor, operation);
  }

  @Override
  public Class<? extends RequestContext> resolveRequestContext(String operation) {
    String requestContextClass = deobfuscator.getRequestContext(operation);
    if (requestContextClass == null) {
      die(null, "No RequestContext for operation %s", operation);
    }
    return forName(requestContextClass).asSubclass(RequestContext.class);
  }

  @Override
  public Method resolveRequestContextMethod(String operation) {
    Class<?> searchIn = getTop().resolveRequestContext(operation);
    String methodName = deobfuscator.getRequestContextMethodName(operation);
    String descriptor = deobfuscator.getRequestContextMethodDescriptor(operation);
    Class<?>[] params = getArgumentTypes(descriptor);
    try {
      return searchIn.getMethod(methodName, params);
    } catch (NoSuchMethodException ex) {
      return report("Could not locate %s operation %s", RequestContext.class.getSimpleName(),
          operation);
    }
  }

  @Override
  public Class<? extends RequestFactory> resolveRequestFactory(String binaryName) {
    if (!updateDeobfuscator(getTop().getDomainClassLoader(), binaryName)) {
      die(null, "The RequestFactory %s did not pass validation", binaryName);
    }
    return forName(binaryName).asSubclass(RequestFactory.class);
  }

  @Override
  public Class<?> resolveServiceClass(Class<? extends RequestContext> requestContextClass) {
    Class<?> searchIn = null;
    Service s = requestContextClass.getAnnotation(Service.class);
    if (s != null) {
      searchIn = s.value();
    }
    ServiceName sn = requestContextClass.getAnnotation(ServiceName.class);
    if (sn != null) {
      searchIn = forName(sn.value());
    }
    if (searchIn == null) {
      die(null, "The %s type %s did not specify a service type", RequestContext.class
          .getSimpleName(), requestContextClass.getCanonicalName());
    }
    return searchIn;
  }

  @Override
  public String resolveTypeToken(Class<? extends BaseProxy> clazz) {
    return OperationKey.hash(clazz.getName());
  }

  /**
   * Call {@link Class#forName(String)} and report any errors through
   * {@link #die()}.
   */
  private Class<?> forName(String name) {
    try {
      return Class.forName(name, false, getTop().getDomainClassLoader());
    } catch (ClassNotFoundException e) {
      return die(e, "Could not locate class %s", name);
    }
  }

  private Class<?>[] getArgumentTypes(String descriptor) {
    Type[] types = Type.getArgumentTypes(descriptor);
    Class<?>[] params = new Class<?>[types.length];
    for (int i = 0, j = types.length; i < j; i++) {
      params[i] = getClass(types[i]);
    }
    return params;
  }

  private Class<?> getClass(Type type) {
    switch (type.getSort()) {
      case Type.BOOLEAN:
        return boolean.class;
      case Type.BYTE:
        return byte.class;
      case Type.CHAR:
        return char.class;
      case Type.DOUBLE:
        return double.class;
      case Type.FLOAT:
        return float.class;
      case Type.INT:
        return int.class;
      case Type.LONG:
        return long.class;
      case Type.OBJECT:
        return forName(type.getClassName());
      case Type.SHORT:
        return short.class;
      case Type.VOID:
        return void.class;
      case Type.ARRAY:
        return die(null, "Unsupported Type used in operation descriptor %s", type.getDescriptor());
      default:
        // Error in this switch statement
        return die(null, "Unhandled Type: %s", type.getDescriptor());
    }
  }
}
